diff --git a/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java b/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java index bf5a7bf..7051bfa 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java @@ -93,23 +93,27 @@ public class CropDetailController { } - public void setPlantFromCrop(Crop crop) throws HardinessZoneNotSetException, IOException, PlantNotFoundException { + public void setPlantFromCrop(Crop crop) throws PlantNotFoundException { this.crop = crop; - Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()) - .orElseThrow(PlantNotFoundException::new); + try { + Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()) + .orElseThrow(PlantNotFoundException::new); - cropName_label.setText(plant.name()); - description_label.setText(plant.description()); - light_label.setText(String.valueOf(plant.light())); - soil_label.setText(plant.soil()); - spacing_label.setText(plant.spacing()); - if (plant.image() != null) { - imageView.setImage(plant.image()); + cropName_label.setText(plant.name()); + description_label.setText(plant.description()); + light_label.setText(String.valueOf(plant.light())); + soil_label.setText(plant.soil()); + spacing_label.setText(plant.spacing()); + if (plant.image() != null) { + imageView.setImage(plant.image()); + } + area_label.setText(""); + location_label.setText(""); + createTaskLists(crop); + createPestList(plant); + } catch (HardinessZoneNotSetException | IOException e) { + throw new PlantNotFoundException(); } - area_label.setText(""); - location_label.setText(""); - createTaskLists(crop); - createPestList(plant); } private void createTaskLists(Crop crop) { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java b/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java index 3568b50..e54e608 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java @@ -90,10 +90,12 @@ public class MyGardenController { Label label = new Label(plant.name()); label.setMaxWidth(2000); HBox.setHgrow(label, Priority.ALWAYS); + Button details = new Button("Details"); Button delete = new Button("delete"); details.setOnAction(getGoToCropDetailEvent(crop)); delete.setOnAction(getDeleteCropEvent(crop)); + hBox.getChildren().addAll(imageView, label, details, delete); return hBox; } @@ -108,7 +110,7 @@ public class MyGardenController { stage.initModality(Modality.APPLICATION_MODAL); stage.setResizable(true); stage.showAndWait(); - } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) { + } catch (IOException | PlantNotFoundException e) { // TODO: show error alert LOG.log(Level.SEVERE, "Could not load plant details.", e); } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java b/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java index 417722a..e895480 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java @@ -9,9 +9,6 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.types.Crop; import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Task; -import javafx.beans.property.ListProperty; -import javafx.beans.property.SimpleListProperty; -import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.control.ListCell; @@ -37,8 +34,6 @@ public class MyScheduleController { @Inject private PlantList plantList; - private final ListProperty cropListProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); - @FXML private Label day1_label; @@ -90,15 +85,8 @@ public class MyScheduleController { @AfterInject @SuppressWarnings("unused") public void init() { - List cropList; - try { - cropList = garden.getCrops(); - cropListProperty.addAll(cropList); - } catch (IOException e) { - e.printStackTrace(); - } setCellFactoryListView(); - scheduledPlants_listview.itemsProperty().bind(cropListProperty); + scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops()); lookForSelectedListEntries(); setDayLabels(); information_label.setText(""); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java b/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java index 200ccf9..8b821c1 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java @@ -21,7 +21,6 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.VBox; -import javafx.stage.Stage; import java.io.IOException; import java.time.LocalDate; @@ -74,7 +73,6 @@ public class PlantsController { */ @FXML void selectSowDate() throws IOException { - Stage stage = new Stage(); Dialog dateSelection = new Dialog<>(); dateSelection.setTitle("Select Date"); dateSelection.setHeaderText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name())); @@ -85,22 +83,21 @@ public class PlantsController { ButtonType sowButton = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE); dialogPane.getButtonTypes().addAll(sowButton, ButtonType.CANCEL); - if (appLoader.loadSceneToStage("SelectSowDay.fxml", stage) instanceof SelectSowDayController controller) { + if (appLoader.loadPaneToDialog("SelectSowDay.fxml", dialogPane) instanceof SelectSowDayController controller) { controller.initSaveButton((Button) dialogPane.lookupButton(sowButton)); controller.setSelectedPlant(selectedPlant); dateSelection.setResultConverter(button -> button.equals(sowButton) ? controller.retrieveResult() : null); - } - dialogPane.setContent(stage.getScene().getRoot()); - dateSelection.showAndWait() - .ifPresent(date -> { - try { - garden.plantAsCrop(selectedPlant, date); - } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) { - LOG.log(Level.SEVERE, "Couldn't save Crop", e); - } - plantsRoot.fireEvent(new ChangeViewEvent(ChangeViewEvent.CHANGE_MAIN_VIEW, "MyGarden.fxml")); - }); + dateSelection.showAndWait() + .ifPresent(date -> { + try { + garden.plantAsCrop(selectedPlant, date); + } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) { + LOG.log(Level.SEVERE, "Couldn't save Crop", e); + } + plantsRoot.fireEvent(new ChangeViewEvent(ChangeViewEvent.CHANGE_MAIN_VIEW, "MyGarden.fxml")); + }); + } } /** diff --git a/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java b/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java index 67338be..e3722fc 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java @@ -7,7 +7,6 @@ import javafx.scene.control.*; import javafx.util.Callback; import java.time.LocalDate; -import java.util.List; public class SelectSowDayController { private Plant selectedPlant; @@ -17,12 +16,15 @@ public class SelectSowDayController { @FXML private RadioButton harvest_radio; + @FXML + private RadioButton sow_radio; + @FXML + public ToggleGroup phase_group; public LocalDate retrieveResult() { LocalDate sowDate = datepicker.getValue(); if (harvest_radio.isSelected()) { - //ToDo method to get current lifecycle group in plant - sowDate = selectedPlant.sowDateFromHarvestDate(datepicker.getValue(), 0); + sowDate = selectedPlant.sowDateFromHarvestDate(sowDate); } return sowDate; } @@ -46,6 +48,9 @@ public class SelectSowDayController { Callback dayCellFactory = getDayCellFactory(); datepicker.setDayCellFactory(dayCellFactory); datepicker.setEditable(false); + + sow_radio.setUserData(GrowthPhaseType.SOW); + harvest_radio.setUserData(GrowthPhaseType.HARVEST); } public void initSaveButton(Button saveButton) { @@ -61,35 +66,28 @@ public class SelectSowDayController { /** * date picker disable/enable dates according to selected plant: sow or harvest day + * * @return cellFactory of datePicker */ private Callback getDayCellFactory() { return (datePicker) -> new DateCell() { + private final LocalDate today = LocalDate.now(); + @Override public void updateItem(LocalDate item, boolean empty) { super.updateItem(item, empty); setDisable(true); setStyle("-fx-background-color: #ffc0cb;"); - List dates; - LocalDate today = LocalDate.now(); - if (harvest_radio.isSelected()) { - dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.HARVEST); - } else { - dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.SOW); - } - for (LocalDate date : dates) { - if (item.getMonth() == date.getMonth() - && item.getDayOfMonth() == date.getDayOfMonth() - && item.compareTo(today) > 0) { + + if (item.compareTo(today) > 0 && (!harvest_radio.isSelected() || selectedPlant.sowDateFromHarvestDate(item).compareTo(today) >= 0)) { + GrowthPhaseType selectedPhase = (GrowthPhaseType) phase_group.getSelectedToggle().getUserData(); + + if (selectedPlant.isDateInPhase(item, selectedPhase)) { setDisable(false); setStyle("-fx-background-color: #32CD32;"); } } - if ((harvest_radio.isSelected() && selectedPlant.sowDateFromHarvestDate(item, 0).compareTo(today) < 0)) { - setDisable(true); - setStyle("-fx-background-color: #ffc0cb;"); - } } }; } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java index f55f6d5..59a4f7d 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java @@ -12,6 +12,7 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.models.PlantListModel; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; +import javafx.scene.control.DialogPane; import javafx.scene.layout.Pane; import javafx.stage.Stage; @@ -78,6 +79,24 @@ public class AppLoader { return controller; } + /** + * Loads the given fxml-file from resources (no caching) and appendeds it's + * contents to the given {@link DialogPane}. + * Performs dependency-injection. + * + * @param fxmlFile The file name to be loaded + * @param appendee The {@link DialogPane} to which the FXML contents are to be appended. + * @return The controller of the loaded scene. + * @throws IOException if the file could not be loaded + */ + public Object loadPaneToDialog(String fxmlFile, DialogPane appendee) throws IOException { + FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); + appendee.setContent(loader.load()); + Object controller = loader.getController(); + annotationInject(controller); + return controller; + } + /** * Loads the given fxml-file from resources and caches the pane. * Performs dependency-injection. diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java index 9cb3d08..1cf6466 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java @@ -3,7 +3,7 @@ package ch.zhaw.gartenverwaltung.types; import javafx.scene.image.Image; import java.time.LocalDate; -import java.util.LinkedList; +import java.time.MonthDay; import java.util.List; import java.util.stream.Collectors; @@ -42,11 +42,10 @@ public record Plant( /** * get sow date from given harvest day from lifecycle group * @param harvestDate date of the harvest - * @param group lifecycle group * @return LocaleDate of sow date */ - public LocalDate sowDateFromHarvestDate(LocalDate harvestDate, int group) { - return harvestDate.minusDays(timeToHarvest(group)); + public LocalDate sowDateFromHarvestDate(LocalDate harvestDate) { + return harvestDate.minusDays(timeToHarvest(lifecycleGroupFromHarvestDate(harvestDate))); } /** @@ -69,37 +68,43 @@ public record Plant( return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear)); } - /** - * filter out the given growthPhase out of the lifecycle - * create list of dates for this growthPhase and return it - * @param growthPhase the wanted growthPhase - * @return a list of dates of the current year - */ - public List getDateListOfGrowthPhase(GrowthPhaseType growthPhase) { - List dates = new LinkedList<>(); - for (GrowthPhase growth : lifecycle) { - if (growth.type().equals(growthPhase)) { - dates = addDatesFromMonthDay(growth); - } - } - return dates; + public int lifecycleGroupFromHarvestDate(LocalDate harvestDate) { + return lifecycle.stream() + .filter(growthPhase -> growthPhase.type().equals(GrowthPhaseType.HARVEST) && + dateInRange(harvestDate, growthPhase.startDate(), growthPhase.endDate())) + .map(GrowthPhase::group) + .findFirst() + .orElse(0); } /** - * transform monthDay value of the given growthPhase to localDate - * return a list of dates from start to end of growth phase - * @param growthPhase the current growthPhase - * @return a list of dates of the current year + * Checks if the given {@link LocalDate} is within a {@link GrowthPhase} of the given {@link GrowthPhaseType} + * + * @param date The date to check. + * @param phase The {@link GrowthPhaseType} to match against + * @return Whether the date is within the given {@link GrowthPhaseType} */ - private List addDatesFromMonthDay(GrowthPhase growthPhase) { - List dates = new LinkedList<>(); - LocalDate today = LocalDate.now(); - LocalDate start = growthPhase.startDate().atYear(today.getYear()); - LocalDate end = growthPhase.endDate().atYear(today.getYear()); - while (!start.isAfter(end)) { - dates.add(start); - start = start.plusDays(1); - } - return dates; + public boolean isDateInPhase(LocalDate date, GrowthPhaseType phase) { + return lifecycle.stream() + .filter(growthPhase -> growthPhase.type().equals(phase)) + .anyMatch(growthPhase -> dateInRange(date, growthPhase.startDate(), growthPhase.endDate())); + } + + /** + * Checks if the given {@link LocalDate} is within the given {@link MonthDay} range. + * (regardless of year) + * + * @param subject The date to check + * @param min The start of the date-range + * @param max The end of the date-range + * @return Whether the subject is within the range. + */ + private boolean dateInRange(LocalDate subject, MonthDay min, MonthDay max) { + return subject.getMonth().compareTo(min.getMonth()) >= 0 && + subject.getMonth().compareTo(max.getMonth()) <= 0 && + // if the day is less than the minimum day, the minimum month must not be equal + (subject.getDayOfMonth() >= min.getDayOfMonth() || !subject.getMonth().equals(min.getMonth())) && + // if the day is greater than the maximum day, the maximum month must not be equal + (subject.getDayOfMonth() <= max.getDayOfMonth() || !subject.getMonth().equals(max.getMonth())); } } diff --git a/src/main/resources/ch/zhaw/gartenverwaltung/SelectSowDay.fxml b/src/main/resources/ch/zhaw/gartenverwaltung/SelectSowDay.fxml index 75f33c3..1ebcf03 100644 --- a/src/main/resources/ch/zhaw/gartenverwaltung/SelectSowDay.fxml +++ b/src/main/resources/ch/zhaw/gartenverwaltung/SelectSowDay.fxml @@ -18,15 +18,15 @@ - + - + - +