Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27b8d1754e | ||
|
|
dc0830120f | ||
|
|
39bff805ac | ||
|
|
3ebbb0e0e3 | ||
|
|
8a2119028c | ||
|
|
083d934472 | ||
|
|
1b096035a7 | ||
|
|
0074d43364 | ||
|
|
3bda390708 | ||
|
|
c6952aba55 | ||
|
|
807a9017ad | ||
|
|
c134025408 | ||
|
|
1e95e0ff30 | ||
|
|
fb21797040 | ||
|
|
76197a19df | ||
|
|
5f7d690875 | ||
|
|
56020a7529 | ||
|
|
5830ee5180 | ||
|
|
b3c7dd67e8 | ||
|
|
59c5d4be5a | ||
|
|
035f5d7fcd | ||
|
|
ccaff13df3 | ||
|
|
c9baf4dfb1 | ||
|
|
f54b39b1f2 | ||
|
|
00be979863 | ||
|
|
86386d8a91 | ||
|
|
d119fd1331 |
@@ -12,6 +12,7 @@ import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
import ch.zhaw.gartenverwaltung.types.Pest;
|
||||
import ch.zhaw.gartenverwaltung.types.Plant;
|
||||
import ch.zhaw.gartenverwaltung.types.Task;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ListProperty;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
@@ -29,6 +30,7 @@ import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -132,8 +134,14 @@ public class CropDetailController {
|
||||
initializeTaskListProperty(crop);
|
||||
|
||||
TaskList.TaskListObserver taskListObserver = newTaskList -> {
|
||||
taskListProperty.clear();
|
||||
taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get()));
|
||||
Platform.runLater(() -> {
|
||||
taskListProperty.clear();
|
||||
try {
|
||||
taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
};
|
||||
gardenSchedule.setTaskListObserver(taskListObserver);
|
||||
|
||||
@@ -230,6 +238,8 @@ public class CropDetailController {
|
||||
|
||||
Button edit = new Button();
|
||||
Button delete = new Button();
|
||||
edit.getStyleClass().add("button-class");
|
||||
delete.getStyleClass().add("button-class");
|
||||
HBox.setHgrow(edit, Priority.NEVER);
|
||||
HBox.setHgrow(delete, Priority.NEVER);
|
||||
setIconToButton(edit, "editIcon.png");
|
||||
@@ -313,6 +323,10 @@ public class CropDetailController {
|
||||
|
||||
DialogPane dialogPane = dialog.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
ButtonType saveTask;
|
||||
if(newTask) {
|
||||
saveTask = new ButtonType("Add", ButtonBar.ButtonData.OK_DONE);
|
||||
@@ -361,6 +375,10 @@ public class CropDetailController {
|
||||
|
||||
DialogPane dialogPane = dialog.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
ButtonType save = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
|
||||
dialogPane.getButtonTypes().addAll(save, ButtonType.CANCEL);
|
||||
|
||||
@@ -392,6 +410,12 @@ public class CropDetailController {
|
||||
alert.setTitle("Delete " + task.getName());
|
||||
alert.setHeaderText("Are you sure want to delete this Task?");
|
||||
|
||||
DialogPane dialogPane = alert.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
alert.showAndWait()
|
||||
.ifPresent(buttonType -> {
|
||||
if (buttonType == ButtonType.OK) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -89,6 +90,10 @@ public class MainFXMLController {
|
||||
|
||||
DialogPane dialogPane = dialog.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
ButtonType saveSettings = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
|
||||
dialogPane.getButtonTypes().addAll(saveSettings, ButtonType.CANCEL);
|
||||
|
||||
@@ -156,7 +161,12 @@ public class MainFXMLController {
|
||||
}
|
||||
|
||||
private void styleChangeButton(Button button) {
|
||||
//ToDo changeStyle of the menu buttons
|
||||
/*home_button.setStyle("-fx-background-color: rgb(0,128,0)");
|
||||
myGarden_button.setStyle("-fx-background-color: rgb(0,128,0)");
|
||||
mySchedule_button.setStyle("-fx-background-color: rgb(0,128,0)");
|
||||
settings_button.setStyle("-fx-background-color: rgb(0,128,0)");
|
||||
tutorial_button.setStyle("-fx-background-color: rgb(0,128,0)");
|
||||
button.setStyle("-fx-background-color: darkgreen");*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -117,6 +117,9 @@ public class MyGardenController {
|
||||
|
||||
Button details = new Button();
|
||||
Button delete = new Button();
|
||||
details.getStyleClass().add("button-class");
|
||||
delete.getStyleClass().add("button-class");
|
||||
|
||||
setIconToButton(details, "detailsIcon.png");
|
||||
setIconToButton(delete, "deleteIcon.png");
|
||||
details.setOnAction(getGoToCropDetailEvent(crop));
|
||||
@@ -186,6 +189,12 @@ public class MyGardenController {
|
||||
Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get();
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setTitle("Delete " + plant.name());
|
||||
DialogPane dialogPane = alert.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
alert.setHeaderText("Are you sure want to delete this Crop?");
|
||||
alert.setContentText("Deleting this crop will remove all associated tasks from your schedule.");
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import javafx.scene.layout.VBox;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -183,6 +184,8 @@ public class MyScheduleController {
|
||||
Pane puffer = new Pane();
|
||||
HBox.setHgrow(puffer, Priority.ALWAYS);
|
||||
Button button = new Button("Task completed!");
|
||||
button.getStyleClass().add("button-class");
|
||||
|
||||
button.setOnAction(new EventHandler<ActionEvent>() {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
@@ -206,6 +209,12 @@ public class MyScheduleController {
|
||||
alert.setHeaderText("Are you sure you have completed this task?");
|
||||
alert.setContentText("Confirming that you have completed the task will remove it from the schedule.");
|
||||
|
||||
DialogPane dialogPane = alert.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
alert.showAndWait()
|
||||
.ifPresent(buttonType -> {
|
||||
if (buttonType == ButtonType.OK) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import javafx.scene.layout.VBox;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -82,6 +83,10 @@ public class PlantsController {
|
||||
|
||||
DialogPane dialogPane = dateSelection.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
ButtonType sowButton = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
|
||||
dialogPane.getButtonTypes().addAll(sowButton, ButtonType.CANCEL);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import javafx.scene.image.ImageView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
@@ -91,6 +92,10 @@ public class SettingsController implements Initializable {
|
||||
|
||||
DialogPane dialogPane = dialog.getDialogPane();
|
||||
|
||||
dialogPane.getStylesheets().add(
|
||||
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||
dialogPane.getStyleClass().add("myDialog");
|
||||
|
||||
ButtonType save = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
|
||||
dialogPane.getButtonTypes().addAll(save, ButtonType.CANCEL);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Controller class for the Tutorial.fxml file
|
||||
@@ -22,6 +23,8 @@ public class TutorialController {
|
||||
public ImageView imgAddNewPlant;
|
||||
public ImageView imgTaskList;
|
||||
public ImageView imgSelectDate;
|
||||
public ImageView imgAddTaskButton;
|
||||
public ImageView imgDetailDeleteButtons;
|
||||
|
||||
private int page = 0;
|
||||
|
||||
@@ -30,10 +33,27 @@ public class TutorialController {
|
||||
switchViews();
|
||||
setButtonAbilities();
|
||||
|
||||
Image placeholder = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
|
||||
imgAddNewPlant.setImage(placeholder);
|
||||
imgSelectDate.setImage(placeholder);
|
||||
imgTaskList.setImage(placeholder);
|
||||
setImageView(imgAddNewPlant, "add-new-plant.png");
|
||||
setImageView(imgSelectDate, "select-sow-harvest.png");
|
||||
setImageView(imgDetailDeleteButtons, "details-delete.png");
|
||||
setImageView(imgTaskList, "schedule.png");
|
||||
setImageView(imgAddTaskButton, "add-task.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* update the given image view with screenshot or placeholder image.
|
||||
* @param imageView the image view to update
|
||||
* @param fileName the file name of the source
|
||||
*/
|
||||
private void setImageView(ImageView imageView, String fileName) {
|
||||
File file = new File(String.valueOf(PlantsController.class.getResource(fileName)));
|
||||
Image image;
|
||||
if (file.exists()) {
|
||||
image = new Image(String.valueOf(PlantsController.class.getResource(fileName)));
|
||||
} else {
|
||||
image = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
|
||||
}
|
||||
imageView.setImage(image);
|
||||
}
|
||||
|
||||
public void viewNextPage() {
|
||||
|
||||
@@ -17,27 +17,38 @@ import java.util.TimerTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Class with tasks which must be executed periodic and not triggered by user. Method run must be called in a fix interval.
|
||||
*/
|
||||
public class BackgroundTasks extends TimerTask {
|
||||
private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
|
||||
private final TaskList taskList;
|
||||
private final Notifier notifier;
|
||||
private final WeatherGradenTaskPlanner weatherGardenTaskPlaner;
|
||||
|
||||
private void movePastTasks() throws IOException {
|
||||
List<Task> taskList = this.taskList.getTaskList(LocalDate.MIN, LocalDate.now().minusDays(1));
|
||||
taskList.forEach(task -> {
|
||||
if (!task.isDone()) {
|
||||
task.setNextExecution(LocalDate.now());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) {
|
||||
this.taskList = taskList;
|
||||
notifier = new Notifier(taskList, plantList, cropList);
|
||||
weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(taskList, plantList, cropList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the field "nextExecution" of all tasks if it's in the past to the actual date as long as they are not done.
|
||||
* @throws IOException if the taskList can't be read.
|
||||
*/
|
||||
private void movePastTasks() throws IOException {
|
||||
List<Task> taskList = this.taskList.getTaskList(LocalDate.MIN.plusDays(1), LocalDate.now().minusDays(1));
|
||||
for (Task task : taskList) {
|
||||
if (!task.isDone()) {
|
||||
task.setNextExecution(LocalDate.now());
|
||||
this.taskList.saveTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to call if Tasks should be executed. It calls all Background tasks after each other.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
@@ -13,6 +13,9 @@ import javax.mail.MessagingException;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Class to send Notifications to the user
|
||||
*/
|
||||
public class Notifier {
|
||||
private final TaskList taskList;
|
||||
private final CropList cropList;
|
||||
@@ -25,6 +28,13 @@ public class Notifier {
|
||||
this.plantList = plantList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to send a Notification to the user for e specific Task
|
||||
* @param task The task to use for notification
|
||||
* @throws IOException if tasklist can not be read
|
||||
* @throws MessagingException if E-Mail can not be sent for any reason
|
||||
* @throws HardinessZoneNotSetException if hardiness zone is not set in plant list.
|
||||
*/
|
||||
private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException {
|
||||
String plantName = "unkown plant";
|
||||
if(cropList.getCropById((task.getCropId())).isPresent()){
|
||||
@@ -38,6 +48,12 @@ public class Notifier {
|
||||
eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification to the user for each task which is due and not done every day as long as it's not done.
|
||||
* @throws IOException if tasklist can not be read
|
||||
* @throws MessagingException if E-Mail can not be sent for any reason
|
||||
* @throws HardinessZoneNotSetException if hardiness zone is not set in plant list.
|
||||
*/
|
||||
public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException {
|
||||
for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) {
|
||||
if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) {
|
||||
|
||||
@@ -10,16 +10,20 @@ import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class to send E-Mails
|
||||
*/
|
||||
public class EMailSender {
|
||||
|
||||
|
||||
public EMailSender(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to send E-Mail to one or multiple recipients
|
||||
* @param recipients recipients E-Mail addresses separated by ";"
|
||||
* @param subject Subject of the E-Mail
|
||||
* @param text E-Mail message Text as rear text or html
|
||||
* @throws MessagingException If sending the E-Mail fails for any reason
|
||||
*/
|
||||
public void sendMails(String recipients, String subject, String text) throws MessagingException {
|
||||
// TODO replace printMail with implementation
|
||||
printMail(recipients, subject, text); // TODO Remove Printing E-Mail to console to test it
|
||||
printMail(recipients, subject, text);
|
||||
MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession());
|
||||
message.addHeader("Content-type", "text/HTML; charset=UTF-8");
|
||||
message.addHeader("format", "flowed");
|
||||
|
||||
@@ -5,6 +5,10 @@ import javax.mail.Session;
|
||||
import java.net.Authenticator;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Class to store SMTP Credentials to send E-Mails and create
|
||||
* corresponding Session Object
|
||||
*/
|
||||
public record SmtpCredentials(
|
||||
String host,
|
||||
String port,
|
||||
@@ -14,6 +18,10 @@ public record SmtpCredentials(
|
||||
boolean startTLS
|
||||
) {
|
||||
|
||||
/**
|
||||
* Creates a Properties Object with SMTP Server Information
|
||||
* @return the created Properties Object
|
||||
*/
|
||||
private Properties getProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.put("mail.smtp.host", host);
|
||||
@@ -23,6 +31,10 @@ public record SmtpCredentials(
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a javax.mail.Authenticator Object with username and password for SMTP Server
|
||||
* @return the created javax.mail.Authenticator Object
|
||||
*/
|
||||
private javax.mail.Authenticator getAuthenticator() {
|
||||
return new javax.mail.Authenticator() {
|
||||
@Override
|
||||
@@ -32,10 +44,11 @@ public record SmtpCredentials(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the Session Instance with the given SMTP Credentials
|
||||
* @return the Session Instance
|
||||
*/
|
||||
public Session getSession() {
|
||||
return Session.getInstance(getProperties(), getAuthenticator());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||
|
||||
/**
|
||||
* Enum of possible Weather events
|
||||
*/
|
||||
public enum SevereWeather {
|
||||
FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
|
||||
}
|
||||
|
||||
+67
-19
@@ -9,18 +9,21 @@ import ch.zhaw.gartenverwaltung.types.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days
|
||||
*
|
||||
*/
|
||||
public class WeatherGradenTaskPlanner {
|
||||
private final TaskList taskList;
|
||||
private final PlantList plantList;
|
||||
private final CropList cropList;
|
||||
WeatherService weatherService;
|
||||
private final LocalDate dateSevereWeather = LocalDate.of(2022,12,15);
|
||||
private final LocalDate dateSevereWeather = LocalDate.now();
|
||||
|
||||
public WeatherGradenTaskPlanner(TaskList taskList, PlantList plantList, CropList cropList) {
|
||||
this.taskList = taskList;
|
||||
@@ -43,8 +46,7 @@ public class WeatherGradenTaskPlanner {
|
||||
private void getSevereWeatherEvents() throws IOException {
|
||||
SevereWeather actualWeather = weatherService.causeSevereWeather(1);
|
||||
if (SevereWeather.HAIL.equals(actualWeather)) {
|
||||
//ToDo creates hail task all 3 seconds, pls fix
|
||||
//createPreHailTask();
|
||||
createPreHailTask();
|
||||
} else if (SevereWeather.FROST.equals(actualWeather)) {
|
||||
createPreFrostTask();
|
||||
} else if (SevereWeather.SNOW.equals(actualWeather)) {
|
||||
@@ -63,11 +65,27 @@ public class WeatherGradenTaskPlanner {
|
||||
*/
|
||||
private void createPreHailTask() throws IOException {
|
||||
|
||||
Task preHailTask = new Task("Hail",
|
||||
"During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin",
|
||||
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L));
|
||||
taskList.saveTask(preHailTask);
|
||||
List<Crop> actualCrops = cropList.getCrops();
|
||||
|
||||
for (Crop crop : actualCrops) {
|
||||
Task preHailTask = new Task("Hail",
|
||||
"During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin",
|
||||
dateSevereWeather,dateSevereWeather.plusDays(1L),crop.getCropId().orElse(-1L));
|
||||
|
||||
List<Task> actualCropTaskList = taskList.getTaskForCrop(crop.getCropId().orElse(-1L));
|
||||
List<Task> hailTasklist = actualCropTaskList.stream().filter(task -> task.getName().equals("Hail")).toList();
|
||||
|
||||
List<Task> hailTaskListAtDate = new ArrayList<>();
|
||||
for (Task task : hailTasklist) {
|
||||
if (task.getStartDate() == (preHailTask.getStartDate())) {
|
||||
hailTaskListAtDate.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
if(hailTaskListAtDate.isEmpty() && hailTasklist.isEmpty()){
|
||||
taskList.saveTask(preHailTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,10 +93,26 @@ public class WeatherGradenTaskPlanner {
|
||||
* @throws IOException If the database cannot be accessed
|
||||
*/
|
||||
private void createPreFrostTask() throws IOException {
|
||||
Task preFrostTask = new Task("Frost",
|
||||
"The temperatur falls below zero degrees, cover especially the root with wool",
|
||||
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L));
|
||||
taskList.saveTask(preFrostTask);
|
||||
List<Crop> actualCrops = cropList.getCrops();
|
||||
for (Crop crop : actualCrops) {
|
||||
|
||||
Task preFrostTask = new Task("Frost",
|
||||
"The temperatur falls below zero degrees, cover especially the root with wool",
|
||||
dateSevereWeather,dateSevereWeather.plusDays(1L),crop.getCropId().orElse(-1L));
|
||||
|
||||
List<Task> actualCropTaskList = taskList.getTaskForCrop(crop.getCropId().orElse(-1L));
|
||||
List<Task> frostTasklist = actualCropTaskList.stream().filter(task -> task.getName().equals("Frost")).toList();
|
||||
|
||||
List<Task> frostTaskListAtDate = new ArrayList<>();
|
||||
for (Task task : frostTasklist) {
|
||||
if (task.getStartDate() == preFrostTask.getStartDate()) {
|
||||
frostTaskListAtDate.add(task);
|
||||
}
|
||||
}
|
||||
if(frostTaskListAtDate.isEmpty() && frostTasklist.isEmpty()){
|
||||
taskList.saveTask(preFrostTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,10 +120,27 @@ public class WeatherGradenTaskPlanner {
|
||||
* @throws IOException If the database cannot be accessed
|
||||
*/
|
||||
private void createPreSnowTask() throws IOException {
|
||||
Task preSnowTask = new Task("Snow",
|
||||
"The weather brings little snowfall. Cover your crops",
|
||||
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L));
|
||||
taskList.saveTask(preSnowTask);
|
||||
List<Crop> actualCrops = cropList.getCrops();
|
||||
for (Crop crop : actualCrops) {
|
||||
|
||||
Task preSnowTask = new Task("Snow",
|
||||
"The weather brings little snowfall. Cover your crops",
|
||||
dateSevereWeather, dateSevereWeather.plusDays(1L), crop.getCropId().orElse(-1L));
|
||||
|
||||
List<Task> actualCropTaskList = taskList.getTaskForCrop(crop.getCropId().orElse(-1L));
|
||||
List<Task> snowTasklist = actualCropTaskList.stream().filter(task -> task.getName().equals("Snow")).toList();
|
||||
|
||||
List<Task> snowTaskListAtDate = new ArrayList<>();
|
||||
for (Task task : snowTasklist) {
|
||||
if (task.getStartDate() == preSnowTask.getStartDate()) {
|
||||
snowTaskListAtDate.add(task);
|
||||
}
|
||||
}
|
||||
if(snowTaskListAtDate .isEmpty() && snowTasklist.isEmpty()){
|
||||
taskList.saveTask(preSnowTask);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,9 +165,6 @@ public class WeatherGradenTaskPlanner {
|
||||
/**
|
||||
* Method to set next execution date of the water plant tasks
|
||||
* @param cropTaskList List with tasks from crops
|
||||
* @throws IOException If the database cannot be accessed
|
||||
* @throws HardinessZoneNotSetException If the hardiness zone is not available
|
||||
* @throws PlantNotFoundException if the plant is not available for the watering task
|
||||
*/
|
||||
private void adjustNextExecutionOfWateringTasks(List<Task> cropTaskList){
|
||||
for(Task task : cropTaskList){
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||
/**
|
||||
* The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner
|
||||
*
|
||||
*/
|
||||
public class WeatherService {
|
||||
private static final int NO_RAIN = 0;
|
||||
@@ -9,6 +8,11 @@ public class WeatherService {
|
||||
private static final int RAIN = 25;
|
||||
private static final int HEAVY_RAIN = 50;
|
||||
|
||||
/**
|
||||
* Method to simmulate a Weather Service for testing
|
||||
* @param randomWeather random int. Range: 1-3
|
||||
* @return the selected SevereWeather
|
||||
*/
|
||||
public SevereWeather causeSevereWeather(int randomWeather) {
|
||||
return switch (randomWeather) {
|
||||
case 1 -> SevereWeather.HAIL;
|
||||
@@ -19,6 +23,11 @@ public class WeatherService {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to simulate a Weather Service for testing
|
||||
* @param randomRainAmount random int. Range: 1-4
|
||||
* @return the selected rain amount
|
||||
*/
|
||||
public int causeRainAmount(int randomRainAmount) {
|
||||
return switch (randomRainAmount) {
|
||||
case 1 -> NO_RAIN;
|
||||
|
||||
@@ -152,6 +152,11 @@ public class AppLoader {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get any AppDependency
|
||||
* @param type Class of Dependency
|
||||
* @return the App dependency
|
||||
*/
|
||||
public Object getAppDependency(Class<?> type) {
|
||||
return dependencies.get(type.getSimpleName());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
/**
|
||||
* Exceptionm which is thrown if Hardiness zone is not set in plant list.
|
||||
*/
|
||||
public class HardinessZoneNotSetException extends Exception {
|
||||
public HardinessZoneNotSetException() {
|
||||
super("HardinessZone must be set to retrieve plants!");
|
||||
|
||||
@@ -2,6 +2,9 @@ package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Excption which is thrown if a JSON file has a invalid File format.
|
||||
*/
|
||||
class InvalidJsonException extends IOException {
|
||||
public InvalidJsonException(String reason) {
|
||||
super(reason);
|
||||
|
||||
@@ -166,14 +166,12 @@ public class GardenSchedule {
|
||||
dayTaskList.add(new ArrayList<>());
|
||||
final int finalI = i;
|
||||
weekTasks.forEach(task -> {
|
||||
if (task.getNextExecution() == null) {
|
||||
task.isDone();
|
||||
} else {
|
||||
if(task.getNextExecution() != null) {
|
||||
LocalDate checkDate = task.getNextExecution();
|
||||
|
||||
do {
|
||||
if (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN))) {
|
||||
if (date.equals(task.getNextExecution()) || (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN)))) {
|
||||
dayTaskList.get(finalI).add(task);
|
||||
break;
|
||||
}
|
||||
checkDate = checkDate.plusDays(task.getInterval().orElse(0));
|
||||
} while (!(task.getInterval().orElse(0) == 0) && checkDate.isBefore(LocalDate.now().plusDays(listLength)));
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package ch.zhaw.gartenverwaltung.models;
|
||||
|
||||
/**
|
||||
* Exception which is thrown if there is no plant in plant Database with the given id.
|
||||
*/
|
||||
public class PlantNotFoundException extends Exception {
|
||||
public PlantNotFoundException() {
|
||||
super("The selected Plant was not found in Database!");
|
||||
|
||||
@@ -40,7 +40,6 @@ public class Crop {
|
||||
public Optional<Long> getCropId() {
|
||||
return Optional.ofNullable(cropId);
|
||||
}
|
||||
|
||||
public long getPlantId() { return plantId; }
|
||||
public LocalDate getStartDate() { return startDate; }
|
||||
public double getArea() { return area; }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package ch.zhaw.gartenverwaltung.types;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -55,11 +57,13 @@ public class Task {
|
||||
* @param startDate The start date of the task
|
||||
* @param endDate The maximum date on which the task should be executed
|
||||
*/
|
||||
public Task(String name, String description, LocalDate startDate, LocalDate endDate) {
|
||||
public Task(String name, String description, LocalDate startDate, LocalDate endDate, long cropId) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.startDate = startDate;
|
||||
nextExecution = startDate;
|
||||
this.endDate = endDate;
|
||||
this.cropId = cropId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +108,7 @@ public class Task {
|
||||
* @return Whether the Task is within the given range
|
||||
*/
|
||||
public boolean isInTimePeriod(LocalDate searchStartDate, LocalDate searchEndDate) {
|
||||
return endDate.isAfter(searchStartDate) && startDate.isBefore(searchEndDate) || (nextExecution != null && nextExecution.isBefore(searchEndDate) && nextExecution.isAfter(searchStartDate));
|
||||
return (endDate.isAfter(searchStartDate) && startDate.isBefore(searchEndDate)) || ((nextExecution != null && nextExecution.isBefore(searchEndDate.plusDays(1)) && nextExecution.isAfter(searchStartDate.minusDays(1))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,6 +124,7 @@ public class Task {
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isDone(){
|
||||
return nextExecution == null;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Class which represents a Task if the start and enddate is not known yet.
|
||||
*/
|
||||
public class TaskTemplate {
|
||||
@JsonProperty
|
||||
private final String name;
|
||||
|
||||
@@ -19,19 +19,19 @@
|
||||
<content>
|
||||
<VBox fx:id="cropDetailVBox" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="781.0" prefWidth="897.0" spacing="5.0">
|
||||
<children>
|
||||
<Button mnemonicParsing="false" onAction="#goBack" prefHeight="25.0" prefWidth="91.0" text="Go Back">
|
||||
<Button styleClass="button-class" mnemonicParsing="false" onAction="#goBack" prefHeight="25.0" prefWidth="91.0" text="Go Back">
|
||||
<VBox.margin>
|
||||
<Insets bottom="10.0" />
|
||||
</VBox.margin>
|
||||
</Button>
|
||||
<Label fx:id="cropName_label" text="Label">
|
||||
<Label styleClass="page-title" fx:id="cropName_label" text="Label">
|
||||
<VBox.margin>
|
||||
<Insets bottom="10.0" />
|
||||
</VBox.margin>
|
||||
</Label>
|
||||
<HBox maxHeight="1.7976931348623157E308" prefHeight="268.0" prefWidth="855.0" spacing="10.0" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<GridPane maxWidth="1.7976931348623157E308" prefHeight="231.0" prefWidth="555.0" HBox.hgrow="ALWAYS">
|
||||
<GridPane styleClass="custom-container" maxWidth="1.7976931348623157E308" prefHeight="231.0" prefWidth="555.0" HBox.hgrow="ALWAYS">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" maxWidth="284.0" minWidth="10.0" prefWidth="97.33334350585938" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="488.99999237060547" minWidth="10.0" prefWidth="481.9999898274739" />
|
||||
@@ -72,6 +72,9 @@
|
||||
</GridPane.margin>
|
||||
</Label>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</GridPane>
|
||||
<ImageView fx:id="imageView" fitHeight="250.0" fitWidth="250.0" pickOnBounds="true" preserveRatio="true" HBox.hgrow="NEVER" />
|
||||
</children>
|
||||
@@ -86,7 +89,7 @@
|
||||
<Insets bottom="10.0" />
|
||||
</VBox.margin>
|
||||
</ListView>
|
||||
<Button fx:id="addTask_button" mnemonicParsing="false" onAction="#addTask" prefHeight="25.0" prefWidth="45.0" VBox.vgrow="NEVER">
|
||||
<Button styleClass="button-class" fx:id="addTask_button" mnemonicParsing="false" onAction="#addTask" prefHeight="25.0" prefWidth="120.0" VBox.vgrow="NEVER" text="Add Task">
|
||||
<VBox.margin>
|
||||
<Insets />
|
||||
</VBox.margin>
|
||||
@@ -109,7 +112,7 @@
|
||||
<Insets right="10.0" />
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<Button fx:id="area_button" mnemonicParsing="false" onAction="#setArea" prefHeight="25.0" prefWidth="116.0" text="Set Area" />
|
||||
<Button styleClass="button-class" fx:id="area_button" mnemonicParsing="false" onAction="#setArea" prefHeight="25.0" prefWidth="116.0" text="Set Area" />
|
||||
</children>
|
||||
<VBox.margin>
|
||||
<Insets />
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<content>
|
||||
<VBox fx:id="homeVBox" prefHeight="1047.0" prefWidth="1019.0" spacing="10.0">
|
||||
<children>
|
||||
<Label text="Garden Management">
|
||||
<Label styleClass="page-title" text="Garden Management">
|
||||
<font>
|
||||
<Font size="34.0" />
|
||||
</font>
|
||||
@@ -34,7 +34,7 @@
|
||||
<Insets />
|
||||
</VBox.margin>
|
||||
</Label>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0" style="-fx-background-color: white; -fx-border-color: black;">
|
||||
<VBox styleClass="vbox" prefHeight="200.0" prefWidth="100.0" spacing="5.0">
|
||||
<children>
|
||||
<Label text="Base Functionalities:">
|
||||
<font>
|
||||
@@ -79,7 +79,7 @@
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0" style="-fx-background-color: white; -fx-border-color: black;">
|
||||
<VBox styleClass="vbox" prefHeight="200.0" prefWidth="100.0" spacing="5.0">
|
||||
<children>
|
||||
<Label text="Advanced Functionalities:">
|
||||
<font>
|
||||
@@ -114,7 +114,7 @@
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0" style="-fx-background-color: white; -fx-border-color: black;">
|
||||
<VBox styleClass="vbox" prefHeight="200.0" prefWidth="100.0" spacing="5.0">
|
||||
<children>
|
||||
<Label text="Weather Forcast:">
|
||||
<font>
|
||||
@@ -139,7 +139,7 @@
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="15.0" style="-fx-background-color: white; -fx-border-color: black;">
|
||||
<VBox styleClass="vbox" prefHeight="200.0" prefWidth="100.0" spacing="15.0">
|
||||
<children>
|
||||
<Label text="Created by:">
|
||||
<font>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<children>
|
||||
<VBox layoutY="49.0" prefHeight="655.0" prefWidth="1175.0" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<Label text="My Garden">
|
||||
<Label styleClass="page-title" text="My Garden">
|
||||
<font>
|
||||
<Font name="System Bold" size="28.0" />
|
||||
</font>
|
||||
@@ -21,7 +21,7 @@
|
||||
</VBox.margin>
|
||||
</Label>
|
||||
<ListView fx:id="myGarden_listView" maxHeight="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
|
||||
<Button fx:id="addPlant_button" mnemonicParsing="false" onAction="#addPlant" prefHeight="45.0" prefWidth="155.0" text="Add new Plant">
|
||||
<Button styleClass="button-class" fx:id="addPlant_button" mnemonicParsing="false" onAction="#addPlant" prefHeight="45.0" prefWidth="155.0" text="Add new Plant">
|
||||
<VBox.margin>
|
||||
<Insets />
|
||||
</VBox.margin>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<children>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<Label text="MySchedule" VBox.vgrow="NEVER">
|
||||
<Label styleClass="page-title" text="MySchedule" VBox.vgrow="NEVER">
|
||||
<font>
|
||||
<Font size="24.0" />
|
||||
</font>
|
||||
@@ -33,7 +33,7 @@
|
||||
<Insets />
|
||||
</VBox.margin>
|
||||
</ListView>
|
||||
<VBox prefHeight="131.0" prefWidth="603.0" spacing="5.0" style="-fx-background-color: white; -fx-border-color: black;" VBox.vgrow="NEVER">
|
||||
<VBox styleClass="custom-container" prefHeight="131.0" prefWidth="603.0" spacing="5.0" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<Label alignment="TOP_LEFT" maxWidth="1.7976931348623157E308" prefHeight="17.0" prefWidth="558.0" text="Importants Information:" wrapText="true" VBox.vgrow="NEVER">
|
||||
<font>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<children>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<Label prefHeight="45.0" prefWidth="903.0" text="Plants" VBox.vgrow="NEVER">
|
||||
<Label styleClass="page-title" prefHeight="45.0" prefWidth="903.0" text="Plants" VBox.vgrow="NEVER">
|
||||
<font>
|
||||
<Font name="System Bold" size="30.0" />
|
||||
</font>
|
||||
@@ -32,14 +32,14 @@
|
||||
<HBox alignment="CENTER_LEFT" minHeight="300.0" prefHeight="480.0" prefWidth="881.0" spacing="10.0" VBox.vgrow="ALWAYS">
|
||||
<children>
|
||||
<ListView fx:id="list_plants" maxWidth="1.7976931348623157E308" prefHeight="497.0" prefWidth="400.0" HBox.hgrow="ALWAYS" />
|
||||
<Pane maxHeight="1.7976931348623157E308" maxWidth="300.0" minWidth="300.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: white; -fx-border-color: black;" HBox.hgrow="NEVER">
|
||||
<Pane styleClass="custom-container" maxHeight="1.7976931348623157E308" maxWidth="300.0" minWidth="300.0" prefHeight="200.0" prefWidth="200.0" HBox.hgrow="NEVER">
|
||||
<children>
|
||||
<ImageView fx:id="img_plant" fitWidth="300" pickOnBounds="true" preserveRatio="true" />
|
||||
</children>
|
||||
</Pane>
|
||||
</children>
|
||||
</HBox>
|
||||
<VBox maxHeight="1.7976931348623157E308" prefHeight="237.0" prefWidth="879.0" style="-fx-background-color: white; -fx-border-color: black;" VBox.vgrow="ALWAYS">
|
||||
<VBox styleClass="vbox" maxHeight="1.7976931348623157E308" prefHeight="237.0" prefWidth="879.0" VBox.vgrow="ALWAYS">
|
||||
<children>
|
||||
<Label maxHeight="1.7976931348623157E308" prefHeight="33.0" prefWidth="919.0" text="Plant Information:" VBox.vgrow="NEVER">
|
||||
<font>
|
||||
@@ -51,7 +51,7 @@
|
||||
<Insets bottom="10.0" top="10.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Button fx:id="selectSowDay_button" alignment="CENTER" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#selectSowDate" prefHeight="38.0" prefWidth="917.0" text="Select Harvest/Sow Day" VBox.vgrow="NEVER" />
|
||||
<Button styleClass="button-class" fx:id="selectSowDay_button" alignment="CENTER" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#selectSowDate" prefHeight="38.0" prefWidth="917.0" text="Select Harvest/Sow Day" VBox.vgrow="NEVER" />
|
||||
</children>
|
||||
<VBox.margin>
|
||||
<Insets />
|
||||
@@ -67,7 +67,7 @@
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
</AnchorPane>
|
||||
<AnchorPane maxWidth="300.0" minHeight="0.0" minWidth="300.0" prefHeight="160.0" prefWidth="100.0" style="-fx-border-color: black; -fx-background-color: white;">
|
||||
<AnchorPane styleClass="custom-container" maxWidth="300.0" minHeight="0.0" minWidth="300.0" prefHeight="160.0" prefWidth="100.0">
|
||||
<children>
|
||||
<VBox layoutX="38.0" layoutY="100.0" prefHeight="850.6666666666666" prefWidth="316.6666666666667" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
@@ -78,7 +78,7 @@
|
||||
</Label>
|
||||
<TitledPane animated="false" text="Seasons">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<AnchorPane styleClass="custom-container" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<children>
|
||||
<VBox fx:id="seasons" layoutX="37.0" layoutY="-19.0" prefHeight="180.66666666666666" prefWidth="310.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
@@ -87,7 +87,7 @@
|
||||
</TitledPane>
|
||||
<TitledPane animated="false" text="Climate Zones">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<AnchorPane styleClass="custom-container" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<children>
|
||||
<VBox fx:id="climate_zones" layoutX="36.0" layoutY="-19.0" prefHeight="180.66666666666666" prefWidth="310.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
<Separator prefWidth="50.0" visible="false" HBox.hgrow="ALWAYS" />
|
||||
<ButtonBar prefHeight="40.0" prefWidth="200.0">
|
||||
<buttons>
|
||||
<Button cancelButton="true" contentDisplay="CENTER" graphicTextGap="5.0" mnemonicParsing="false" text="Close" onAction="#closeTutorial"/>
|
||||
<Button fx:id="previousPageButton" mnemonicParsing="false" text="Previous" onAction="#viewPreviousPage"/>
|
||||
<Button fx:id="nextPageButton" defaultButton="true" mnemonicParsing="false" text="Next" onAction="#viewNextPage" />
|
||||
<Button cancelButton="true" contentDisplay="CENTER" graphicTextGap="5.0" mnemonicParsing="false" onAction="#closeTutorial" styleClass="button-class" text="Close" />
|
||||
<Button fx:id="previousPageButton" mnemonicParsing="false" onAction="#viewPreviousPage" styleClass="button-class" text="Previous" />
|
||||
<Button fx:id="nextPageButton" defaultButton="true" mnemonicParsing="false" onAction="#viewNextPage" styleClass="button-class" text="Next" />
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</children>
|
||||
@@ -38,7 +38,7 @@
|
||||
<children>
|
||||
<VBox layoutX="30.0" layoutY="26.0" opacity="0.0" prefHeight="200.0" prefWidth="100.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Managing Your Crops">
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Adding Crops">
|
||||
<font>
|
||||
<Font size="24.0" />
|
||||
</font>
|
||||
@@ -75,7 +75,7 @@
|
||||
</children>
|
||||
</TextFlow>
|
||||
<Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
|
||||
<ImageView fx:id="imgSelectDate" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
|
||||
<ImageView fx:id="imgSelectDate" fitHeight="150.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true" />
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
@@ -83,7 +83,50 @@
|
||||
<Insets />
|
||||
</opaqueInsets>
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0">
|
||||
<VBox layoutX="30.0" layoutY="30.0" prefHeight="200.0" prefWidth="100.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Managing Your Crops">
|
||||
<font>
|
||||
<Font size="24.0" />
|
||||
</font>
|
||||
</Text>
|
||||
<Separator prefWidth="200.0">
|
||||
<VBox.margin>
|
||||
<Insets bottom="15.0" top="10.0" />
|
||||
</VBox.margin>
|
||||
</Separator>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Once you've added a crop to your garden, it will be displayed in the "My Garden" tab.">
|
||||
<VBox.margin>
|
||||
<Insets bottom="20.0" />
|
||||
</VBox.margin>
|
||||
</Text>
|
||||
<HBox prefHeight="100.0" prefWidth="200.0">
|
||||
<children>
|
||||
<TextFlow lineSpacing="4.0" prefHeight="200.0" prefWidth="500.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="On the right hand side of the listing, you'll see two buttons. Button with the "trash can" icon lets you remove a crop from your garden plan. This will also delete all associated tasks. The button on the left will display the details of the crop in a new window." />
|
||||
</children>
|
||||
</TextFlow>
|
||||
<Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
|
||||
<ImageView fitHeight="70.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true" fx:id="imgDetailDeleteButtons"/>
|
||||
</children></HBox>
|
||||
<HBox layoutX="10.0" layoutY="105.0" prefHeight="100.0" prefWidth="200.0">
|
||||
<children>
|
||||
<TextFlow lineSpacing="4.0" prefHeight="200.0" prefWidth="500.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Here, you can also add your own custom tasks, by clicking the "Add Task" button. In the subsequently shown dialog, you can enter the corresponding details. Note: If you want to make a task recurring, you need to set both an interval (in days) AND an end date, so the task won't repeat for all eternity." />
|
||||
</children>
|
||||
</TextFlow>
|
||||
<Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
|
||||
<ImageView fitHeight="150.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true" fx:id="imgAddTaskButton"/>
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
<opaqueInsets>
|
||||
<Insets />
|
||||
</opaqueInsets>
|
||||
</VBox>
|
||||
<VBox opacity="0.0" prefHeight="200.0" prefWidth="100.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Managing Your Tasks">
|
||||
<font>
|
||||
@@ -111,19 +154,9 @@
|
||||
</HBox.margin>
|
||||
</TextFlow>
|
||||
<Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
|
||||
<ImageView fx:id="imgTaskList" fitHeight="98.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
|
||||
<ImageView fx:id="imgTaskList" fitHeight="200.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox prefHeight="100.0" prefWidth="200.0">
|
||||
<children>
|
||||
<TextFlow lineSpacing="4.0" prefHeight="200.0" prefWidth="500.0">
|
||||
<children>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="You can also add your own custom tasks, by clicking the "Add Task" button. In the subsequently shown dialog, you can enter the corresponding details. Note: If you want to make a task recurring, you need to set both an interval (in days) AND an end date, so the task won't repeat for all eternity." />
|
||||
</children>
|
||||
</TextFlow>
|
||||
<Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
|
||||
<ImageView fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
|
||||
</children></HBox>
|
||||
</children>
|
||||
<opaqueInsets>
|
||||
<Insets />
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
.myDialog *.header-panel,
|
||||
.myDialog *.header-panel .label {
|
||||
-fx-background-color: #D3FFB5;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
.myDialog {
|
||||
-fx-background-color: #EAFFE2;
|
||||
-fx-border-color: black;
|
||||
}
|
||||
|
||||
.myDialog .button {
|
||||
-fx-border-color: darkgreen;
|
||||
-fx-border-radius: 4;
|
||||
-fx-border-width: 1.5;
|
||||
-fx-background-color: #D1FFB7;
|
||||
-fx-font-weight: bold;
|
||||
-fx-font-size: 13
|
||||
}
|
||||
|
||||
.myDialog .check-box .box {
|
||||
-fx-background-color: #D3FFB5;
|
||||
-fx-border-color:grey;
|
||||
-fx-border-radius: 3;
|
||||
}
|
||||
|
||||
.myDialog .combo-box .list-cell
|
||||
{
|
||||
-fx-background-color: #D1FFB7;
|
||||
-fx-text-fill: -fx-text-base-color;
|
||||
}
|
||||
|
||||
.myDialog .combo-box-popup .list-view
|
||||
{
|
||||
-fx-background-color: darkgreen, darkgreen;
|
||||
-fx-background-insets: 0, 1;
|
||||
-fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 8, 0.0 , 0 , 0 );
|
||||
}
|
||||
|
||||
.myDialog .combo-box-popup .list-view .list-cell
|
||||
{
|
||||
-fx-padding: 4 0 4 5;
|
||||
|
||||
/* No alternate highlighting */
|
||||
-fx-background-color: #EAFFE2;
|
||||
}
|
||||
|
||||
.myDialog .combo-box-popup .list-view .list-cell:filled:selected, .combo-box-popup .list-view .list-cell:filled:selected:hover
|
||||
{
|
||||
-fx-background: -fx-accent;
|
||||
-fx-text-fill: black;
|
||||
-fx-background-color: #D1FFB7;
|
||||
|
||||
}
|
||||
|
||||
.myDialog .combo-box-popup .list-view .list-cell:filled:hover
|
||||
{
|
||||
-fx-text-fill: black;
|
||||
-fx-background-color: #54B91C;
|
||||
|
||||
}
|
||||
|
||||
.myDialog .combo-box-base {
|
||||
-fx-border-color: grey;
|
||||
-fx-background-color: #D1FFB7;
|
||||
}
|
||||
|
||||
.myDialog .combo-box-base:hover
|
||||
{
|
||||
-fx-color: #54B91C;
|
||||
}
|
||||
|
||||
.myDialog .radio-button .radio {
|
||||
-fx-background-color: #D3FFB5;
|
||||
-fx-border-color:grey;
|
||||
-fx-border-radius: 25;
|
||||
}
|
||||
|
||||
.myDialog .date-picker .button {
|
||||
-fx-border-color: none;
|
||||
-fx-background-color: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
|
||||
.button-class {
|
||||
-fx-border-color: darkgreen;
|
||||
-fx-border-radius: 4;
|
||||
-fx-border-width: 1.5;
|
||||
-fx-background-color: #D1FFB7;
|
||||
-fx-font-weight: bold;
|
||||
-fx-font-size: 13
|
||||
}
|
||||
|
||||
#home_button, #myGarden_button,
|
||||
#mySchedule_button, #settings_button,
|
||||
#tutorial_button, #menu_pane {
|
||||
-fx-text-fill: white;
|
||||
-fx-background-color: rgb(0,128,0);
|
||||
-fx-border-color: rgb(0,128,0);
|
||||
-fx-border-radius: 0;
|
||||
}
|
||||
|
||||
#menubar {
|
||||
@@ -13,13 +22,64 @@
|
||||
|
||||
#home_button:hover, #myGarden_button:hover,
|
||||
#mySchedule_button:hover, #settings_button:hover,
|
||||
#tutorial_button:hover,
|
||||
#home_button:focused, #myGarden_button:focused,
|
||||
#mySchedule_button:focused, #settings_button:focused,
|
||||
#tutorial_button:focused{
|
||||
#tutorial_button:hover {
|
||||
-fx-background-color: darkgreen;
|
||||
}
|
||||
|
||||
.root, .scroll-pane, #homeVBox, #cropDetailVBox {
|
||||
-fx-background-color: #e6ffe6;
|
||||
}
|
||||
-fx-background-color: #F3FFEC;
|
||||
}
|
||||
|
||||
.list-view {
|
||||
-fx-border-color: black;
|
||||
-fx-background-color: #EAFFE2;
|
||||
}
|
||||
|
||||
.list-cell:even:filled:selected:focused .label,
|
||||
.list-cell:even:filled:selected .label,
|
||||
.list-cell:even {
|
||||
-fx-background-color: #EAFFE2;
|
||||
-fx-text-fill: black;
|
||||
}
|
||||
|
||||
.list-cell:odd:filled:selected:focused .label,
|
||||
.list-cell:odd:filled:selected .label,
|
||||
.list-cell:odd {
|
||||
-fx-background-color: #D3FFB5;
|
||||
-fx-text-fill: black;
|
||||
}
|
||||
|
||||
#list_plants .list-cell:even:filled:selected:focused,
|
||||
#list_plants .list-cell:even:filled:selected,
|
||||
#list_plants .list-cell:odd:filled:selected:focused,
|
||||
#list_plants .list-cell:odd:filled:selected,
|
||||
#scheduledPlants_listview .list-cell:even:filled:selected:focused,
|
||||
#scheduledPlants_listview .list-cell:even:filled:selected,
|
||||
#scheduledPlants_listview .list-cell:odd:filled:selected:focused,
|
||||
#scheduledPlants_listview .list-cell:odd:filled:selected{
|
||||
-fx-background-color: #7CD14B;
|
||||
-fx-text-fill: white;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.vbox, .custom-container {
|
||||
-fx-background-color: #EAFFE2;
|
||||
-fx-border-color: black;
|
||||
}
|
||||
|
||||
.titled-pane > .title {
|
||||
-fx-background-color: #D3FFB5;
|
||||
-fx-border-color: black;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
-fx-font-size: 20;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.radio-button .radio {
|
||||
-fx-background-color: #D3FFB5;
|
||||
-fx-border-color:grey;
|
||||
-fx-border-radius: 25;
|
||||
}
|
||||
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.io.*;
|
||||
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
|
||||
import ch.zhaw.gartenverwaltung.types.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.time.LocalDate;
|
||||
import java.time.MonthDay;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class WeatherGardenTaskPlannerTest {
|
||||
private final URL testFile = JsonCropListTest.class.getResource("test-taskdb.json");
|
||||
Plant examplePlantOnion;
|
||||
Crop exampleCropOnion;
|
||||
Task exampleTask;
|
||||
Task exampleWeatherTask;
|
||||
List<Crop> cropList;
|
||||
List<Plant> plantList;
|
||||
TaskList taskList;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
examplePlantOnion = new Plant(
|
||||
20,
|
||||
"summertime onion",
|
||||
"Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.",
|
||||
null,
|
||||
"15,30,2",
|
||||
0,
|
||||
"sandy to loamy, loose soil, free of stones",
|
||||
new ArrayList<>(),
|
||||
new WateringCycle(15, 3, null),
|
||||
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
|
||||
new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())));
|
||||
|
||||
exampleCropOnion = new Crop(examplePlantOnion.id(), LocalDate.of(2022, 12, 5))
|
||||
.withId(3L);
|
||||
exampleTask = new Task("water plant","water the plant until the ground is wet enough",LocalDate.now(), LocalDate.now().plusDays(2L),3L);
|
||||
exampleTask.setNextExecution(LocalDate.now().plusDays(1L));
|
||||
exampleWeatherTask = new Task("Hail",
|
||||
"During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin",
|
||||
LocalDate.now(),LocalDate.now().plusDays(1L),3L);
|
||||
|
||||
taskList = new JsonTaskList(testFile);
|
||||
|
||||
plantList = new ArrayList<>();
|
||||
plantList.add(examplePlantOnion);
|
||||
|
||||
cropList = new ArrayList<>();
|
||||
cropList.add(exampleCropOnion);
|
||||
|
||||
}
|
||||
|
||||
CropList mockCropList(List<Crop> cropList) throws IOException {
|
||||
CropList croplist = mock(CropList.class);
|
||||
when(croplist.getCrops()).thenReturn(cropList);
|
||||
when(croplist.getCropById(3)).thenReturn(java.util.Optional.ofNullable(exampleCropOnion));
|
||||
return croplist;
|
||||
}
|
||||
|
||||
PlantList mockPlantDatabase(List<Plant> plantList) throws HardinessZoneNotSetException, IOException {
|
||||
PlantList plantDatabase = mock(JsonPlantList.class);
|
||||
when(plantDatabase.getPlantList(HardinessZone.ZONE_8A)).thenReturn(plantList);
|
||||
when(plantDatabase.getPlantById(HardinessZone.ZONE_8A,20)).thenReturn(Optional.of(plantList.get(0)));
|
||||
return plantDatabase;
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshtasks() throws HardinessZoneNotSetException, IOException, PlantNotFoundException {
|
||||
WeatherGradenTaskPlanner weatherGradenTaskPlanner = new WeatherGradenTaskPlanner(taskList, mockPlantDatabase(plantList), mockCropList(cropList));
|
||||
taskList.saveTask(exampleTask);
|
||||
weatherGradenTaskPlanner.refreshTasks();
|
||||
assertEquals(exampleTask.getName(),taskList.getTaskList(LocalDate.now(),LocalDate.now().plusDays(7)).get(0).getName());
|
||||
assertEquals(LocalDate.now().plusDays(2L),taskList.getTaskList(LocalDate.now(),LocalDate.now().plusDays(7)).get(0).getNextExecution());
|
||||
assertEquals(exampleWeatherTask.getName(),taskList.getTaskList(LocalDate.now(),LocalDate.now().plusDays(7)).get(1).getName());
|
||||
assertEquals(exampleWeatherTask.getStartDate(),taskList.getTaskList(LocalDate.now(),LocalDate.now().plusDays(7)).get(1).getStartDate());
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.models.GardenSchedule;
|
||||
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
|
||||
import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
import ch.zhaw.gartenverwaltung.types.Task;
|
||||
import javafx.application.Platform;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@@ -13,6 +18,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
@@ -27,6 +33,22 @@ public class JsonTaskListTest {
|
||||
private final URL dbDataSource = this.getClass().getResource("test-taskdb.json");
|
||||
private final URL testFile = this.getClass().getResource("template-taskdb.json");
|
||||
|
||||
|
||||
@BeforeAll
|
||||
static void setUpAll() {
|
||||
try{
|
||||
Platform.startup(()->{});
|
||||
}catch (IllegalStateException ise){
|
||||
//ignore double launches
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDownAll() {
|
||||
//Dont do: Platform.exit();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void connectToDb() throws URISyntaxException, IOException {
|
||||
assertNotNull(testFile);
|
||||
@@ -35,6 +57,10 @@ public class JsonTaskListTest {
|
||||
testDatabase = new JsonTaskList(dbDataSource);
|
||||
}
|
||||
|
||||
private void reloadDb() {
|
||||
testDatabase = new JsonTaskList(dbDataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Check if results are retrieved completely")
|
||||
void getTasks() {
|
||||
@@ -47,7 +73,8 @@ public class JsonTaskListTest {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Assertions.assertEquals(3, taskList.size());
|
||||
List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
|
||||
Assertions.assertEquals(Arrays.asList(1L, 2L, 5L), ids);
|
||||
|
||||
}
|
||||
|
||||
@@ -65,7 +92,8 @@ public class JsonTaskListTest {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Assertions.assertEquals(4, taskList.size());
|
||||
List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
|
||||
Assertions.assertEquals(Arrays.asList(1L, 2L, 5L, 9L), ids);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -83,7 +111,8 @@ public class JsonTaskListTest {
|
||||
taskList = testDatabase.getTaskList(LocalDate.parse("2022-04-30", formatter),
|
||||
LocalDate.parse("2022-05-31", formatter));
|
||||
|
||||
Assertions.assertEquals(2, taskList.size());
|
||||
List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
|
||||
Assertions.assertEquals(Arrays.asList(1L, 5L), ids);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -100,8 +129,8 @@ public class JsonTaskListTest {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Assertions.assertEquals(6, taskList.size());
|
||||
|
||||
List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
|
||||
Assertions.assertEquals(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L), ids);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,10 +145,20 @@ public class JsonTaskListTest {
|
||||
}
|
||||
|
||||
Assertions.assertEquals(0, taskList.size());
|
||||
|
||||
try {
|
||||
taskList = testDatabase.getTaskForCrop(1);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
List<Long> ids = (taskList.stream().map( task -> task.getId().orElse(0L)).toList());
|
||||
Assertions.assertEquals(Arrays.asList(7L, 8L), ids);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultConstructor(){
|
||||
void testDefaultConstructor() {
|
||||
JsonTaskList db = new JsonTaskList();
|
||||
try {
|
||||
assertNotNull(db.getTaskForCrop(0));
|
||||
@@ -138,6 +177,43 @@ public class JsonTaskListTest {
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
verify(mockObs, times(1)).onChange(ArgumentMatchers.anyList());
|
||||
|
||||
ArgumentCaptor<List<Task>> captor = ArgumentCaptor.forClass(List.class);
|
||||
|
||||
verify(mockObs, times(1)).onChange(captor.capture());
|
||||
List<Long> ids = captor.getValue().stream().map(t -> t.getId().orElse(0L)).toList();
|
||||
Assertions.assertEquals(Arrays.asList(7L, 8L), ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("IntegrationTest")
|
||||
void testComplete() {
|
||||
JsonPlantList plantList = new JsonPlantList();
|
||||
try {
|
||||
testDatabase.removeTasksForCrop(0);
|
||||
testDatabase.removeTasksForCrop(1);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
GardenSchedule gardenSchedule = null;
|
||||
try {
|
||||
gardenSchedule = new GardenSchedule(testDatabase, plantList);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Crop crop = new Crop(3L, LocalDate.parse("2022-12-01", formatter));
|
||||
|
||||
try {
|
||||
gardenSchedule.planTasksForCrop(crop);
|
||||
|
||||
reloadDb();
|
||||
|
||||
List<Task> tasks = gardenSchedule.getTaskList();
|
||||
List<String> tasknames = (tasks.stream().map( task -> task.getName().substring(0,3).toLowerCase()).toList());
|
||||
Assertions.assertEquals(Arrays.asList("ger","wat","hil","har"), tasknames);
|
||||
} catch (IOException | PlantNotFoundException | HardinessZoneNotSetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@ package ch.zhaw.gartenverwaltung.models;
|
||||
import ch.zhaw.gartenverwaltung.io.*;
|
||||
import ch.zhaw.gartenverwaltung.models.GardenSchedule;
|
||||
import ch.zhaw.gartenverwaltung.types.*;
|
||||
import javafx.application.Platform;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -29,6 +32,21 @@ class GardenScheduleTest {
|
||||
List<TaskTemplate> exampleTaskTemplateList;
|
||||
GardenSchedule model;
|
||||
|
||||
@BeforeAll
|
||||
static void setUpAll() {
|
||||
try{
|
||||
Platform.startup(()->{});
|
||||
}catch (IllegalStateException ise){
|
||||
//ignore double launches
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDownAll() {
|
||||
//Dont do: Platform.exit();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws IOException, HardinessZoneNotSetException {
|
||||
createExampleTaskList();
|
||||
@@ -221,5 +239,8 @@ class GardenScheduleTest {
|
||||
testTaskList.getTaskList(LocalDate.MIN,LocalDate.MAX).get(0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testPlantNotFoundException() throws HardinessZoneNotSetException, IOException {
|
||||
assertThrowsExactly(PlantNotFoundException.class, () -> { model.planTasksForCrop(new Crop(0, exampleStartDate)); });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
[
|
||||
]
|
||||
@@ -26,8 +26,8 @@
|
||||
"name" : "fertilize plant",
|
||||
"description": "The fertilizer has to be mixed with water. Then fertilize the plants soil with the mixture",
|
||||
"startDate" : "2022-06-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"nextExecution": "2022-06-01",
|
||||
"nextNotification": "2022-06-01",
|
||||
"endDate" : "2022-08-01",
|
||||
"interval" : 28,
|
||||
"cropId" : 0
|
||||
@@ -37,8 +37,8 @@
|
||||
"name" : "covering plant",
|
||||
"description": "Take a big enough coverage for the plants. Cover the whole plant with a bit space between the plant and the coverage",
|
||||
"startDate" : "2022-07-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"nextExecution": "2022-07-01",
|
||||
"nextNotification": "2022-07-01",
|
||||
"endDate" : "2022-07-01",
|
||||
"interval" : 0,
|
||||
"cropId" : 0
|
||||
@@ -59,10 +59,32 @@
|
||||
"name" : "harvest plant",
|
||||
"description": "Pull the ripe vegetables out from the soil. Clean them with clear, fresh water. ",
|
||||
"startDate" : "2022-09-01",
|
||||
"nextExecution": "2022-05-01",
|
||||
"nextNotification": "2022-05-01",
|
||||
"nextExecution": "2022-09-01",
|
||||
"nextNotification": "2022-09-01",
|
||||
"endDate" : "2022-09-01",
|
||||
"interval" : 0,
|
||||
"cropId" : 0
|
||||
},
|
||||
{
|
||||
"id" : 7,
|
||||
"name" : "sow plant",
|
||||
"description": "Plant the seeds, crops in de bed.",
|
||||
"startDate" : "2022-11-01",
|
||||
"nextExecution": "2022-11-01",
|
||||
"nextNotification": "2022-11-01",
|
||||
"endDate" : "2022-11-01",
|
||||
"interval" : 0,
|
||||
"cropId" : 1
|
||||
},
|
||||
{
|
||||
"id" : 8,
|
||||
"name" : "harvest plant",
|
||||
"description": "Pull the ripe vegetables out from the soil. Clean them with clear, fresh water. ",
|
||||
"startDate" : "2022-12-01",
|
||||
"nextExecution": "2022-12-01",
|
||||
"nextNotification": "2022-12-01",
|
||||
"endDate" : "2022-12-01",
|
||||
"interval" : 0,
|
||||
"cropId" : 1
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user