Compare commits
	
		
			No commits in common. "main" and "tests_extended_M3" have entirely different histories.
		
	
	
		
			main
			...
			tests_exte
		
	
		
							
								
								
									
										43
									
								
								README.md
								
								
								
								
							
							
						
						| 
						 | 
					@ -1,19 +1,32 @@
 | 
				
			||||||
# GardenPlanner
 | 
					# PM3-HS22-IT21b_WIN-Team1
 | 
				
			||||||
 | 
					PM3 FivePlants Gartenverwaltung
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##	Installations- und Gebrauchsanweisung
 | 
					## Class Diagram
 | 
				
			||||||
### Vorbedingungen
 | 
					Umletino: https://www.umletino.com/umletino.html
 | 
				
			||||||
 - Das Java Runtime Environment (JRE) muss in der Version 17 auf Ihrem Computer installiert sein.
 | 
					 | 
				
			||||||
 - Das Java Development Kit (JDK) muss in der Version 17 auf Ihrem Computer installiert sein.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Installation und Starten der Applikation
 | 
					Draft File: doc/ClassDiagramDraft.uxf
 | 
				
			||||||
1. Laden sie die neuste Version der Applikation herunter. Sie finden die Applikation hier:
 | 
					 | 
				
			||||||
      https://github.zhaw.ch/schrom01/PM3-HS22-IT21b_WIN-Team1/tags
 | 
					 | 
				
			||||||
2. Extrahieren sie die heruntergeladene ZIP-Datei
 | 
					 | 
				
			||||||
3. Öffnen sie ein Kommandozeilenfenster und navigieren sie an den Speicherort der Entpack-ten Applikation.
 | 
					 | 
				
			||||||
4. Führen sie den Befehl: «./gradlew.bat run» (auf Windows) oder «./gradlew run» (auf ma-cOS und Linux) aus.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
###	Anwendung
 | 
					## Branch model
 | 
				
			||||||
Eine Bedienungsanleitung finden Sie im Dokument ["Technischer Bericht II"](doc/PM3-HS22-IT21b_WIN-Technischer_Bericht_II-Team1.pdf) im Kapitel 6.3.3.
 | 
					- production branch: `main`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Projektdokumentation
 | 
					This branch has a working version of the code.
 | 
				
			||||||
Die gesamte Projektdokumentation ist im Dokument ["Technischer Bericht II"](doc/PM3-HS22-IT21b_WIN-Technischer_Bericht_II-Team1.pdf) zu finden.
 | 
					
 | 
				
			||||||
 | 
					- development branch: `dev`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This branch should contain a running (although not necessarily working) version of the code. Working states are to be merged into the `main` branch regularly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- feature:       `feature_xy_<Milestone>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These branches contain features in active development. When the code is ready it will be merged into the `dev` branch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- bugfix:        `bugfix_xy_<Milestone>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These branches are for bugfixes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- documentation: `doc_xy_<Milestone>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These branches are for javadoc and project documentation (such as the readme, class diagrams etc.).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## User Manual
 | 
				
			||||||
 | 
					- Search Plant List: if first Char is '#': only exact match in ID.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					<diagram program="umletino" version="15.0.0"><zoom_level>10</zoom_level><element><id>UMLClass</id><coordinates><x>720</x><y>30</y><w>100</w><h>30</h></coordinates><panel_attributes>Main</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1240</x><y>250</y><w>300</w><h>140</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					PlantDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getPlantList(zone: HardinessZone): List<Plant>
 | 
				
			||||||
 | 
					+ getPlant(id: long): Optional<Plant></panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>940</x><y>580</y><w>220</w><h>40</h></coordinates><panel_attributes>TaskListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1240</x><y>10</y><w>300</w><h>180</h></coordinates><panel_attributes><<Record>>
 | 
				
			||||||
 | 
					Plant
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ id: long
 | 
				
			||||||
 | 
					+ name: String
 | 
				
			||||||
 | 
					+ description: String
 | 
				
			||||||
 | 
					+ spacing: int
 | 
				
			||||||
 | 
					+ lifecycle: List<GrowthPhase>
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ calculateStartDate(harvestDate: Date): Date
 | 
				
			||||||
 | 
					+ generateTasks()
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1210</x><y>580</y><w>210</w><h>120</h></coordinates><panel_attributes>TaskListModel
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- tasks: ListProperty<Task>
 | 
				
			||||||
 | 
					- taskDb: TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getTask(id: long): Optional<Task>
 | 
				
			||||||
 | 
					+ saveTask(task: Task)
 | 
				
			||||||
 | 
					+ removeTask(task: Task)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>590</x><y>560</y><w>250</w><h>110</h></coordinates><panel_attributes>GardenPlanModel
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- tasks: ListProperty<Task>
 | 
				
			||||||
 | 
					- gardenPlan: GardenPlan
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ savePlanting(planting: UserPlanting)
 | 
				
			||||||
 | 
					+ removePlanting(planting: UserPlanting)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>340</x><y>550</y><w>180</w><h>80</h></coordinates><panel_attributes>GardenPlanController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1660</x><y>720</y><w>490</w><h>240</h></coordinates><panel_attributes>Task
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ id: long
 | 
				
			||||||
 | 
					+ name: String {readOnly}
 | 
				
			||||||
 | 
					+ description: String {readOnly}
 | 
				
			||||||
 | 
					+ startDate: Date {readOnly}
 | 
				
			||||||
 | 
					+ isReadOnly: boolean {readOnly}
 | 
				
			||||||
 | 
					- interval: int
 | 
				
			||||||
 | 
					- endDate: Date
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ Task(name: String, description: String, startDate: String, isReadOnly: boolean): Task
 | 
				
			||||||
 | 
					+ withInterval(interval: int): Task
 | 
				
			||||||
 | 
					+ withEndDate(endDate: Date): Task
 | 
				
			||||||
 | 
					+ withId(id: long): Task
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getInterval(): Optional<int>
 | 
				
			||||||
 | 
					+ getEndDate(): Optional<Date></panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1170</x><y>760</y><w>280</w><h>140</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getTaskList(start: Date, end: Date): List<Task>
 | 
				
			||||||
 | 
					+ saveTask(Task task) throws ??Exception
 | 
				
			||||||
 | 
					+ removeTask(Task task) throws ??Exception</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>780</x><y>310</y><w>100</w><h>100</h></coordinates><panel_attributes>MainWindow</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>440</x><y>180</y><w>180</w><h>130</h></coordinates><panel_attributes>MainWindowController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1340</x><y>1070</y><w>210</w><h>70</h></coordinates><panel_attributes>NotificationService
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- taskDb: TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ tick()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1640</x><y>1210</y><w>240</w><h>140</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					WeatherProvider
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getWeatherForecast: WeatherForecast</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1620</x><y>1040</y><w>400</w><h>100</h></coordinates><panel_attributes>WeatherService
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- weatherPovider: WeatherProvider
 | 
				
			||||||
 | 
					- taskDb: TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ WeatherService(provider: WeatherProvider, taskDb: TaskDatabase)
 | 
				
			||||||
 | 
					- updateTasks()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1620</x><y>10</y><w>260</w><h>150</h></coordinates><panel_attributes><<Record>>
 | 
				
			||||||
 | 
					GrowthPhase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ startDate: Date
 | 
				
			||||||
 | 
					+ endDate: Date 
 | 
				
			||||||
 | 
					+ type: GrowthPhaseType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1530</x><y>80</y><w>110</w><h>30</h></coordinates><panel_attributes>lt=<->>>>></panel_attributes><additional_attributes>90;10;10;10</additional_attributes></element><element><id>Text</id><coordinates><x>420</x><y>0</y><w>190</w><h>70</h></coordinates><panel_attributes>Note:
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					{final, readOnly} omitted on public  data fields in <<Record>> Entities for clarity
 | 
				
			||||||
 | 
					style=wordwrap</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1440</x><y>820</y><w>240</w><h>30</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>220;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1300</x><y>690</y><w>30</w><h>90</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;70;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>600</x><y>980</y><w>210</w><h>120</h></coordinates><panel_attributes><<Record>>
 | 
				
			||||||
 | 
					UserPlanting
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ plantId: long
 | 
				
			||||||
 | 
					+ asSowing: boolean
 | 
				
			||||||
 | 
					+ startDate: Date
 | 
				
			||||||
 | 
					+ area: int</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1380</x><y>180</y><w>30</w><h>90</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;10;10;70</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1950</x><y>10</y><w>140</w><h>120</h></coordinates><panel_attributes><<Enumeration>>
 | 
				
			||||||
 | 
					GrowthPhaseType
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					SOW
 | 
				
			||||||
 | 
					PLANT
 | 
				
			||||||
 | 
					HARVEST</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1870</x><y>70</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=<->>>></panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1150</x><y>590</y><w>80</w><h>30</h></coordinates><panel_attributes>lt=<->>>></panel_attributes><additional_attributes>60;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>700</x><y>890</y><w>30</w><h>110</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;90;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>510</x><y>580</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=<->>>></panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>570</x><y>760</y><w>280</w><h>140</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					GardenPlan
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getPlantings(): List<UserPlanting>
 | 
				
			||||||
 | 
					+ addPlanting(plantId: long, startDate)
 | 
				
			||||||
 | 
					+ savePlanting(planting: UserPlanting)
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>690</x><y>660</y><w>30</w><h>120</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;100;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>60</x><y>390</y><w>180</w><h>80</h></coordinates><panel_attributes>PlantingCell
 | 
				
			||||||
 | 
					{extends ListCell<>}</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>0</x><y>540</y><w>290</w><h>80</h></coordinates><panel_attributes>PlantingCellFactory
 | 
				
			||||||
 | 
					{implements Callback<ListView<UserPlanting> >}</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>140</x><y>460</y><w>30</w><h>100</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;10;10;80</additional_attributes></element><element><id>Relation</id><coordinates><x>1750</x><y>1130</y><w>30</w><h>100</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;80;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1350</x><y>890</y><w>120</w><h>200</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;10;100;180</additional_attributes></element><element><id>Relation</id><coordinates><x>1380</x><y>890</y><w>260</w><h>220</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;10;240;200</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1090</x><y>1060</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonTaskDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1180</x><y>890</y><w>30</w><h>190</h></coordinates><panel_attributes>lt=<<-</panel_attributes><additional_attributes>10;10;10;170</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1620</x><y>310</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonPlantDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1530</x><y>320</y><w>110</w><h>30</h></coordinates><panel_attributes>lt=<<-</panel_attributes><additional_attributes>10;10;90;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>300</x><y>800</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonGardenPlan</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>490</x><y>810</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=<<-</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>280</x><y>570</y><w>80</w><h>30</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;10;60;10</additional_attributes></element><element><id>Relation</id><coordinates><x>850</x><y>400</y><w>220</w><h>200</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>200;180;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>440</x><y>400</y><w>390</w><h>170</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;150;370;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>850</x><y>120</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>760</x><y>50</y><w>90</w><h>280</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>70;260;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>610</x><y>230</y><w>190</w><h>140</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;10;170;120</additional_attributes></element><element><id>Relation</id><coordinates><x>870</x><y>170</y><w>80</w><h>210</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>60;10;10;190</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1020</x><y>290</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListModel</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1000</x><y>150</y><w>110</w><h>160</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>90;140;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1170</x><y>310</y><w>90</w><h>30</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>70;10;10;10</additional_attributes></element></diagram>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 25 KiB  | 
| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					<diagram program="umletino" version="15.0.0"><zoom_level>10</zoom_level><element><id>UMLPackage</id><coordinates><x>390</x><y>60</y><w>340</w><h>100</h></coordinates><panel_attributes>UI</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>390</x><y>180</y><w>460</w><h>120</h></coordinates><panel_attributes>Domain</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>390</x><y>330</y><w>460</w><h>120</h></coordinates><panel_attributes>Technical Services</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>90</y><w>100</w><h>60</h></coordinates><panel_attributes>Views (JFX)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>IO</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>Jackson</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>Types</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>620</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>Models</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>90</y><w>110</w><h>60</h></coordinates><panel_attributes>Controllers (JFX)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>Logging</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>620</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>JavaFX</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>730</x><y>220</y><w>110</w><h>60</h></coordinates><panel_attributes>Services</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>730</x><y>370</y><w>110</w><h>60</h></coordinates><panel_attributes>HTTP/API</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>570</x><y>150</y><w>90</w><h>70</h></coordinates><panel_attributes>lt=.>
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes>70;10;10;50</additional_attributes></element><element><id>Relation</id><coordinates><x>570</x><y>290</y><w>110</w><h>80</h></coordinates><panel_attributes>lt=.>
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes>90;10;10;60</additional_attributes></element><element><id>Relation</id><coordinates><x>340</x><y>120</y><w>350</w><h>400</h></coordinates><panel_attributes>lt=.>
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes>60;10;10;10;10;380;330;380;330;310</additional_attributes></element><element><id>Relation</id><coordinates><x>770</x><y>270</y><w>30</w><h>120</h></coordinates><panel_attributes>lt=.>
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes>10;10;10;100</additional_attributes></element><element><id>Relation</id><coordinates><x>360</x><y>250</y><w>60</w><h>180</h></coordinates><panel_attributes>lt=.>
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes>40;10;10;10;10;160;40;160</additional_attributes></element><element><id>Relation</id><coordinates><x>610</x><y>120</y><w>70</w><h>120</h></coordinates><panel_attributes>lt=.>
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes>10;10;50;10;50;100</additional_attributes></element></diagram>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 286 KiB  | 
| 
						 | 
					@ -0,0 +1,144 @@
 | 
				
			||||||
 | 
					<diagram program="umletino" version="15.0.0"><zoom_level>10</zoom_level><element><id>UMLClass</id><coordinates><x>482</x><y>360</y><w>100</w><h>30</h></coordinates><panel_attributes>Main</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1082</x><y>380</y><w>370</w><h>100</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					PlantDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getPlantList(zone: HardinessZone): List<Plant>
 | 
				
			||||||
 | 
					+ getPlantById(zone: HardinessZone id: long): Optional<Plant></panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>672</x><y>710</y><w>220</w><h>40</h></coordinates><panel_attributes>TaskListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1132</x><y>110</y><w>300</w><h>180</h></coordinates><panel_attributes><<Record>>
 | 
				
			||||||
 | 
					Plant
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ id: long
 | 
				
			||||||
 | 
					+ name: String
 | 
				
			||||||
 | 
					+ description: String
 | 
				
			||||||
 | 
					+ spacing: int
 | 
				
			||||||
 | 
					+ lifecycle: List<GrowthPhase>
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ calculateStartDate(harvestDate: Date): Date
 | 
				
			||||||
 | 
					+ generateTasks()
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>942</x><y>710</y><w>210</w><h>120</h></coordinates><panel_attributes>TaskListModel
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- tasks: ListProperty<Task>
 | 
				
			||||||
 | 
					- taskDb: TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getTask(id: long): Optional<Task>
 | 
				
			||||||
 | 
					+ saveTask(task: Task)
 | 
				
			||||||
 | 
					+ removeTask(task: Task)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>322</x><y>690</y><w>250</w><h>120</h></coordinates><panel_attributes>GardenPlanModel
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- tasks: ListProperty<Crop>
 | 
				
			||||||
 | 
					- gardenPlan: GardenPlan
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ plantAsCrop(planting: UserPlanting)
 | 
				
			||||||
 | 
					+ removePlanting(planting: UserPlanting)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>72</x><y>680</y><w>180</w><h>80</h></coordinates><panel_attributes>GardenPlanController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1362</x><y>830</y><w>490</w><h>240</h></coordinates><panel_attributes>Task
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ id: long
 | 
				
			||||||
 | 
					+ name: String {readOnly}
 | 
				
			||||||
 | 
					+ description: String {readOnly}
 | 
				
			||||||
 | 
					+ startDate: Date {readOnly}
 | 
				
			||||||
 | 
					+ isOptional: boolean {readOnly}
 | 
				
			||||||
 | 
					- interval: int
 | 
				
			||||||
 | 
					- endDate: Date
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ Task(name: String, description: String, startDate: String, isReadOnly: boolean): Task
 | 
				
			||||||
 | 
					+ withInterval(interval: int): Task
 | 
				
			||||||
 | 
					+ withEndDate(endDate: Date): Task
 | 
				
			||||||
 | 
					+ withId(id: long): Task
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getInterval(): Optional<int>
 | 
				
			||||||
 | 
					+ getEndDate(): Optional<Date></panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>902</x><y>930</y><w>280</w><h>140</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getTaskList(start: Date, end: Date): List<Task>
 | 
				
			||||||
 | 
					+ saveTask(Task task) throws ??Exception
 | 
				
			||||||
 | 
					+ removeTask(Task task) throws ??Exception</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>442</x><y>440</y><w>170</w><h>80</h></coordinates><panel_attributes>MainWindowController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>962</x><y>1310</y><w>210</w><h>70</h></coordinates><panel_attributes>NotificationService
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- taskDb: TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ tick()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1412</x><y>1310</y><w>240</w><h>90</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					WeatherProvider
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getWeatherForecast: WeatherForecast</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1392</x><y>1150</y><w>400</w><h>100</h></coordinates><panel_attributes>WeatherService
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- weatherPovider: WeatherProvider
 | 
				
			||||||
 | 
					- taskDb: TaskDatabase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ WeatherService(provider: WeatherProvider, taskDb: TaskDatabase)
 | 
				
			||||||
 | 
					- updateTasks()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1502</x><y>110</y><w>260</w><h>150</h></coordinates><panel_attributes><<Record>>
 | 
				
			||||||
 | 
					GrowthPhase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ startDate: MonthDay
 | 
				
			||||||
 | 
					+ endDate: MonthDay 
 | 
				
			||||||
 | 
					+ type: GrowthPhaseType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1422</x><y>180</y><w>100</w><h>40</h></coordinates><panel_attributes>lt=<->>>>>
 | 
				
			||||||
 | 
					m1=*
 | 
				
			||||||
 | 
					m2=1</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Text</id><coordinates><x>152</x><y>130</y><w>190</w><h>70</h></coordinates><panel_attributes>Note:
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					{final, readOnly} omitted on public  data fields in <<Record>> Entities for clarity
 | 
				
			||||||
 | 
					style=wordwrap</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1172</x><y>970</y><w>210</w><h>50</h></coordinates><panel_attributes>lt=<.
 | 
				
			||||||
 | 
					m1=*
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					returns ></panel_attributes><additional_attributes>190;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>1032</x><y>820</y><w>140</w><h>130</h></coordinates><panel_attributes>lt=<-
 | 
				
			||||||
 | 
					m1=1 external database
 | 
				
			||||||
 | 
					m2=1 internal list
 | 
				
			||||||
 | 
					accesses</panel_attributes><additional_attributes>10;110;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>322</x><y>1120</y><w>240</w><h>150</h></coordinates><panel_attributes>Crop
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					- cropId: Long
 | 
				
			||||||
 | 
					+ plantId: long {final, readOnly}
 | 
				
			||||||
 | 
					+ startDate: LocalDate {final, readOnly}
 | 
				
			||||||
 | 
					+ area: Double
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ withId(long): Crop
 | 
				
			||||||
 | 
					+ withArea(double): Crop
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getCropId(): Optional<Long></panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1262</x><y>280</y><w>70</w><h>120</h></coordinates><panel_attributes>lt=<.
 | 
				
			||||||
 | 
					m1=*
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					returns</panel_attributes><additional_attributes>10;10;10;100</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1632</x><y>290</y><w>130</w><h>100</h></coordinates><panel_attributes><<Enumeration>>
 | 
				
			||||||
 | 
					GrowthPhaseType
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					SOW
 | 
				
			||||||
 | 
					PLANT
 | 
				
			||||||
 | 
					HARVEST</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1582</x><y>250</y><w>70</w><h>120</h></coordinates><panel_attributes>lt=<->>>>
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=*</panel_attributes><additional_attributes>50;90;10;90;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>882</x><y>720</y><w>80</w><h>30</h></coordinates><panel_attributes>lt=<->>>></panel_attributes><additional_attributes>60;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>432</x><y>1020</y><w>110</w><h>120</h></coordinates><panel_attributes>lt=<.
 | 
				
			||||||
 | 
					m1=*
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					returns / saves</panel_attributes><additional_attributes>10;100;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>242</x><y>710</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=<->>>></panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>302</x><y>890</y><w>280</w><h>140</h></coordinates><panel_attributes><<Interface>>
 | 
				
			||||||
 | 
					GardenPlan
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ getPlantings(): List<UserPlanting>
 | 
				
			||||||
 | 
					+ addPlanting(plantId: long, startDate)
 | 
				
			||||||
 | 
					+ savePlanting(planting: UserPlanting)
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>422</x><y>800</y><w>80</w><h>110</h></coordinates><panel_attributes>lt=<.
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					accesses</panel_attributes><additional_attributes>10;90;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1522</x><y>1240</y><w>30</w><h>90</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;70;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1062</x><y>1060</y><w>80</w><h>270</h></coordinates><panel_attributes>lt=<-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					accesses</panel_attributes><additional_attributes>10;10;10;250</additional_attributes></element><element><id>Relation</id><coordinates><x>1142</x><y>1060</y><w>270</w><h>170</h></coordinates><panel_attributes>lt=<-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					adds Tasks</panel_attributes><additional_attributes>10;10;10;140;250;140</additional_attributes></element><element><id>UMLClass</id><coordinates><x>822</x><y>1140</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonTaskDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>912</x><y>1060</y><w>30</w><h>100</h></coordinates><panel_attributes>lt=<<-</panel_attributes><additional_attributes>10;10;10;80</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1562</x><y>430</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonPlantDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1442</x><y>440</y><w>140</w><h>30</h></coordinates><panel_attributes>lt=<<-</panel_attributes><additional_attributes>10;10;120;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>32</x><y>930</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonGardenPlan</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>222</x><y>940</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=<<-</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>582</x><y>510</y><w>220</w><h>220</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>200;200;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>172</x><y>510</y><w>340</w><h>190</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;170;320;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>582</x><y>250</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>522</x><y>380</y><w>30</w><h>80</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>10;60;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>602</x><y>300</y><w>80</w><h>210</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>60;10;10;190</additional_attributes></element><element><id>UMLClass</id><coordinates><x>732</x><y>390</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListModel</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>732</x><y>280</y><w>90</w><h>130</h></coordinates><panel_attributes>lt=<.</panel_attributes><additional_attributes>70;110;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>882</x><y>400</y><w>220</w><h>70</h></coordinates><panel_attributes>lt=<-
 | 
				
			||||||
 | 
					m1=1\nexternal\ndatabase
 | 
				
			||||||
 | 
					m2=1\ninternal\nlist
 | 
				
			||||||
 | 
					accesses ></panel_attributes><additional_attributes>200;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>582</x><y>0</y><w>190</w><h>50</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=0..n
 | 
				
			||||||
 | 
					m2=0..1
 | 
				
			||||||
 | 
					teaches to ></panel_attributes><additional_attributes>10;20;170;20</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1412</x><y>530</y><w>420</w><h>200</h></coordinates><panel_attributes>TaskTemplate
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ name: String {readOnly}
 | 
				
			||||||
 | 
					+ description: String {readOnly}
 | 
				
			||||||
 | 
					+ relativeStartDate: int {readOnly}
 | 
				
			||||||
 | 
					- interval: Integer
 | 
				
			||||||
 | 
					- relativeEndDate: Integer
 | 
				
			||||||
 | 
					- isOptional: boolean
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					+ Task(name: String, description: String, startDate: String): TaskTemplate
 | 
				
			||||||
 | 
					+ setRelativeEndDate(relativeEndDate: int)
 | 
				
			||||||
 | 
					+ setInterval(interval: Integer)
 | 
				
			||||||
 | 
					+ generateTask(realStartDate: LocalDate): Task
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1752</x><y>180</y><w>130</w><h>490</h></coordinates><panel_attributes>lt=<->>>>>
 | 
				
			||||||
 | 
					m1=*
 | 
				
			||||||
 | 
					m2=1</panel_attributes><additional_attributes>80;460;110;460;110;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1602</x><y>720</y><w>90</w><h>130</h></coordinates><panel_attributes>lt=<.
 | 
				
			||||||
 | 
					m1=*
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					generates</panel_attributes><additional_attributes>10;110;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>562</x><y>770</y><w>400</w><h>40</h></coordinates><panel_attributes>lt=<-
 | 
				
			||||||
 | 
					delegates generating Tasks</panel_attributes><additional_attributes>380;20;10;20</additional_attributes></element></diagram>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					<diagram program="umletino" version="15.0.0"><zoom_level>12</zoom_level><element><id>UMLClass</id><coordinates><x>852</x><y>372</y><w>120</w><h>72</h></coordinates><panel_attributes>Gardener
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					Name
 | 
				
			||||||
 | 
					Type</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>144</x><y>372</y><w>120</w><h>120</h></coordinates><panel_attributes>Plant
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					name
 | 
				
			||||||
 | 
					description</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>600</x><y>372</y><w>120</w><h>84</h></coordinates><panel_attributes>Garden
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					Location
 | 
				
			||||||
 | 
					hardiness zone</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>384</x><y>372</y><w>120</w><h>72</h></coordinates><panel_attributes>Bed
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					Area</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1152</x><y>624</y><w>120</w><h>36</h></coordinates><panel_attributes>Weather</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>852</x><y>816</y><w>120</w><h>36</h></coordinates><panel_attributes>Calendar</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>852</x><y>96</y><w>144</w><h>72</h></coordinates><panel_attributes>Community
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					Plant Information
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>288</x><y>636</y><w>120</w><h>72</h></coordinates><panel_attributes>Growth phase
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					duration</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>852</x><y>624</y><w>120</w><h>84</h></coordinates><panel_attributes>Gardening task
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					start date
 | 
				
			||||||
 | 
					end date
 | 
				
			||||||
 | 
					interval</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>852</x><y>156</y><w>120</w><h>240</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=0..*
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					< is part of </panel_attributes><additional_attributes>10;180;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>708</x><y>372</y><w>168</w><h>60</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					< has </panel_attributes><additional_attributes>120;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>252</x><y>372</y><w>156</w><h>60</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=0..*
 | 
				
			||||||
 | 
					< contains </panel_attributes><additional_attributes>110;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>252</x><y>444</y><w>156</w><h>216</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					has ></panel_attributes><additional_attributes>10;10;80;10;80;160</additional_attributes></element><element><id>Relation</id><coordinates><x>492</x><y>372</y><w>132</w><h>60</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					< contains </panel_attributes><additional_attributes>90;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>900</x><y>432</y><w>120</w><h>216</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					< manages </panel_attributes><additional_attributes>10;10;10;160</additional_attributes></element><element><id>Relation</id><coordinates><x>960</x><y>624</y><w>216</w><h>60</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					< manipulates</panel_attributes><additional_attributes>160;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>900</x><y>696</y><w>108</w><h>144</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=0..*
 | 
				
			||||||
 | 
					< contains</panel_attributes><additional_attributes>10;10;10;100</additional_attributes></element><element><id>Relation</id><coordinates><x>960</x><y>408</y><w>468</w><h>468</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					< informs </panel_attributes><additional_attributes>10;360;310;360;310;10;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>12</x><y>636</y><w>120</w><h>84</h></coordinates><panel_attributes>Need
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					start date
 | 
				
			||||||
 | 
					end date</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>60</x><y>432</y><w>108</w><h>228</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1..*
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					has ></panel_attributes><additional_attributes>10;170;10;10;70;10</additional_attributes></element><element><id>Relation</id><coordinates><x>60</x><y>672</y><w>816</w><h>120</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					requires ></panel_attributes><additional_attributes>660;10;520;10;520;80;10;80;10;40</additional_attributes></element><element><id>UMLClass</id><coordinates><x>456</x><y>588</y><w>120</w><h>36</h></coordinates><panel_attributes>Team
 | 
				
			||||||
 | 
					</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>564</x><y>432</y><w>312</w><h>180</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=1..*
 | 
				
			||||||
 | 
					contains of ></panel_attributes><additional_attributes>10;130;240;10</additional_attributes></element><element><id>Relation</id><coordinates><x>564</x><y>600</y><w>312</w><h>60</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=1
 | 
				
			||||||
 | 
					m2=0..*
 | 
				
			||||||
 | 
					manages ></panel_attributes><additional_attributes>10;20;240;20</additional_attributes></element><element><id>Relation</id><coordinates><x>960</x><y>156</y><w>216</w><h>240</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=0..n
 | 
				
			||||||
 | 
					m2=1..n
 | 
				
			||||||
 | 
					exchanges Informatione ></panel_attributes><additional_attributes>10;10;10;180</additional_attributes></element><element><id>Relation</id><coordinates><x>120</x><y>648</y><w>192</w><h>60</h></coordinates><panel_attributes>lt=-
 | 
				
			||||||
 | 
					m1=0..n
 | 
				
			||||||
 | 
					m2=1
 | 
				
			||||||
 | 
					< contains </panel_attributes><additional_attributes>10;20;140;20</additional_attributes></element></diagram>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 44 KiB  | 
| 
						 | 
					@ -12,7 +12,6 @@ import ch.zhaw.gartenverwaltung.types.Crop;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.types.Pest;
 | 
					import ch.zhaw.gartenverwaltung.types.Pest;
 | 
				
			||||||
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.application.Platform;
 | 
					 | 
				
			||||||
import javafx.beans.property.ListProperty;
 | 
					import javafx.beans.property.ListProperty;
 | 
				
			||||||
import javafx.beans.property.SimpleListProperty;
 | 
					import javafx.beans.property.SimpleListProperty;
 | 
				
			||||||
import javafx.collections.FXCollections;
 | 
					import javafx.collections.FXCollections;
 | 
				
			||||||
| 
						 | 
					@ -134,14 +133,8 @@ public class CropDetailController {
 | 
				
			||||||
            initializeTaskListProperty(crop);
 | 
					            initializeTaskListProperty(crop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            TaskList.TaskListObserver taskListObserver = newTaskList -> {
 | 
					            TaskList.TaskListObserver taskListObserver = newTaskList -> {
 | 
				
			||||||
                Platform.runLater(() -> {
 | 
					                taskListProperty.clear();
 | 
				
			||||||
                    taskListProperty.clear();
 | 
					                taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get()));
 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get()));
 | 
					 | 
				
			||||||
                    } catch (IOException e) {
 | 
					 | 
				
			||||||
                        e.printStackTrace();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            gardenSchedule.setTaskListObserver(taskListObserver);
 | 
					            gardenSchedule.setTaskListObserver(taskListObserver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,6 +205,7 @@ public class CropDetailController {
 | 
				
			||||||
                taskListProperty.clear();
 | 
					                taskListProperty.clear();
 | 
				
			||||||
                taskListProperty.addAll(taskList);
 | 
					                taskListProperty.addAll(taskList);
 | 
				
			||||||
            } catch (IOException e) {
 | 
					            } catch (IOException e) {
 | 
				
			||||||
 | 
					                // TODO: Alert
 | 
				
			||||||
                LOG.log(Level.SEVERE, "Could not get task list for crop", e.getCause());
 | 
					                LOG.log(Level.SEVERE, "Could not get task list for crop", e.getCause());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
| 
						 | 
					@ -420,7 +414,9 @@ public class CropDetailController {
 | 
				
			||||||
                    if (buttonType == ButtonType.OK) {
 | 
					                    if (buttonType == ButtonType.OK) {
 | 
				
			||||||
                        try {
 | 
					                        try {
 | 
				
			||||||
                            gardenSchedule.removeTask(task);
 | 
					                            gardenSchedule.removeTask(task);
 | 
				
			||||||
 | 
					                            //setTaskListProperty(this.crop);
 | 
				
			||||||
                        } catch (IOException e) {
 | 
					                        } catch (IOException e) {
 | 
				
			||||||
 | 
					                            // TODO: Show error alert
 | 
				
			||||||
                            LOG.log(Level.SEVERE, "Could not remove crop.", e);
 | 
					                            LOG.log(Level.SEVERE, "Could not remove crop.", e);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,46 +13,30 @@ import javafx.stage.Stage;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.Timer;
 | 
					import java.util.Timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Main class of the Application
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class Main extends Application {
 | 
					public class Main extends Application {
 | 
				
			||||||
    Timer backGroundTaskTimer = new Timer();
 | 
					    Timer backGroundTaskTimer = new Timer();
 | 
				
			||||||
    BackgroundTasks backgroundTasks;
 | 
					    BackgroundTasks backgroundTasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Method which is automatically called if Application is starting. It loads the scenes to stage and shows the stage.
 | 
					 | 
				
			||||||
     * It creates a new Instance of BackgroundTasks and schedules them with a Timer instance to execute them every minute.
 | 
					 | 
				
			||||||
     * @param stage Stage to show
 | 
					 | 
				
			||||||
     * @throws IOException If loading Scenes can not access the fxml Resource File
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void start(Stage stage) throws IOException {
 | 
					    public void start(Stage stage) throws IOException {
 | 
				
			||||||
        AppLoader appLoader = new AppLoader();
 | 
					        AppLoader appLoader = new AppLoader();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        backgroundTasks = new BackgroundTasks((TaskList) appLoader.getAppDependency(TaskList.class),(CropList) appLoader.getAppDependency(CropList.class), (PlantList) appLoader.getAppDependency(PlantList.class));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        appLoader.loadSceneToStage("MainFXML.fxml", stage);
 | 
					        appLoader.loadSceneToStage("MainFXML.fxml", stage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        stage.setTitle("Gartenverwaltung");
 | 
					        stage.setTitle("Gartenverwaltung");
 | 
				
			||||||
        stage.show();
 | 
					        stage.show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        backgroundTasks = new BackgroundTasks((TaskList) appLoader.getAppDependency(TaskList.class),(CropList) appLoader.getAppDependency(CropList.class), (PlantList) appLoader.getAppDependency(PlantList.class));
 | 
					 | 
				
			||||||
        backGroundTaskTimer.scheduleAtFixedRate(backgroundTasks, 0, 60000);
 | 
					        backGroundTaskTimer.scheduleAtFixedRate(backgroundTasks, 0, 60000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Method which is automatically called when application is stopped.
 | 
					 | 
				
			||||||
     * It cancels the timer to not execute the background tasks anymore.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void stop(){
 | 
					    public void stop(){
 | 
				
			||||||
        backGroundTaskTimer.cancel();
 | 
					        backGroundTaskTimer.cancel();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * The Main method launches the application
 | 
					 | 
				
			||||||
     * @param args There are no arguments needed.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static void main(String[] args) {
 | 
					    public static void main(String[] args) {
 | 
				
			||||||
        launch();
 | 
					        launch();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,7 @@ public class MainFXMLController {
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    void goToHome() {
 | 
					    void goToHome() {
 | 
				
			||||||
        showPaneAsMainView("Home.fxml");
 | 
					        showPaneAsMainView("Home.fxml");
 | 
				
			||||||
 | 
					        styleChangeButton(home_button);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -64,6 +65,7 @@ public class MainFXMLController {
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    void goToMyPlants() {
 | 
					    void goToMyPlants() {
 | 
				
			||||||
        showPaneAsMainView("MyGarden.fxml");
 | 
					        showPaneAsMainView("MyGarden.fxml");
 | 
				
			||||||
 | 
					        styleChangeButton(myGarden_button);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -72,6 +74,7 @@ public class MainFXMLController {
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    void goToMySchedule() {
 | 
					    void goToMySchedule() {
 | 
				
			||||||
        showPaneAsMainView("MySchedule.fxml");
 | 
					        showPaneAsMainView("MySchedule.fxml");
 | 
				
			||||||
 | 
					        styleChangeButton(mySchedule_button);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -157,6 +160,15 @@ public class MainFXMLController {
 | 
				
			||||||
        appLoader.loadAndCacheFxml("Plants.fxml");
 | 
					        appLoader.loadAndCacheFxml("Plants.fxml");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void styleChangeButton(Button button) {
 | 
				
			||||||
 | 
					        /*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");*/
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * loads the default FXML File
 | 
					     * loads the default FXML File
 | 
				
			||||||
     * {@inheritDoc}
 | 
					     * {@inheritDoc}
 | 
				
			||||||
| 
						 | 
					@ -167,6 +179,7 @@ public class MainFXMLController {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            preloadPanes();
 | 
					            preloadPanes();
 | 
				
			||||||
            showPaneAsMainView("MyGarden.fxml");
 | 
					            showPaneAsMainView("MyGarden.fxml");
 | 
				
			||||||
 | 
					            styleChangeButton(myGarden_button);
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            LOG.log(Level.SEVERE, "Failed to load FXML-Pane!", e);
 | 
					            LOG.log(Level.SEVERE, "Failed to load FXML-Pane!", e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,6 @@ import javafx.scene.image.ImageView;
 | 
				
			||||||
import javafx.scene.layout.AnchorPane;
 | 
					import javafx.scene.layout.AnchorPane;
 | 
				
			||||||
import javafx.scene.layout.HBox;
 | 
					import javafx.scene.layout.HBox;
 | 
				
			||||||
import javafx.scene.layout.Priority;
 | 
					import javafx.scene.layout.Priority;
 | 
				
			||||||
import javafx.scene.layout.VBox;
 | 
					 | 
				
			||||||
import javafx.stage.Modality;
 | 
					import javafx.stage.Modality;
 | 
				
			||||||
import javafx.stage.Stage;
 | 
					import javafx.stage.Stage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,6 +99,7 @@ public class MyGardenController {
 | 
				
			||||||
     * @throws IOException exception
 | 
					     * @throws IOException exception
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private HBox createHBoxForListView(Crop crop) throws HardinessZoneNotSetException, IOException {
 | 
					    private HBox createHBoxForListView(Crop crop) throws HardinessZoneNotSetException, IOException {
 | 
				
			||||||
 | 
					        //ToDo add better design
 | 
				
			||||||
        Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get();
 | 
					        Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get();
 | 
				
			||||||
        HBox hBox = new HBox(10);
 | 
					        HBox hBox = new HBox(10);
 | 
				
			||||||
        ImageView imageView = new ImageView();
 | 
					        ImageView imageView = new ImageView();
 | 
				
			||||||
| 
						 | 
					@ -112,23 +112,8 @@ public class MyGardenController {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        hBox.setMinHeight(100);
 | 
					        hBox.setMinHeight(100);
 | 
				
			||||||
        Label label = new Label(plant.name());
 | 
					        Label label = new Label(plant.name());
 | 
				
			||||||
        label.setMinWidth(100);
 | 
					        label.setMaxWidth(2000);
 | 
				
			||||||
 | 
					        HBox.setHgrow(label, Priority.ALWAYS);
 | 
				
			||||||
        VBox vbox = new VBox(10);
 | 
					 | 
				
			||||||
        HBox startDateHBox = new HBox(10);
 | 
					 | 
				
			||||||
        Label startDateDescription = new Label("Start Date:");
 | 
					 | 
				
			||||||
        startDateDescription.setMinWidth(75);
 | 
					 | 
				
			||||||
        Label startDate = new Label(crop.getStartDate().toString());
 | 
					 | 
				
			||||||
        startDateHBox.getChildren().addAll(startDateDescription, startDate);
 | 
					 | 
				
			||||||
        HBox endDateHBox = new HBox(10);
 | 
					 | 
				
			||||||
        Label endDateDescription = new Label("End Date:");
 | 
					 | 
				
			||||||
        endDateDescription.setMinWidth(75);
 | 
					 | 
				
			||||||
        Label endDate = new Label(crop.getStartDate().plusDays(plant.timeToHarvest(0)).toString());
 | 
					 | 
				
			||||||
        endDateHBox.getChildren().addAll(endDateDescription, endDate);
 | 
					 | 
				
			||||||
        vbox.getChildren().addAll(startDateHBox, endDateHBox);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        vbox.setMaxWidth(2000);
 | 
					 | 
				
			||||||
        HBox.setHgrow(vbox, Priority.ALWAYS);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Button details = new Button();
 | 
					        Button details = new Button();
 | 
				
			||||||
        Button delete = new Button();
 | 
					        Button delete = new Button();
 | 
				
			||||||
| 
						 | 
					@ -140,7 +125,7 @@ public class MyGardenController {
 | 
				
			||||||
        details.setOnAction(getGoToCropDetailEvent(crop));
 | 
					        details.setOnAction(getGoToCropDetailEvent(crop));
 | 
				
			||||||
        delete.setOnAction(getDeleteCropEvent(crop));
 | 
					        delete.setOnAction(getDeleteCropEvent(crop));
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        hBox.getChildren().addAll(imageView, label, vbox, details, delete);
 | 
					        hBox.getChildren().addAll(imageView, label, details, delete);
 | 
				
			||||||
        return hBox;
 | 
					        return hBox;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,6 +158,7 @@ public class MyGardenController {
 | 
				
			||||||
                stage.setResizable(true);
 | 
					                stage.setResizable(true);
 | 
				
			||||||
                stage.showAndWait();
 | 
					                stage.showAndWait();
 | 
				
			||||||
            } catch (IOException | PlantNotFoundException e) {
 | 
					            } catch (IOException | PlantNotFoundException e) {
 | 
				
			||||||
 | 
					                // TODO: show error alert
 | 
				
			||||||
                LOG.log(Level.SEVERE, "Could not load plant details.", e);
 | 
					                LOG.log(Level.SEVERE, "Could not load plant details.", e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
| 
						 | 
					@ -218,6 +204,7 @@ public class MyGardenController {
 | 
				
			||||||
                        try {
 | 
					                        try {
 | 
				
			||||||
                            garden.removeCrop(crop);
 | 
					                            garden.removeCrop(crop);
 | 
				
			||||||
                        } catch (IOException e) {
 | 
					                        } catch (IOException e) {
 | 
				
			||||||
 | 
					                            // TODO: Show error alert
 | 
				
			||||||
                            LOG.log(Level.SEVERE, "Could not remove crop.", e);
 | 
					                            LOG.log(Level.SEVERE, "Could not remove crop.", e);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,15 +3,15 @@ package ch.zhaw.gartenverwaltung;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
 | 
					import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.bootstrap.Inject;
 | 
					import ch.zhaw.gartenverwaltung.bootstrap.Inject;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.io.PlantList;
 | 
					import ch.zhaw.gartenverwaltung.io.PlantList;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.io.TaskList;
 | 
					 | 
				
			||||||
import ch.zhaw.gartenverwaltung.models.Garden;
 | 
					import ch.zhaw.gartenverwaltung.models.Garden;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
 | 
					import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.models.GardenSchedule;
 | 
					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.application.Platform;
 | 
					 | 
				
			||||||
import javafx.beans.property.ListProperty;
 | 
					import javafx.beans.property.ListProperty;
 | 
				
			||||||
 | 
					import javafx.beans.property.SimpleListProperty;
 | 
				
			||||||
 | 
					import javafx.collections.FXCollections;
 | 
				
			||||||
import javafx.event.ActionEvent;
 | 
					import javafx.event.ActionEvent;
 | 
				
			||||||
import javafx.event.EventHandler;
 | 
					import javafx.event.EventHandler;
 | 
				
			||||||
import javafx.fxml.FXML;
 | 
					import javafx.fxml.FXML;
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,6 @@ import javafx.scene.layout.VBox;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.time.LocalDate;
 | 
					import java.time.LocalDate;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.Level;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,15 +51,9 @@ public class MyScheduleController {
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    private ListView<Crop> scheduledPlants_listview;
 | 
					    private ListView<Crop> scheduledPlants_listview;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @FXML
 | 
					 | 
				
			||||||
    private void showAllTasks(ActionEvent actionEvent) throws IOException {
 | 
					 | 
				
			||||||
        gardenSchedule.getTasksUpcomingWeek();
 | 
					 | 
				
			||||||
        scheduledPlants_listview.getSelectionModel().clearSelection();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @AfterInject
 | 
					    @AfterInject
 | 
				
			||||||
    @SuppressWarnings("unused")
 | 
					    @SuppressWarnings("unused")
 | 
				
			||||||
    public void init() throws IOException {
 | 
					    public void init() {
 | 
				
			||||||
        setCellFactoryCropListView();
 | 
					        setCellFactoryCropListView();
 | 
				
			||||||
        setCellFactoryTaskListView();
 | 
					        setCellFactoryTaskListView();
 | 
				
			||||||
        scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops());
 | 
					        scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops());
 | 
				
			||||||
| 
						 | 
					@ -68,19 +61,6 @@ public class MyScheduleController {
 | 
				
			||||||
        week_listView.itemsProperty().bind(taskListProperty);
 | 
					        week_listView.itemsProperty().bind(taskListProperty);
 | 
				
			||||||
        lookForSelectedListEntries();
 | 
					        lookForSelectedListEntries();
 | 
				
			||||||
        information_label.setText("");
 | 
					        information_label.setText("");
 | 
				
			||||||
 | 
					 | 
				
			||||||
        gardenSchedule.getTasksUpcomingWeek();
 | 
					 | 
				
			||||||
        TaskList.TaskListObserver taskListObserver = newTaskList -> {
 | 
					 | 
				
			||||||
            Platform.runLater(() -> {
 | 
					 | 
				
			||||||
                try {
 | 
					 | 
				
			||||||
                    gardenSchedule.getTasksUpcomingWeek();
 | 
					 | 
				
			||||||
                    scheduledPlants_listview.getSelectionModel().clearSelection();
 | 
					 | 
				
			||||||
                } catch (IOException e) {
 | 
					 | 
				
			||||||
                    throw new RuntimeException(e);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        gardenSchedule.setTaskListObserver(taskListObserver);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -101,8 +81,6 @@ public class MyScheduleController {
 | 
				
			||||||
     * set cellFactory for the crops.
 | 
					     * set cellFactory for the crops.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private void setCellFactoryCropListView() {
 | 
					    private void setCellFactoryCropListView() {
 | 
				
			||||||
        MultipleSelectionModel<Crop> selectionModel = scheduledPlants_listview.getSelectionModel();
 | 
					 | 
				
			||||||
        selectionModel.setSelectionMode(SelectionMode.MULTIPLE);
 | 
					 | 
				
			||||||
        scheduledPlants_listview.setCellFactory(param -> new ListCell<>() {
 | 
					        scheduledPlants_listview.setCellFactory(param -> new ListCell<>() {
 | 
				
			||||||
            @Override
 | 
					            @Override
 | 
				
			||||||
            protected void updateItem(Crop crop, boolean empty) {
 | 
					            protected void updateItem(Crop crop, boolean empty) {
 | 
				
			||||||
| 
						 | 
					@ -155,6 +133,8 @@ public class MyScheduleController {
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            gardenSchedule.getTasksUpcomingWeek();
 | 
					            gardenSchedule.getTasksUpcomingWeek();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        //taskListProperty.clear();
 | 
				
			||||||
 | 
					        //taskListProperty.addAll(taskLists);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -209,12 +189,6 @@ public class MyScheduleController {
 | 
				
			||||||
        alert.setHeaderText("Are you sure you have completed this task?");
 | 
					        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.");
 | 
					        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()
 | 
					        alert.showAndWait()
 | 
				
			||||||
                .ifPresent(buttonType -> {
 | 
					                .ifPresent(buttonType -> {
 | 
				
			||||||
                    if (buttonType == ButtonType.OK) {
 | 
					                    if (buttonType == ButtonType.OK) {
 | 
				
			||||||
| 
						 | 
					@ -228,4 +202,5 @@ public class MyScheduleController {
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,58 +6,21 @@ import javafx.beans.property.BooleanProperty;
 | 
				
			||||||
import javafx.beans.property.SimpleBooleanProperty;
 | 
					import javafx.beans.property.SimpleBooleanProperty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Singleton Class to store default Settings and User Settings
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class Settings {
 | 
					public class Settings {
 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
     * The Class instance to use everywhere
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private static final Settings instance;
 | 
					    private static final Settings instance;
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * The current Hardiness zone initialized as default value Zone_8A
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private HardinessZone currentHardinessZone = HardinessZone.ZONE_8A;
 | 
					    private HardinessZone currentHardinessZone = HardinessZone.ZONE_8A;
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Setting to show or hide the Tutorial in Main Menu
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private final BooleanProperty showTutorial = new SimpleBooleanProperty(false);
 | 
					    private final BooleanProperty showTutorial = new SimpleBooleanProperty(false);
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * The SMTP Credentials which are used to send E-Mail Notifications
 | 
					 | 
				
			||||||
     * The following Google Account is created for Testing:
 | 
					 | 
				
			||||||
     * E-Mail Address: pm3.hs22.it21b.win.team1@gmail.com
 | 
					 | 
				
			||||||
     * Account Password: Gartenverwaltung.PM3.2022
 | 
					 | 
				
			||||||
     * SMTP Password: bisefhhjtrrhtoqr
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private SmtpCredentials smtpCredentials = new SmtpCredentials("imap.gmail.com", "587", "pm3.hs22.it21b.win.team1@gmail.com", "pm3.hs22.it21b.win.team1@gmail.com", "bisefhhjtrrhtoqr", true);
 | 
					    private SmtpCredentials smtpCredentials = new SmtpCredentials("imap.gmail.com", "587", "pm3.hs22.it21b.win.team1@gmail.com", "pm3.hs22.it21b.win.team1@gmail.com", "bisefhhjtrrhtoqr", true);
 | 
				
			||||||
    /**
 | 
					    // Gmail Address: pm3.hs22.it21b.win.team1@gmail.com
 | 
				
			||||||
     * List of Receivers for E-Mailnotifications. Multiple E-Mailadresses can be separated by ";"
 | 
					    // Gmail Passwort: Gartenverwaltung.PM3.2022
 | 
				
			||||||
     * Following Public E-mail address  was used for Testing: pm3.hs22.it21b.win.team1@mailinator.com
 | 
					    // E-Mail Inbox: https://www.mailinator.com/v4/public/inboxes.jsp?to=pm3.hs22.it21b.win.team1
 | 
				
			||||||
     * The E-Mail inbox of this address can be found here: https://www.mailinator.com/v4/public/inboxes.jsp?to=pm3.hs22.it21b.win.team1
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private String mailNotificationReceivers = "pm3.hs22.it21b.win.team1@mailinator.com";
 | 
					    private String mailNotificationReceivers = "pm3.hs22.it21b.win.team1@mailinator.com";
 | 
				
			||||||
    /**
 | 
					    private String mailNotificationSubjectTemplate = "Task %s is due!"; // {0} = Task Name
 | 
				
			||||||
     * String Template to create E-Mail Subject for Notifications
 | 
					    private String mailNotificationTextTemplate = "Dear user\nYour gardentask %s for plant %s is due at %tF. Don't forget to confirm in your application if the task is done.\nTask description:\n%s"; // {0} = Task Name, {1} = plantname, {2} = nextExecution, {3} = Task description
 | 
				
			||||||
     * Variables: Task Name
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private String mailNotificationSubjectTemplate = "Task %s is due!";
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * String Template to create E-Mail Text for Notifications
 | 
					 | 
				
			||||||
     * Variables: Task Name, plant Name, nextExecution, Task description
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private String mailNotificationTextTemplate = "Dear user\nYour gardentask %s for plant %s is due at %tF. Don't forget to confirm in your application if the task is done.\nTask description:\n%s";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Location of the garden can be set by user (Used for Weather Service)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private String location = "";
 | 
					    private String location = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
      Create Instance of Settings
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static {
 | 
					    static {
 | 
				
			||||||
        instance = new Settings();
 | 
					        instance = new Settings();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -66,21 +29,14 @@ public class Settings {
 | 
				
			||||||
        return Settings.instance;
 | 
					        return Settings.instance;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Private constructor to prevent Classes from creating more instances
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private Settings() {}
 | 
					    private Settings() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public HardinessZone getCurrentHardinessZone() {
 | 
					    public HardinessZone getCurrentHardinessZone() {
 | 
				
			||||||
        return currentHardinessZone;
 | 
					        return currentHardinessZone;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Method to set the current Hardiness Zone. If no Hardiness Zone is given the default zone (ZONE_8A) will be used.
 | 
					 | 
				
			||||||
     * @param currentHardinessZone the new Hardiness Zone
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public void setCurrentHardinessZone(HardinessZone currentHardinessZone) {
 | 
					    public void setCurrentHardinessZone(HardinessZone currentHardinessZone) {
 | 
				
			||||||
        this.currentHardinessZone = Objects.requireNonNullElse(currentHardinessZone, HardinessZone.ZONE_8A);
 | 
					        this.currentHardinessZone = currentHardinessZone;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setShowTutorial (boolean showTutorial) {
 | 
					    public void setShowTutorial (boolean showTutorial) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,6 @@ import javafx.scene.image.Image;
 | 
				
			||||||
import javafx.scene.image.ImageView;
 | 
					import javafx.scene.image.ImageView;
 | 
				
			||||||
import javafx.scene.layout.StackPane;
 | 
					import javafx.scene.layout.StackPane;
 | 
				
			||||||
import javafx.stage.Stage;
 | 
					import javafx.stage.Stage;
 | 
				
			||||||
import java.io.InputStream;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Controller class for the Tutorial.fxml file
 | 
					 * Controller class for the Tutorial.fxml file
 | 
				
			||||||
| 
						 | 
					@ -23,8 +22,6 @@ public class TutorialController {
 | 
				
			||||||
    public ImageView imgAddNewPlant;
 | 
					    public ImageView imgAddNewPlant;
 | 
				
			||||||
    public ImageView imgTaskList;
 | 
					    public ImageView imgTaskList;
 | 
				
			||||||
    public ImageView imgSelectDate;
 | 
					    public ImageView imgSelectDate;
 | 
				
			||||||
    public ImageView imgAddTaskButton;
 | 
					 | 
				
			||||||
    public ImageView imgDetailDeleteButtons;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private int page = 0;
 | 
					    private int page = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,27 +30,10 @@ public class TutorialController {
 | 
				
			||||||
        switchViews();
 | 
					        switchViews();
 | 
				
			||||||
        setButtonAbilities();
 | 
					        setButtonAbilities();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        setImageView(imgAddNewPlant, "add-new-plant.png");
 | 
					        Image placeholder = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
 | 
				
			||||||
        setImageView(imgSelectDate, "select-sow-harvest.png");
 | 
					        imgAddNewPlant.setImage(placeholder);
 | 
				
			||||||
        setImageView(imgDetailDeleteButtons, "details-delete.png");
 | 
					        imgSelectDate.setImage(placeholder);
 | 
				
			||||||
        setImageView(imgTaskList, "schedule.png");
 | 
					        imgTaskList.setImage(placeholder);
 | 
				
			||||||
        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) {
 | 
					 | 
				
			||||||
        InputStream is = PlantsController.class.getResourceAsStream("screenshots/" + fileName);
 | 
					 | 
				
			||||||
        Image image;
 | 
					 | 
				
			||||||
        if (is != null) {
 | 
					 | 
				
			||||||
            image = new Image(String.valueOf(PlantsController.class.getResource("screenshots/" + fileName)));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            image = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        imageView.setImage(image);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void viewNextPage() {
 | 
					    public void viewNextPage() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,57 +17,46 @@ import java.util.TimerTask;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.Level;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					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 {
 | 
					public class BackgroundTasks extends TimerTask {
 | 
				
			||||||
    private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
 | 
					    private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
 | 
				
			||||||
    private final TaskList taskList;
 | 
					    private final TaskList taskList;
 | 
				
			||||||
    private final Notifier notifier;
 | 
					    private final Notifier notifier;
 | 
				
			||||||
    private final WeatherGradenTaskPlanner weatherGardenTaskPlaner;
 | 
					    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) {
 | 
					    public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) {
 | 
				
			||||||
        this.taskList = taskList;
 | 
					        this.taskList = taskList;
 | 
				
			||||||
        notifier = new Notifier(taskList, plantList, cropList);
 | 
					        notifier = new Notifier(taskList, plantList, cropList);
 | 
				
			||||||
        weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(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
 | 
					    @Override
 | 
				
			||||||
    public void run() {
 | 
					    public void run() {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            movePastTasks();
 | 
					            movePastTasks();
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
            LOG.log(Level.WARNING, "Could not execute Background Task: move past Tasks ", e.getCause());
 | 
					            LOG.log(Level.SEVERE, "Could not execute Background Task: move past Tasks ", e.getCause());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            weatherGardenTaskPlaner.refreshTasks();
 | 
					            weatherGardenTaskPlaner.refreshTasks();
 | 
				
			||||||
        } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) {
 | 
					        } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) {
 | 
				
			||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
            LOG.log(Level.WARNING, "Could not execute Background Task: Refresh Tasks by WeatherGardenTaskPlaner ", e.getCause());
 | 
					            LOG.log(Level.SEVERE, "Could not execute Background Task: Refresh Tasks by WeatherGardenTaskPlaner ", e.getCause());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            notifier.sendNotifications();
 | 
					            notifier.sendNotifications();
 | 
				
			||||||
        } catch (IOException | MessagingException | HardinessZoneNotSetException e) {
 | 
					        } catch (IOException | MessagingException | HardinessZoneNotSetException e) {
 | 
				
			||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
            LOG.log(Level.WARNING, "Could not execute Background Task: send Notification for due Tasks", e.getCause());
 | 
					            LOG.log(Level.SEVERE, "Could not execute Background Task: send Notification for due Tasks", e.getCause());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,9 +13,6 @@ import javax.mail.MessagingException;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.time.LocalDate;
 | 
					import java.time.LocalDate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Class to send Notifications to the user
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class Notifier {
 | 
					public class Notifier {
 | 
				
			||||||
    private final TaskList taskList;
 | 
					    private final TaskList taskList;
 | 
				
			||||||
    private final CropList cropList;
 | 
					    private final CropList cropList;
 | 
				
			||||||
| 
						 | 
					@ -28,13 +25,6 @@ public class Notifier {
 | 
				
			||||||
        this.plantList = plantList;
 | 
					        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 {
 | 
					    private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException {
 | 
				
			||||||
        String plantName = "unkown plant";
 | 
					        String plantName = "unkown plant";
 | 
				
			||||||
        if(cropList.getCropById((task.getCropId())).isPresent()){
 | 
					        if(cropList.getCropById((task.getCropId())).isPresent()){
 | 
				
			||||||
| 
						 | 
					@ -48,12 +38,6 @@ public class Notifier {
 | 
				
			||||||
        eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText);
 | 
					        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 {
 | 
					    public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException {
 | 
				
			||||||
        for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) {
 | 
					        for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) {
 | 
				
			||||||
            if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) {
 | 
					            if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,20 +10,16 @@ import java.util.Arrays;
 | 
				
			||||||
import java.util.Date;
 | 
					import java.util.Date;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Class to send E-Mails
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class EMailSender {
 | 
					public class EMailSender {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					
 | 
				
			||||||
     * Method to send E-Mail to one or multiple recipients
 | 
					    public EMailSender(){
 | 
				
			||||||
     * @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 {
 | 
					    public void sendMails(String recipients, String subject, String text) throws MessagingException {
 | 
				
			||||||
        printMail(recipients, subject, text);
 | 
					        // TODO replace printMail with implementation
 | 
				
			||||||
 | 
					        printMail(recipients, subject, text); // TODO Remove Printing E-Mail to console to test it
 | 
				
			||||||
        MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession());
 | 
					        MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession());
 | 
				
			||||||
        message.addHeader("Content-type", "text/HTML; charset=UTF-8");
 | 
					        message.addHeader("Content-type", "text/HTML; charset=UTF-8");
 | 
				
			||||||
        message.addHeader("format", "flowed");
 | 
					        message.addHeader("format", "flowed");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,10 +5,6 @@ import javax.mail.Session;
 | 
				
			||||||
import java.net.Authenticator;
 | 
					import java.net.Authenticator;
 | 
				
			||||||
import java.util.Properties;
 | 
					import java.util.Properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Class to store SMTP Credentials to send E-Mails and create
 | 
					 | 
				
			||||||
 * corresponding Session Object
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public record SmtpCredentials(
 | 
					public record SmtpCredentials(
 | 
				
			||||||
        String host,
 | 
					        String host,
 | 
				
			||||||
        String port,
 | 
					        String port,
 | 
				
			||||||
| 
						 | 
					@ -18,10 +14,6 @@ public record SmtpCredentials(
 | 
				
			||||||
        boolean startTLS
 | 
					        boolean startTLS
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Creates a Properties Object with SMTP Server Information
 | 
					 | 
				
			||||||
     * @return the created Properties Object
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private Properties getProperties() {
 | 
					    private Properties getProperties() {
 | 
				
			||||||
        Properties properties = new Properties();
 | 
					        Properties properties = new Properties();
 | 
				
			||||||
        properties.put("mail.smtp.host", host);
 | 
					        properties.put("mail.smtp.host", host);
 | 
				
			||||||
| 
						 | 
					@ -31,10 +23,6 @@ public record SmtpCredentials(
 | 
				
			||||||
        return properties;
 | 
					        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() {
 | 
					    private javax.mail.Authenticator getAuthenticator() {
 | 
				
			||||||
        return new javax.mail.Authenticator() {
 | 
					        return new javax.mail.Authenticator() {
 | 
				
			||||||
            @Override
 | 
					            @Override
 | 
				
			||||||
| 
						 | 
					@ -44,11 +32,10 @@ public record SmtpCredentials(
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Method to get the Session Instance with the given SMTP Credentials
 | 
					 | 
				
			||||||
     * @return the Session Instance
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public Session getSession() {
 | 
					    public Session getSession() {
 | 
				
			||||||
        return Session.getInstance(getProperties(), getAuthenticator());
 | 
					        return Session.getInstance(getProperties(), getAuthenticator());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,5 @@
 | 
				
			||||||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
 | 
					package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Enum of possible Weather events
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public enum SevereWeather {
 | 
					public enum SevereWeather {
 | 
				
			||||||
    FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
 | 
					    FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,11 +9,11 @@ import ch.zhaw.gartenverwaltung.types.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.time.LocalDate;
 | 
					import java.time.LocalDate;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days
 | 
					 * The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class WeatherGradenTaskPlanner {
 | 
					public class WeatherGradenTaskPlanner {
 | 
				
			||||||
    private final TaskList taskList;
 | 
					    private final TaskList taskList;
 | 
				
			||||||
| 
						 | 
					@ -42,19 +42,13 @@ public class WeatherGradenTaskPlanner {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void getSevereWeatherEvents() throws IOException {
 | 
					    private void getSevereWeatherEvents() throws IOException {
 | 
				
			||||||
        SevereWeather actualWeather = weatherService.causeSevereWeather(1);
 | 
					        SevereWeather actualWeather = weatherService.causeSevereWeather(1);
 | 
				
			||||||
 | 
					        if (SevereWeather.HAIL.equals(actualWeather)) {
 | 
				
			||||||
        List<Crop> actualCrops = cropList.getCrops();
 | 
					            //ToDo creates hail task all 3 seconds, pls fix
 | 
				
			||||||
        for (Crop crop : actualCrops) {
 | 
					            //createPreHailTask();
 | 
				
			||||||
 | 
					        } else if (SevereWeather.FROST.equals(actualWeather)) {
 | 
				
			||||||
            List<Task> actualCropTasks = taskList.getTaskForCrop(crop.getCropId().orElse(-1L));
 | 
					            createPreFrostTask();
 | 
				
			||||||
 | 
					        } else if (SevereWeather.SNOW.equals(actualWeather)) {
 | 
				
			||||||
            if (SevereWeather.HAIL.equals(actualWeather)) {
 | 
					            createPreSnowTask();
 | 
				
			||||||
                createPreHailTask(crop, actualCropTasks);
 | 
					 | 
				
			||||||
            } else if (SevereWeather.FROST.equals(actualWeather)) {
 | 
					 | 
				
			||||||
                createPreFrostTask(crop, actualCropTasks);
 | 
					 | 
				
			||||||
            } else if (SevereWeather.SNOW.equals(actualWeather)) {
 | 
					 | 
				
			||||||
                createPreSnowTask(crop, actualCropTasks);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,69 +58,38 @@ public class WeatherGradenTaskPlanner {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Method to create a PreHailTask and saves it in the tasklist
 | 
					     * Method to create a PreHailTask
 | 
				
			||||||
     * @throws IOException If the database cannot be accessed
 | 
					     * @throws IOException If the database cannot be accessed
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private void createPreHailTask(Crop crop, List<Task> actualTasksForCrop) throws IOException {
 | 
					    private void createPreHailTask() throws IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Task preHailTask = new Task("Hail",
 | 
					        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",
 | 
					                                    "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));
 | 
					                                    dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L),1L);
 | 
				
			||||||
 | 
					        taskList.saveTask(preHailTask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List<Task> hailTasks = actualTasksForCrop.stream().filter(task -> task.getName().equals("Hail")).toList();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(isNoSevereWeatherTaskAtDate(preHailTask, hailTasks) && hailTasks.isEmpty()){
 | 
					 | 
				
			||||||
            taskList.saveTask(preHailTask);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Method to create a PreFrosttask and saves it in the tasklist
 | 
					     * Method to create a PreFrosttask
 | 
				
			||||||
     * @throws IOException If the database cannot be accessed
 | 
					     * @throws IOException If the database cannot be accessed
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private void createPreFrostTask(Crop crop, List<Task> actualTasksForCrop) throws IOException {
 | 
					    private void createPreFrostTask() throws IOException {
 | 
				
			||||||
         Task preFrostTask = new Task("Frost",
 | 
					        Task preFrostTask = new Task("Frost",
 | 
				
			||||||
                    "The temperatur falls below zero degrees, cover especially the root with wool",
 | 
					                                    "The temperatur falls below zero degrees, cover especially the root with wool",
 | 
				
			||||||
                    dateSevereWeather,dateSevereWeather.plusDays(1L),crop.getCropId().orElse(-1L));
 | 
					                                    dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L),1L);
 | 
				
			||||||
 | 
					        taskList.saveTask(preFrostTask);
 | 
				
			||||||
         List<Task> frostTasks = actualTasksForCrop.stream().filter(task -> task.getName().equals("Frost")).toList();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         if(isNoSevereWeatherTaskAtDate(preFrostTask, frostTasks) && frostTasks.isEmpty()){
 | 
					 | 
				
			||||||
            taskList.saveTask(preFrostTask);
 | 
					 | 
				
			||||||
         }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Method to create a PreSnowTask and saves it in the tasklist
 | 
					     * Method to create a PreSnowTask
 | 
				
			||||||
     * @throws IOException If the database cannot be accessed
 | 
					     * @throws IOException If the database cannot be accessed
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private void createPreSnowTask(Crop crop, List<Task> actualTasksForCrop) throws IOException {
 | 
					    private void createPreSnowTask() throws IOException {
 | 
				
			||||||
        Task preSnowTask = new Task("Snow",
 | 
					        Task preSnowTask = new Task("Snow",
 | 
				
			||||||
                "The weather brings little snowfall. Cover your crops",
 | 
					                                    "The weather brings little snowfall. Cover your crops",
 | 
				
			||||||
                dateSevereWeather, dateSevereWeather.plusDays(1L), crop.getCropId().orElse(-1L));
 | 
					                                    dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L),1L);
 | 
				
			||||||
 | 
					        taskList.saveTask(preSnowTask);
 | 
				
			||||||
        List<Task> snowTasklist = actualTasksForCrop.stream().filter(task -> task.getName().equals("Snow")).toList();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(isNoSevereWeatherTaskAtDate(preSnowTask, snowTasklist) && snowTasklist.isEmpty()){
 | 
					 | 
				
			||||||
            taskList.saveTask(preSnowTask);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Method to create a PreSnowTask and saves it in the tasklist
 | 
					 | 
				
			||||||
     * @param preSevereWeatherTask the Task which would be added if there is not already
 | 
					 | 
				
			||||||
     *                             the same Type of severe weather task
 | 
					 | 
				
			||||||
     * @param severeWeatherTasks List of severe weather tasks from e specific severe weather
 | 
					 | 
				
			||||||
     * @return true If there is not already a severe weather task of the same type of preSevereWeatherTask
 | 
					 | 
				
			||||||
     *              task at the date of the preSevereWeatherTask
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private boolean isNoSevereWeatherTaskAtDate(Task preSevereWeatherTask, List<Task> severeWeatherTasks) {
 | 
					 | 
				
			||||||
        List<Task> severeWeatherTasksAtDate = new ArrayList<>();
 | 
					 | 
				
			||||||
        for (Task task : severeWeatherTasks) {
 | 
					 | 
				
			||||||
            if (task.getStartDate() == preSevereWeatherTask.getStartDate()) {
 | 
					 | 
				
			||||||
                severeWeatherTasksAtDate.add(task);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return severeWeatherTasksAtDate.isEmpty();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
 | 
					package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner
 | 
					 * The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class WeatherService {
 | 
					public class WeatherService {
 | 
				
			||||||
    private static final int NO_RAIN = 0;
 | 
					    private static final int NO_RAIN = 0;
 | 
				
			||||||
| 
						 | 
					@ -8,11 +9,6 @@ public class WeatherService {
 | 
				
			||||||
    private static final int RAIN = 25;
 | 
					    private static final int RAIN = 25;
 | 
				
			||||||
    private static final int HEAVY_RAIN = 50;
 | 
					    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) {
 | 
					    public SevereWeather causeSevereWeather(int randomWeather) {
 | 
				
			||||||
        return switch (randomWeather) {
 | 
					        return switch (randomWeather) {
 | 
				
			||||||
            case 1 -> SevereWeather.HAIL;
 | 
					            case 1 -> SevereWeather.HAIL;
 | 
				
			||||||
| 
						 | 
					@ -23,11 +19,6 @@ 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) {
 | 
					    public int causeRainAmount(int randomRainAmount) {
 | 
				
			||||||
        return switch (randomRainAmount) {
 | 
					        return switch (randomRainAmount) {
 | 
				
			||||||
            case 1 -> NO_RAIN;
 | 
					            case 1 -> NO_RAIN;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
package ch.zhaw.gartenverwaltung.bootstrap;
 | 
					package ch.zhaw.gartenverwaltung.bootstrap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.CropDetailController;
 | 
					 | 
				
			||||||
import ch.zhaw.gartenverwaltung.Main;
 | 
					import ch.zhaw.gartenverwaltung.Main;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.io.*;
 | 
					import ch.zhaw.gartenverwaltung.io.*;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.models.Garden;
 | 
					import ch.zhaw.gartenverwaltung.models.Garden;
 | 
				
			||||||
| 
						 | 
					@ -18,15 +17,12 @@ import java.util.Arrays;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Class responsible for bootstrapping the application wide dependencies
 | 
					 * Class responsible for bootstrapping the application wide dependencies
 | 
				
			||||||
 * and injecting them into JavaFX Controllers.
 | 
					 * and injecting them into JavaFX Controllers.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class AppLoader {
 | 
					public class AppLoader {
 | 
				
			||||||
    private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Caching the panes
 | 
					     * Caching the panes
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
| 
						 | 
					@ -150,17 +146,12 @@ public class AppLoader {
 | 
				
			||||||
                    try {
 | 
					                    try {
 | 
				
			||||||
                        afterInjectMethod.invoke(controller);
 | 
					                        afterInjectMethod.invoke(controller);
 | 
				
			||||||
                    } catch (IllegalAccessException | InvocationTargetException e) {
 | 
					                    } catch (IllegalAccessException | InvocationTargetException e) {
 | 
				
			||||||
                        LOG.log(Level.SEVERE, "Could not invoke afterInjectMethod", e.getCause());
 | 
					                        // TODO: Log
 | 
				
			||||||
                        e.printStackTrace();
 | 
					                        e.printStackTrace();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Method to get any AppDependency
 | 
					 | 
				
			||||||
     * @param type Class of Dependency
 | 
					 | 
				
			||||||
     * @return the App dependency
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public Object getAppDependency(Class<?> type) {
 | 
					    public Object getAppDependency(Class<?> type) {
 | 
				
			||||||
        return dependencies.get(type.getSimpleName());
 | 
					        return dependencies.get(type.getSimpleName());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,5 @@
 | 
				
			||||||
package ch.zhaw.gartenverwaltung.io;
 | 
					package ch.zhaw.gartenverwaltung.io;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Exceptionm which is thrown if Hardiness zone is not set in plant list.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class HardinessZoneNotSetException extends Exception {
 | 
					public class HardinessZoneNotSetException extends Exception {
 | 
				
			||||||
    public HardinessZoneNotSetException() {
 | 
					    public HardinessZoneNotSetException() {
 | 
				
			||||||
        super("HardinessZone must be set to retrieve plants!");
 | 
					        super("HardinessZone must be set to retrieve plants!");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,9 +2,6 @@ package ch.zhaw.gartenverwaltung.io;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Excption which is thrown if a JSON file has a invalid File format.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
class InvalidJsonException extends IOException {
 | 
					class InvalidJsonException extends IOException {
 | 
				
			||||||
    public InvalidJsonException(String reason) {
 | 
					    public InvalidJsonException(String reason) {
 | 
				
			||||||
        super(reason);
 | 
					        super(reason);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,6 +50,8 @@ public class Garden {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void plantAsCrop(Plant plant, LocalDate plantingDate) throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
 | 
					    public void plantAsCrop(Plant plant, LocalDate plantingDate) throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
 | 
				
			||||||
        Crop crop = new Crop(plant.id(), plantingDate);
 | 
					        Crop crop = new Crop(plant.id(), plantingDate);
 | 
				
			||||||
 | 
					        //TODO Add Area to Plant
 | 
				
			||||||
 | 
					        //crop.withArea(0);
 | 
				
			||||||
        cropList.saveCrop(crop);
 | 
					        cropList.saveCrop(crop);
 | 
				
			||||||
        gardenSchedule.planTasksForCrop(crop);
 | 
					        gardenSchedule.planTasksForCrop(crop);
 | 
				
			||||||
        plantedCrops.clear();
 | 
					        plantedCrops.clear();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,16 @@ public class GardenSchedule {
 | 
				
			||||||
    public GardenSchedule(TaskList taskList, PlantList plantList) throws IOException {
 | 
					    public GardenSchedule(TaskList taskList, PlantList plantList) throws IOException {
 | 
				
			||||||
        this.taskList = taskList;
 | 
					        this.taskList = taskList;
 | 
				
			||||||
        this.plantList = plantList;
 | 
					        this.plantList = plantList;
 | 
				
			||||||
 | 
					        TaskList.TaskListObserver taskListObserver = newTaskList -> {
 | 
				
			||||||
 | 
					            Platform.runLater(() -> {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    getTasksUpcomingWeek();
 | 
				
			||||||
 | 
					                } catch (IOException e) {
 | 
				
			||||||
 | 
					                    throw new RuntimeException(e);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        setTaskListObserver(taskListObserver);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ListProperty<List<Task>> getWeeklyTaskListProperty() {
 | 
					    public ListProperty<List<Task>> getWeeklyTaskListProperty() {
 | 
				
			||||||
| 
						 | 
					@ -166,12 +176,14 @@ public class GardenSchedule {
 | 
				
			||||||
            dayTaskList.add(new ArrayList<>());
 | 
					            dayTaskList.add(new ArrayList<>());
 | 
				
			||||||
            final int finalI = i;
 | 
					            final int finalI = i;
 | 
				
			||||||
            weekTasks.forEach(task -> {
 | 
					            weekTasks.forEach(task -> {
 | 
				
			||||||
            if(task.getNextExecution() != null) {
 | 
					                if (task.getNextExecution() == null) {
 | 
				
			||||||
 | 
					                    task.isDone();
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
                    LocalDate checkDate = task.getNextExecution();
 | 
					                    LocalDate checkDate = task.getNextExecution();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    do {
 | 
					                    do {
 | 
				
			||||||
                        if (date.equals(task.getNextExecution()) || (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN)))) {
 | 
					                        if (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN))) {
 | 
				
			||||||
                            dayTaskList.get(finalI).add(task);
 | 
					                            dayTaskList.get(finalI).add(task);
 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        checkDate = checkDate.plusDays(task.getInterval().orElse(0));
 | 
					                        checkDate = checkDate.plusDays(task.getInterval().orElse(0));
 | 
				
			||||||
                    } while (!(task.getInterval().orElse(0) == 0) && checkDate.isBefore(LocalDate.now().plusDays(listLength)));
 | 
					                    } while (!(task.getInterval().orElse(0) == 0) && checkDate.isBefore(LocalDate.now().plusDays(listLength)));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
package ch.zhaw.gartenverwaltung.models;
 | 
					package ch.zhaw.gartenverwaltung.models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.Settings;
 | 
					 | 
				
			||||||
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
 | 
					import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.io.PlantList;
 | 
					import ch.zhaw.gartenverwaltung.io.PlantList;
 | 
				
			||||||
import ch.zhaw.gartenverwaltung.types.GrowthPhaseType;
 | 
					import ch.zhaw.gartenverwaltung.types.GrowthPhaseType;
 | 
				
			||||||
| 
						 | 
					@ -17,6 +16,7 @@ import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class PlantListModel {
 | 
					public class PlantListModel {
 | 
				
			||||||
    private final PlantList plantList;
 | 
					    private final PlantList plantList;
 | 
				
			||||||
 | 
					    private HardinessZone currentZone;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Comparators to create sorted Plant List
 | 
					     * Comparators to create sorted Plant List
 | 
				
			||||||
| 
						 | 
					@ -33,15 +33,15 @@ public class PlantListModel {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void setDefaultZone() {
 | 
					    private void setDefaultZone() {
 | 
				
			||||||
        Settings.getInstance().setCurrentHardinessZone(null);
 | 
					        currentZone = HardinessZone.ZONE_8A; // TODO: get Default Zone from Settings
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setCurrentZone(HardinessZone currentZone) {
 | 
					    public void setCurrentZone(HardinessZone currentZone) {
 | 
				
			||||||
        Settings.getInstance().setCurrentHardinessZone(currentZone);
 | 
					        this.currentZone = currentZone;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public HardinessZone getCurrentZone() {
 | 
					    public HardinessZone getCurrentZone() {
 | 
				
			||||||
        return Settings.getInstance().getCurrentHardinessZone();
 | 
					        return currentZone;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,5 @@
 | 
				
			||||||
package ch.zhaw.gartenverwaltung.models;
 | 
					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 class PlantNotFoundException extends Exception {
 | 
				
			||||||
    public PlantNotFoundException() {
 | 
					    public PlantNotFoundException() {
 | 
				
			||||||
        super("The selected Plant was not found in Database!");
 | 
					        super("The selected Plant was not found in Database!");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,7 @@ public class Crop {
 | 
				
			||||||
    public Optional<Long> getCropId() {
 | 
					    public Optional<Long> getCropId() {
 | 
				
			||||||
        return Optional.ofNullable(cropId);
 | 
					        return Optional.ofNullable(cropId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public long getPlantId() { return plantId; }
 | 
					    public long getPlantId() { return plantId; }
 | 
				
			||||||
    public LocalDate getStartDate() { return startDate; }
 | 
					    public LocalDate getStartDate() { return startDate; }
 | 
				
			||||||
    public double getArea() { return area; }
 | 
					    public double getArea() { return area; }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,7 +68,7 @@ public record Plant(
 | 
				
			||||||
                return growthPhase.group();
 | 
					                return growthPhase.group();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return 0;
 | 
					        return 0; // TODO implement
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,6 @@ public class Task {
 | 
				
			||||||
        this.startDate = startDate;
 | 
					        this.startDate = startDate;
 | 
				
			||||||
        nextExecution = startDate;
 | 
					        nextExecution = startDate;
 | 
				
			||||||
        this.endDate = endDate;
 | 
					        this.endDate = endDate;
 | 
				
			||||||
        this.cropId = cropId;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -108,7 +107,7 @@ public class Task {
 | 
				
			||||||
     * @return Whether the Task is within the given range
 | 
					     * @return Whether the Task is within the given range
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public boolean isInTimePeriod(LocalDate searchStartDate, LocalDate searchEndDate) {
 | 
					    public boolean isInTimePeriod(LocalDate searchStartDate, LocalDate searchEndDate) {
 | 
				
			||||||
        return  (endDate.isAfter(searchStartDate) && startDate.isBefore(searchEndDate)) || ((nextExecution != null && nextExecution.isBefore(searchEndDate.plusDays(1)) && nextExecution.isAfter(searchStartDate.minusDays(1))));
 | 
					        return endDate.isAfter(searchStartDate) && startDate.isBefore(searchEndDate) || (nextExecution != null && nextExecution.isBefore(searchEndDate) && nextExecution.isAfter(searchStartDate));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,9 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.time.LocalDate;
 | 
					import java.time.LocalDate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Class which represents a Task if the start and enddate is not known yet.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class TaskTemplate {
 | 
					public class TaskTemplate {
 | 
				
			||||||
    @JsonProperty
 | 
					    @JsonProperty
 | 
				
			||||||
    private final String name;
 | 
					    private final String name;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@
 | 
				
			||||||
                        <Insets bottom="10.0" />
 | 
					                        <Insets bottom="10.0" />
 | 
				
			||||||
                     </VBox.margin>
 | 
					                     </VBox.margin>
 | 
				
			||||||
                  </ListView>
 | 
					                  </ListView>
 | 
				
			||||||
                  <Button styleClass="button-class" fx:id="addTask_button" mnemonicParsing="false" onAction="#addTask" prefHeight="25.0" prefWidth="120.0" VBox.vgrow="NEVER" text="Add Task">
 | 
					                  <Button styleClass="button-class" fx:id="addTask_button" mnemonicParsing="false" onAction="#addTask" prefHeight="25.0" prefWidth="45.0" VBox.vgrow="NEVER">
 | 
				
			||||||
                     <VBox.margin>
 | 
					                     <VBox.margin>
 | 
				
			||||||
                        <Insets />
 | 
					                        <Insets />
 | 
				
			||||||
                     </VBox.margin>
 | 
					                     </VBox.margin>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<?import javafx.geometry.Insets?>
 | 
					<?import javafx.geometry.Insets?>
 | 
				
			||||||
<?import javafx.scene.control.Button?>
 | 
					 | 
				
			||||||
<?import javafx.scene.control.Label?>
 | 
					<?import javafx.scene.control.Label?>
 | 
				
			||||||
<?import javafx.scene.control.ListView?>
 | 
					<?import javafx.scene.control.ListView?>
 | 
				
			||||||
<?import javafx.scene.layout.AnchorPane?>
 | 
					<?import javafx.scene.layout.AnchorPane?>
 | 
				
			||||||
| 
						 | 
					@ -20,12 +19,11 @@
 | 
				
			||||||
            </Label>
 | 
					            </Label>
 | 
				
			||||||
            <HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="541.0" prefWidth="867.0" spacing="10.0" VBox.vgrow="ALWAYS">
 | 
					            <HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="541.0" prefWidth="867.0" spacing="10.0" VBox.vgrow="ALWAYS">
 | 
				
			||||||
               <children>
 | 
					               <children>
 | 
				
			||||||
                  <VBox prefHeight="497.0" prefWidth="237.0" spacing="10.0" HBox.hgrow="NEVER">
 | 
					                  <ListView fx:id="scheduledPlants_listview" maxWidth="1.7976931348623157E308" prefHeight="522.0" prefWidth="271.0" HBox.hgrow="NEVER">
 | 
				
			||||||
                     <children>
 | 
					                     <HBox.margin>
 | 
				
			||||||
                        <ListView fx:id="scheduledPlants_listview" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="522.0" prefWidth="271.0" VBox.vgrow="ALWAYS" />
 | 
					                        <Insets />
 | 
				
			||||||
                        <Button maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#showAllTasks" styleClass="button-class" text="Show All Tasks" VBox.vgrow="NEVER" />
 | 
					                     </HBox.margin>
 | 
				
			||||||
                     </children>
 | 
					                  </ListView>
 | 
				
			||||||
                  </VBox>
 | 
					 | 
				
			||||||
                  <VBox maxWidth="1.7976931348623157E308" prefHeight="537.0" prefWidth="650.0" spacing="10.0" HBox.hgrow="ALWAYS">
 | 
					                  <VBox maxWidth="1.7976931348623157E308" prefHeight="537.0" prefWidth="650.0" spacing="10.0" HBox.hgrow="ALWAYS">
 | 
				
			||||||
                     <children>
 | 
					                     <children>
 | 
				
			||||||
                        <ListView fx:id="week_listView" maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
 | 
					                        <ListView fx:id="week_listView" maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,9 +22,9 @@
 | 
				
			||||||
            <Separator prefWidth="50.0" visible="false" HBox.hgrow="ALWAYS" />
 | 
					            <Separator prefWidth="50.0" visible="false" HBox.hgrow="ALWAYS" />
 | 
				
			||||||
            <ButtonBar prefHeight="40.0" prefWidth="200.0">
 | 
					            <ButtonBar prefHeight="40.0" prefWidth="200.0">
 | 
				
			||||||
              <buttons>
 | 
					              <buttons>
 | 
				
			||||||
                  <Button cancelButton="true" contentDisplay="CENTER" graphicTextGap="5.0" mnemonicParsing="false" onAction="#closeTutorial" styleClass="button-class" text="Close" />
 | 
					                  <Button styleClass="button-class" cancelButton="true" contentDisplay="CENTER" graphicTextGap="5.0" mnemonicParsing="false" text="Close" onAction="#closeTutorial"/>
 | 
				
			||||||
                <Button fx:id="previousPageButton" mnemonicParsing="false" onAction="#viewPreviousPage" styleClass="button-class" text="Previous" />
 | 
					                <Button styleClass="button-class" fx:id="previousPageButton" mnemonicParsing="false" text="Previous" onAction="#viewPreviousPage"/>
 | 
				
			||||||
                  <Button fx:id="nextPageButton" defaultButton="true" mnemonicParsing="false" onAction="#viewNextPage" styleClass="button-class" text="Next" />
 | 
					                  <Button styleClass="button-class" fx:id="nextPageButton" defaultButton="true" mnemonicParsing="false" text="Next" onAction="#viewNextPage" />
 | 
				
			||||||
              </buttons>
 | 
					              </buttons>
 | 
				
			||||||
            </ButtonBar>
 | 
					            </ButtonBar>
 | 
				
			||||||
         </children>
 | 
					         </children>
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,7 @@
 | 
				
			||||||
         <children>
 | 
					         <children>
 | 
				
			||||||
            <VBox layoutX="30.0" layoutY="26.0" opacity="0.0" prefHeight="200.0" prefWidth="100.0">
 | 
					            <VBox layoutX="30.0" layoutY="26.0" opacity="0.0" prefHeight="200.0" prefWidth="100.0">
 | 
				
			||||||
               <children>
 | 
					               <children>
 | 
				
			||||||
                  <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Adding Crops">
 | 
					                  <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Managing Your Crops">
 | 
				
			||||||
                     <font>
 | 
					                     <font>
 | 
				
			||||||
                        <Font size="24.0" />
 | 
					                        <Font size="24.0" />
 | 
				
			||||||
                     </font>
 | 
					                     </font>
 | 
				
			||||||
| 
						 | 
					@ -75,7 +75,7 @@
 | 
				
			||||||
                           </children>
 | 
					                           </children>
 | 
				
			||||||
                        </TextFlow>
 | 
					                        </TextFlow>
 | 
				
			||||||
                        <Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
 | 
					                        <Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
 | 
				
			||||||
                        <ImageView fx:id="imgSelectDate" fitHeight="150.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true" />
 | 
					                        <ImageView fx:id="imgSelectDate" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
 | 
				
			||||||
                     </children>
 | 
					                     </children>
 | 
				
			||||||
                  </HBox>
 | 
					                  </HBox>
 | 
				
			||||||
               </children>
 | 
					               </children>
 | 
				
			||||||
| 
						 | 
					@ -83,50 +83,7 @@
 | 
				
			||||||
                  <Insets />
 | 
					                  <Insets />
 | 
				
			||||||
               </opaqueInsets>
 | 
					               </opaqueInsets>
 | 
				
			||||||
            </VBox>
 | 
					            </VBox>
 | 
				
			||||||
            <VBox layoutX="30.0" layoutY="30.0" prefHeight="200.0" prefWidth="100.0">
 | 
					            <VBox 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>
 | 
					               <children>
 | 
				
			||||||
                  <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Managing Your Tasks">
 | 
					                  <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Managing Your Tasks">
 | 
				
			||||||
                     <font>
 | 
					                     <font>
 | 
				
			||||||
| 
						 | 
					@ -154,9 +111,19 @@
 | 
				
			||||||
                           </HBox.margin>
 | 
					                           </HBox.margin>
 | 
				
			||||||
                        </TextFlow>
 | 
					                        </TextFlow>
 | 
				
			||||||
                        <Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
 | 
					                        <Separator prefWidth="200.0" visible="false" HBox.hgrow="ALWAYS" />
 | 
				
			||||||
                        <ImageView fx:id="imgTaskList" fitHeight="200.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true" />
 | 
					                        <ImageView fx:id="imgTaskList" fitHeight="98.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" />
 | 
				
			||||||
                     </children>
 | 
					                     </children>
 | 
				
			||||||
                  </HBox>
 | 
					                  </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>
 | 
					               </children>
 | 
				
			||||||
               <opaqueInsets>
 | 
					               <opaqueInsets>
 | 
				
			||||||
                  <Insets />
 | 
					                  <Insets />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 3.2 KiB  | 
| 
		 Before Width: | Height: | Size: 16 KiB  | 
| 
		 Before Width: | Height: | Size: 1.4 KiB  | 
| 
		 Before Width: | Height: | Size: 42 KiB  | 
| 
		 Before Width: | Height: | Size: 34 KiB  | 
| 
						 | 
					@ -52,7 +52,7 @@ public class WeatherGardenTaskPlannerTest {
 | 
				
			||||||
        exampleTask.setNextExecution(LocalDate.now().plusDays(1L));
 | 
					        exampleTask.setNextExecution(LocalDate.now().plusDays(1L));
 | 
				
			||||||
        exampleWeatherTask = new Task("Hail",
 | 
					        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",
 | 
					                "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);
 | 
					                LocalDate.now().minusDays(1L),LocalDate.now().plusDays(1L),3L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        taskList = new JsonTaskList(testFile);
 | 
					        taskList = new JsonTaskList(testFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,7 +101,7 @@ class PlantListModelTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    void setCurrentZone() {
 | 
					    void setCurrentZone() {
 | 
				
			||||||
        checkCurrentZone(HardinessZone.ZONE_8A);
 | 
					        checkCurrentZone(HardinessZone.ZONE_8A); // TODO change to get default zone from config
 | 
				
			||||||
        model.setCurrentZone(HardinessZone.ZONE_1A);
 | 
					        model.setCurrentZone(HardinessZone.ZONE_1A);
 | 
				
			||||||
        checkCurrentZone(HardinessZone.ZONE_1A);
 | 
					        checkCurrentZone(HardinessZone.ZONE_1A);
 | 
				
			||||||
        model.setCurrentZone(HardinessZone.ZONE_8A);
 | 
					        model.setCurrentZone(HardinessZone.ZONE_8A);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||