Compare commits

..

No commits in common. "b70a758099760321c8d607af10ed85041d5998fe" and "86a9eeaf2ed714897354e04a1cab6e3eaa23a656" have entirely different histories.

8 changed files with 95 additions and 108 deletions

View File

@ -93,27 +93,23 @@ public class CropDetailController {
} }
public void setPlantFromCrop(Crop crop) throws PlantNotFoundException { public void setPlantFromCrop(Crop crop) throws HardinessZoneNotSetException, IOException, PlantNotFoundException {
this.crop = crop; this.crop = crop;
try { Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId())
Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()) .orElseThrow(PlantNotFoundException::new);
.orElseThrow(PlantNotFoundException::new);
cropName_label.setText(plant.name()); cropName_label.setText(plant.name());
description_label.setText(plant.description()); description_label.setText(plant.description());
light_label.setText(String.valueOf(plant.light())); light_label.setText(String.valueOf(plant.light()));
soil_label.setText(plant.soil()); soil_label.setText(plant.soil());
spacing_label.setText(plant.spacing()); spacing_label.setText(plant.spacing());
if (plant.image() != null) { if (plant.image() != null) {
imageView.setImage(plant.image()); 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) { private void createTaskLists(Crop crop) {

View File

@ -90,12 +90,10 @@ public class MyGardenController {
Label label = new Label(plant.name()); Label label = new Label(plant.name());
label.setMaxWidth(2000); label.setMaxWidth(2000);
HBox.setHgrow(label, Priority.ALWAYS); HBox.setHgrow(label, Priority.ALWAYS);
Button details = new Button("Details"); Button details = new Button("Details");
Button delete = new Button("delete"); Button delete = new Button("delete");
details.setOnAction(getGoToCropDetailEvent(crop)); details.setOnAction(getGoToCropDetailEvent(crop));
delete.setOnAction(getDeleteCropEvent(crop)); delete.setOnAction(getDeleteCropEvent(crop));
hBox.getChildren().addAll(imageView, label, details, delete); hBox.getChildren().addAll(imageView, label, details, delete);
return hBox; return hBox;
} }
@ -110,7 +108,7 @@ public class MyGardenController {
stage.initModality(Modality.APPLICATION_MODAL); stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(true); stage.setResizable(true);
stage.showAndWait(); stage.showAndWait();
} catch (IOException | PlantNotFoundException e) { } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) {
// TODO: show error alert // TODO: show error alert
LOG.log(Level.SEVERE, "Could not load plant details.", e); LOG.log(Level.SEVERE, "Could not load plant details.", e);
} }

View File

@ -9,6 +9,9 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.types.Crop; import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task; 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.fxml.FXML;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ListCell; import javafx.scene.control.ListCell;
@ -34,6 +37,8 @@ public class MyScheduleController {
@Inject @Inject
private PlantList plantList; private PlantList plantList;
private final ListProperty<Crop> cropListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
@FXML @FXML
private Label day1_label; private Label day1_label;
@ -85,8 +90,15 @@ public class MyScheduleController {
@AfterInject @AfterInject
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void init() { public void init() {
List<Crop> cropList;
try {
cropList = garden.getCrops();
cropListProperty.addAll(cropList);
} catch (IOException e) {
e.printStackTrace();
}
setCellFactoryListView(); setCellFactoryListView();
scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops()); scheduledPlants_listview.itemsProperty().bind(cropListProperty);
lookForSelectedListEntries(); lookForSelectedListEntries();
setDayLabels(); setDayLabels();
information_label.setText(""); information_label.setText("");

View File

@ -21,6 +21,7 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
@ -73,6 +74,7 @@ public class PlantsController {
*/ */
@FXML @FXML
void selectSowDate() throws IOException { void selectSowDate() throws IOException {
Stage stage = new Stage();
Dialog<LocalDate> dateSelection = new Dialog<>(); Dialog<LocalDate> dateSelection = new Dialog<>();
dateSelection.setTitle("Select Date"); dateSelection.setTitle("Select Date");
dateSelection.setHeaderText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name())); dateSelection.setHeaderText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name()));
@ -83,21 +85,22 @@ public class PlantsController {
ButtonType sowButton = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE); ButtonType sowButton = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
dialogPane.getButtonTypes().addAll(sowButton, ButtonType.CANCEL); dialogPane.getButtonTypes().addAll(sowButton, ButtonType.CANCEL);
if (appLoader.loadPaneToDialog("SelectSowDay.fxml", dialogPane) instanceof SelectSowDayController controller) { if (appLoader.loadSceneToStage("SelectSowDay.fxml", stage) instanceof SelectSowDayController controller) {
controller.initSaveButton((Button) dialogPane.lookupButton(sowButton)); controller.initSaveButton((Button) dialogPane.lookupButton(sowButton));
controller.setSelectedPlant(selectedPlant); controller.setSelectedPlant(selectedPlant);
dateSelection.setResultConverter(button -> button.equals(sowButton) ? controller.retrieveResult() : null); dateSelection.setResultConverter(button -> button.equals(sowButton) ? controller.retrieveResult() : null);
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"));
});
} }
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"));
});
} }
/** /**

View File

@ -7,6 +7,7 @@ import javafx.scene.control.*;
import javafx.util.Callback; import javafx.util.Callback;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List;
public class SelectSowDayController { public class SelectSowDayController {
private Plant selectedPlant; private Plant selectedPlant;
@ -16,15 +17,12 @@ public class SelectSowDayController {
@FXML @FXML
private RadioButton harvest_radio; private RadioButton harvest_radio;
@FXML
private RadioButton sow_radio;
@FXML
public ToggleGroup phase_group;
public LocalDate retrieveResult() { public LocalDate retrieveResult() {
LocalDate sowDate = datepicker.getValue(); LocalDate sowDate = datepicker.getValue();
if (harvest_radio.isSelected()) { if (harvest_radio.isSelected()) {
sowDate = selectedPlant.sowDateFromHarvestDate(sowDate); //ToDo method to get current lifecycle group in plant
sowDate = selectedPlant.sowDateFromHarvestDate(datepicker.getValue(), 0);
} }
return sowDate; return sowDate;
} }
@ -48,9 +46,6 @@ public class SelectSowDayController {
Callback<DatePicker, DateCell> dayCellFactory = getDayCellFactory(); Callback<DatePicker, DateCell> dayCellFactory = getDayCellFactory();
datepicker.setDayCellFactory(dayCellFactory); datepicker.setDayCellFactory(dayCellFactory);
datepicker.setEditable(false); datepicker.setEditable(false);
sow_radio.setUserData(GrowthPhaseType.SOW);
harvest_radio.setUserData(GrowthPhaseType.HARVEST);
} }
public void initSaveButton(Button saveButton) { public void initSaveButton(Button saveButton) {
@ -66,28 +61,35 @@ public class SelectSowDayController {
/** /**
* date picker disable/enable dates according to selected plant: sow or harvest day * date picker disable/enable dates according to selected plant: sow or harvest day
*
* @return cellFactory of datePicker * @return cellFactory of datePicker
*/ */
private Callback<DatePicker, DateCell> getDayCellFactory() { private Callback<DatePicker, DateCell> getDayCellFactory() {
return (datePicker) -> new DateCell() { return (datePicker) -> new DateCell() {
private final LocalDate today = LocalDate.now();
@Override @Override
public void updateItem(LocalDate item, boolean empty) { public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
setDisable(true); setDisable(true);
setStyle("-fx-background-color: #ffc0cb;"); setStyle("-fx-background-color: #ffc0cb;");
List<LocalDate> dates;
if (item.compareTo(today) > 0 && (!harvest_radio.isSelected() || selectedPlant.sowDateFromHarvestDate(item).compareTo(today) >= 0)) { LocalDate today = LocalDate.now();
GrowthPhaseType selectedPhase = (GrowthPhaseType) phase_group.getSelectedToggle().getUserData(); if (harvest_radio.isSelected()) {
dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.HARVEST);
if (selectedPlant.isDateInPhase(item, selectedPhase)) { } else {
dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.SOW);
}
for (LocalDate date : dates) {
if (item.getMonth() == date.getMonth()
&& item.getDayOfMonth() == date.getDayOfMonth()
&& item.compareTo(today) > 0) {
setDisable(false); setDisable(false);
setStyle("-fx-background-color: #32CD32;"); setStyle("-fx-background-color: #32CD32;");
} }
} }
if ((harvest_radio.isSelected() && selectedPlant.sowDateFromHarvestDate(item, 0).compareTo(today) < 0)) {
setDisable(true);
setStyle("-fx-background-color: #ffc0cb;");
}
} }
}; };
} }

View File

@ -12,7 +12,6 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.models.PlantListModel; import ch.zhaw.gartenverwaltung.models.PlantListModel;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.DialogPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -79,24 +78,6 @@ public class AppLoader {
return controller; 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. * Loads the given fxml-file from resources and caches the pane.
* Performs dependency-injection. * Performs dependency-injection.

View File

@ -3,7 +3,7 @@ package ch.zhaw.gartenverwaltung.types;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.MonthDay; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -42,10 +42,11 @@ public record Plant(
/** /**
* get sow date from given harvest day from lifecycle group * get sow date from given harvest day from lifecycle group
* @param harvestDate date of the harvest * @param harvestDate date of the harvest
* @param group lifecycle group
* @return LocaleDate of sow date * @return LocaleDate of sow date
*/ */
public LocalDate sowDateFromHarvestDate(LocalDate harvestDate) { public LocalDate sowDateFromHarvestDate(LocalDate harvestDate, int group) {
return harvestDate.minusDays(timeToHarvest(lifecycleGroupFromHarvestDate(harvestDate))); return harvestDate.minusDays(timeToHarvest(group));
} }
/** /**
@ -68,43 +69,37 @@ public record Plant(
return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear)); return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear));
} }
public int lifecycleGroupFromHarvestDate(LocalDate harvestDate) { /**
return lifecycle.stream() * filter out the given growthPhase out of the lifecycle
.filter(growthPhase -> growthPhase.type().equals(GrowthPhaseType.HARVEST) && * create list of dates for this growthPhase and return it
dateInRange(harvestDate, growthPhase.startDate(), growthPhase.endDate())) * @param growthPhase the wanted growthPhase
.map(GrowthPhase::group) * @return a list of dates of the current year
.findFirst() */
.orElse(0); public List<LocalDate> getDateListOfGrowthPhase(GrowthPhaseType growthPhase) {
List<LocalDate> dates = new LinkedList<>();
for (GrowthPhase growth : lifecycle) {
if (growth.type().equals(growthPhase)) {
dates = addDatesFromMonthDay(growth);
}
}
return dates;
} }
/** /**
* Checks if the given {@link LocalDate} is within a {@link GrowthPhase} of the given {@link GrowthPhaseType} * transform monthDay value of the given growthPhase to localDate
* * return a list of dates from start to end of growth phase
* @param date The date to check. * @param growthPhase the current growthPhase
* @param phase The {@link GrowthPhaseType} to match against * @return a list of dates of the current year
* @return Whether the date is within the given {@link GrowthPhaseType}
*/ */
public boolean isDateInPhase(LocalDate date, GrowthPhaseType phase) { private List<LocalDate> addDatesFromMonthDay(GrowthPhase growthPhase) {
return lifecycle.stream() List<LocalDate> dates = new LinkedList<>();
.filter(growthPhase -> growthPhase.type().equals(phase)) LocalDate today = LocalDate.now();
.anyMatch(growthPhase -> dateInRange(date, growthPhase.startDate(), growthPhase.endDate())); LocalDate start = growthPhase.startDate().atYear(today.getYear());
} LocalDate end = growthPhase.endDate().atYear(today.getYear());
while (!start.isAfter(end)) {
/** dates.add(start);
* Checks if the given {@link LocalDate} is within the given {@link MonthDay} range. start = start.plusDays(1);
* (regardless of year) }
* return dates;
* @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()));
} }
} }

View File

@ -18,15 +18,15 @@
<children> <children>
<VBox alignment="CENTER_LEFT" prefHeight="88.0" prefWidth="155.0"> <VBox alignment="CENTER_LEFT" prefHeight="88.0" prefWidth="155.0">
<children> <children>
<RadioButton fx:id="sow_radio" mnemonicParsing="false" selected="true" text="Sow" toggleGroup="$phase_group"> <RadioButton fx:id="sow_radio" mnemonicParsing="false" selected="true" text="Sow" toggleGroup="$group">
<VBox.margin> <VBox.margin>
<Insets bottom="10.0" /> <Insets bottom="10.0" />
</VBox.margin> </VBox.margin>
<toggleGroup> <toggleGroup>
<ToggleGroup fx:id="phase_group" /> <ToggleGroup fx:id="group" />
</toggleGroup> </toggleGroup>
</RadioButton> </RadioButton>
<RadioButton fx:id="harvest_radio" mnemonicParsing="false" text="Harvest" toggleGroup="$phase_group" /> <RadioButton fx:id="harvest_radio" mnemonicParsing="false" text="Harvest" toggleGroup="$group" />
</children> </children>
<HBox.margin> <HBox.margin>
<Insets top="10.0" /> <Insets top="10.0" />