From 384dc2d85313df09d4c470b2a272d8ab2d91a891 Mon Sep 17 00:00:00 2001 From: schrom01 Date: Fri, 18 Nov 2022 11:34:53 +0100 Subject: [PATCH 01/13] completed Tests for GardenScheduleTest --- .../GardenScheduleTest.java | 86 +++++++++++++------ 1 file changed, 62 insertions(+), 24 deletions(-) rename src/test/java/ch/zhaw/gartenverwaltung/{taskList => models}/GardenScheduleTest.java (57%) diff --git a/src/test/java/ch/zhaw/gartenverwaltung/taskList/GardenScheduleTest.java b/src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java similarity index 57% rename from src/test/java/ch/zhaw/gartenverwaltung/taskList/GardenScheduleTest.java rename to src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java index cf354de..0cadffb 100644 --- a/src/test/java/ch/zhaw/gartenverwaltung/taskList/GardenScheduleTest.java +++ b/src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java @@ -1,35 +1,45 @@ -package ch.zhaw.gartenverwaltung.taskList; +package ch.zhaw.gartenverwaltung.models; import ch.zhaw.gartenverwaltung.io.*; import ch.zhaw.gartenverwaltung.models.GardenSchedule; -import ch.zhaw.gartenverwaltung.types.HardinessZone; -import ch.zhaw.gartenverwaltung.types.Plant; -import ch.zhaw.gartenverwaltung.types.Task; +import ch.zhaw.gartenverwaltung.types.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.LocalDate; +import java.time.MonthDay; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; class GardenScheduleTest { + LocalDate exampleStartDate = LocalDate.of(2020, 02, 02); TaskList taskList; PlantList plantList; + List examplePlantList; List exampleTaskList; - Map examplePlantMap; + List exampleTaskTemplateList; GardenSchedule model; @BeforeEach - void setUp() throws IOException { + void setUp() throws IOException, HardinessZoneNotSetException { createExampleTaskList(); + createExampleTaskTemplateList(); + createExamplePlantList(); taskList = mockTaskDatabase(exampleTaskList); - plantList = mockPlantDatabase(examplePlantMap); + plantList = mockPlantDatabase(examplePlantList); model = new GardenSchedule(taskList, plantList); } + PlantList mockPlantDatabase(List 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(examplePlantList.get(0))); + return plantDatabase; + } + private TaskList mockTaskDatabase(List exampleTaskList) throws IOException { TaskList taskList = mock(JsonTaskList.class); when(taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)).thenReturn(exampleTaskList); @@ -54,18 +64,39 @@ class GardenScheduleTest { return taskList; } - private PlantList mockPlantDatabase(Map examplePlantMap) { - return new PlantList() { - @Override - public List getPlantList(HardinessZone zone) { - return null; - } + void createExampleTaskTemplateList(){ + exampleTaskTemplateList = new ArrayList<>(); + exampleTaskTemplateList.add(mock(TaskTemplate.class)); + exampleTaskTemplateList.add(mock(TaskTemplate.class)); + exampleTaskTemplateList.add(mock(TaskTemplate.class)); + exampleTaskTemplateList.add(mock(TaskTemplate.class)); + when(exampleTaskTemplateList.get(0).generateTask(exampleStartDate, 30)).thenReturn(exampleTaskList.get(0)); + when(exampleTaskTemplateList.get(1).generateTask(exampleStartDate, 30)).thenReturn(exampleTaskList.get(1)); + when(exampleTaskTemplateList.get(2).generateTask(exampleStartDate, 30)).thenReturn(exampleTaskList.get(2)); + when(exampleTaskTemplateList.get(3).generateTask(exampleStartDate, 30)).thenReturn(exampleTaskList.get(3)); + } - @Override - public Optional getPlantById(HardinessZone zone, long id) { - return Optional.ofNullable(examplePlantMap.get(id)); - } - }; + void createExamplePlantList(){ + examplePlantList = new ArrayList<>(); + examplePlantList.add(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<>(), + List.of( + new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, List.of( + exampleTaskTemplateList.get(0), + exampleTaskTemplateList.get(1) + )), + new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, List.of( + exampleTaskTemplateList.get(2), + exampleTaskTemplateList.get(3) + )) + ))); } void createExampleTaskList() { @@ -77,12 +108,6 @@ class GardenScheduleTest { exampleTaskList.add(new Task("name", "description", LocalDate.of(2019, 5, 5), 2L)); } - void createExamplePlantMap() { - examplePlantMap = new HashMap<>(); - } - - - @Test void addTask() throws IOException { Task taskToAdd = new Task("name", "description", LocalDate.now(), 1L); @@ -156,4 +181,17 @@ class GardenScheduleTest { model.removeTasksForCrop(1L); verify(taskList, times(1)).removeTasksForCrop(1L); } + + @Test + void planTasksForCrop() throws HardinessZoneNotSetException, PlantNotFoundException, IOException { + model.planTasksForCrop(new Crop(20, exampleStartDate).withId(30)); + verify(exampleTaskTemplateList.get(0), times(1)).generateTask(exampleStartDate, 30); + verify(exampleTaskTemplateList.get(1), times(1)).generateTask(exampleStartDate, 30); + verify(exampleTaskTemplateList.get(2), times(1)).generateTask(exampleStartDate, 30); + verify(exampleTaskTemplateList.get(3), times(1)).generateTask(exampleStartDate, 30); + verify(taskList, times(1)).saveTask(exampleTaskList.get(0)); + verify(taskList, times(1)).saveTask(exampleTaskList.get(1)); + verify(taskList, times(1)).saveTask(exampleTaskList.get(2)); + verify(taskList, times(1)).saveTask(exampleTaskList.get(3)); + } } \ No newline at end of file From 165dc6d9015147e38949c0e94af2090849120247 Mon Sep 17 00:00:00 2001 From: schrom01 Date: Fri, 18 Nov 2022 12:21:21 +0100 Subject: [PATCH 02/13] implemented Method getGrowphaseGroupForDate --- .../zhaw/gartenverwaltung/models/GardenSchedule.java | 3 ++- .../java/ch/zhaw/gartenverwaltung/types/Plant.java | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java index 9195d51..a362f00 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java @@ -46,7 +46,8 @@ public class GardenSchedule { */ public void planTasksForCrop(Crop crop) throws PlantNotFoundException, HardinessZoneNotSetException, IOException { Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).orElseThrow(PlantNotFoundException::new); - for (GrowthPhase growthPhase : plant.lifecycle()) { + int growPhaseGroup = plant.getGrowphaseGroupForDate(crop.getStartDate()); + for (GrowthPhase growthPhase : plant.lifecycleForGroup(growPhaseGroup)) { for (TaskTemplate taskTemplate : growthPhase.taskTemplates()) { addTask(taskTemplate.generateTask(crop.getStartDate(), crop.getCropId().orElse(0L))); } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java index 9cb3d08..5fb6dff 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java @@ -3,6 +3,7 @@ package ch.zhaw.gartenverwaltung.types; import javafx.scene.image.Image; import java.time.LocalDate; +import java.time.MonthDay; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; @@ -39,6 +40,16 @@ public record Plant( .collect(Collectors.toList()); } + public int getGrowphaseGroupForDate(LocalDate date) { + for(GrowthPhase growthPhase : lifecycle){ + MonthDay plantingDate = MonthDay.of(date.getMonth().getValue(), date.getDayOfMonth()); + if(plantingDate.isAfter(growthPhase.startDate()) && plantingDate.isBefore(growthPhase.endDate())){ + return growthPhase.group(); + } + } + return 0; // TODO implement + } + /** * get sow date from given harvest day from lifecycle group * @param harvestDate date of the harvest From bcb36b89c7b025d8c89673a016de4b834ac956d2 Mon Sep 17 00:00:00 2001 From: David Guler Date: Wed, 23 Nov 2022 21:55:35 +0100 Subject: [PATCH 03/13] feature: added tutorial window --- .../gartenverwaltung/MainFXMLController.java | 40 +++-- .../gartenverwaltung/TutorialController.java | 55 +++++++ .../ch/zhaw/gartenverwaltung/MainFXML.fxml | 2 +- .../ch/zhaw/gartenverwaltung/Tutorial.fxml | 148 ++++++++++++++++-- 4 files changed, 215 insertions(+), 30 deletions(-) diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java b/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java index 2cc05d3..33a67c5 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java @@ -11,6 +11,9 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; import java.io.IOException; import java.util.logging.Level; @@ -40,6 +43,9 @@ public class MainFXMLController { @FXML private Button tutorial_button; + private final Stage tutorialModal = new Stage(); + + /** * go to home pane */ @@ -95,11 +101,23 @@ public class MainFXMLController { } /** - * go to Tutorial pane + * Show the tutorial window */ - public void goToTutorial() { - showPaneAsMainView("Tutorial.fxml"); - styleChangeButton(tutorial_button); + public void showTutorial() { + if (!tutorialModal.isShowing()) { + if (tutorialModal.getScene() == null) { + try { + appLoader.loadSceneToStage("Tutorial.fxml", tutorialModal); + tutorialModal.initModality(Modality.NONE); + tutorialModal.setResizable(false); + tutorialModal.sizeToScene(); + } catch (IOException e) { + LOG.log(Level.SEVERE, "Could not load Tutorial"); + } + } + tutorialModal.show(); + } + tutorialModal.requestFocus(); } /** @@ -132,7 +150,6 @@ public class MainFXMLController { appLoader.loadAndCacheFxml("MyGarden.fxml"); appLoader.loadAndCacheFxml("MySchedule.fxml"); appLoader.loadAndCacheFxml("Plants.fxml"); - appLoader.loadAndCacheFxml("Tutorial.fxml"); } private void styleChangeButton(Button button) { @@ -153,12 +170,14 @@ public class MainFXMLController { } catch (IOException e) { LOG.log(Level.SEVERE, "Failed to load FXML-Pane!", e); } + mainPane.getScene().getWindow().setOnCloseRequest(this::closeWindowHandler); setIconToButton(home_button, "homeIcon.png"); setIconToButton(settings_button, "settingsIcon.png"); - Settings.getInstance().getShowTutorialProperty().addListener((observable, oldValue, newValue) -> { - tutorial_button.setVisible(newValue); - }); - tutorial_button.setVisible(Settings.getInstance().getShowTutorial()); + tutorial_button.visibleProperty().bind(Settings.getInstance().getShowTutorialProperty()); + } + + private void closeWindowHandler(WindowEvent windowEvent) { + tutorialModal.close(); } /** @@ -173,7 +192,4 @@ public class MainFXMLController { imageView.setPreserveRatio(true); button.setGraphic(imageView); } - - } - diff --git a/src/main/java/ch/zhaw/gartenverwaltung/TutorialController.java b/src/main/java/ch/zhaw/gartenverwaltung/TutorialController.java index aa02930..a1de10b 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/TutorialController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/TutorialController.java @@ -1,6 +1,61 @@ package ch.zhaw.gartenverwaltung; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.StackPane; +import javafx.stage.Stage; + public class TutorialController { + @FXML + public Button previousPageButton; + @FXML + public Button nextPageButton; + @FXML + public StackPane tourPages; + public ImageView imgAddNewPlant; + public ImageView imgTaskList; + public ImageView imgSelectDate; + + private int page = 0; + + @FXML + public void initialize() { + switchViews(); + setButtonAbilities(); + + Image placeholder = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png"))); + imgAddNewPlant.setImage(placeholder); + imgSelectDate.setImage(placeholder); + imgTaskList.setImage(placeholder); + } + + public void viewNextPage() { + page++; + switchViews(); + setButtonAbilities(); + } + public void viewPreviousPage() { + page--; + switchViews(); + setButtonAbilities(); + } + + private void setButtonAbilities() { + previousPageButton.setDisable(page <= 0); + nextPageButton.setDisable(page >= tourPages.getChildren().size() - 1); + } + + private void switchViews() { + tourPages.getChildren().forEach(node -> node.setOpacity(0)); + tourPages.getChildren().get(page).setOpacity(1); + } + + public void closeTutorial() { + Stage root = (Stage) tourPages.getScene().getWindow(); + root.close(); + } } diff --git a/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml b/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml index ddca3e3..74a6e34 100644 --- a/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml +++ b/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml @@ -12,7 +12,7 @@