diff --git a/.gitignore b/.gitignore
index 2873e189e1..1444868b63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,6 @@ bin/
/text-ui-test/ACTUAL.TXT
text-ui-test/EXPECTED-UNIX.TXT
+
+# plantuml jar
+plantuml.jar
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..c5f3f6b9c7
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "interactive"
+}
\ No newline at end of file
diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..b942eaba55
--- /dev/null
+++ b/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: seedu.lifetracker.LifeTracker
+
diff --git a/README.md b/README.md
index f82e2494b7..70670a7826 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,11 @@
-# Duke project template
+# LifeTracker
-This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
+LifeTracker is a desktop application used for encouraging users to lead a healthier life by tracking their net calorie intake. The user interacts with it using a CLI. LifeTracker is written in Java 11 and has about 4 kLoC.
+
+Useful links:
+
+* [User Guide](./docs/UserGuide.md)
+* [Developer Guide](./docs/DeveloperGuide.md)
## Setting up in Intellij
@@ -8,22 +13,33 @@ Prerequisites: JDK 11 (use the exact version), update Intellij to the most recen
1. **Ensure Intellij JDK 11 is defined as an SDK**, as described [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk) -- this step is not needed if you have used JDK 11 in a previous Intellij project.
1. **Import the project _as a Gradle project_**, as described [here](https://se-education.org/guides/tutorials/intellijImportGradleProject.html).
-1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/duke/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below:
+1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/lifetracker/LifeTracker.java` file, right-click it, and choose `Run LifeTracker.main()`. If the setup is correct, you should see something like the below:
+
```
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
-
- > Task :Duke.main()
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
-
- What is your name?
+
+ > Task :run
+ Initialised Meal Storage
+ Initialised User Storage
+ Initialised Exercise Storage
+ ------------------------------------------------------------
+ Hello! Welcome to
+ _ _ __ _______ _
+ | | (_)/ _||__ __| | |
+ | | _| |_ ___| |_ __ __ _ ___| | _____ _ __
+ | | | | _/ _ \ | '__/ _` |/ __| |/ / _ \ '__|
+ | |____| | || __/ | | | (_| | (__| < __/ |
+ |______|_|_| \___|_|_| \__,_|\___|_|\_\___|_|
+
+ ------------------------------------------------------------
+ Hello! I am LifeTracker, a program to aid you in keeping fit!
+
+ Please enter command 'help' if you require assistance.
+ ------------------------------------------------------------
```
+
Type some word and press enter to let the execution proceed to the end.
## Build automation using Gradle
@@ -39,7 +55,7 @@ Prerequisites: JDK 11 (use the exact version), update Intellij to the most recen
### JUnit tests
-* A skeleton JUnit test (`src/test/java/seedu/duke/DukeTest.java`) is provided with this project template.
+* A skeleton JUnit test (`src/test/java/seedu/duke/DukeTest.java`) is provided with this project template.
* If you are new to JUnit, refer to the [JUnit Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/junit.html).
## Checkstyle
@@ -55,7 +71,8 @@ The project uses [GitHub actions](https://github.com/features/actions) for CI. W
`/docs` folder contains a skeleton version of the project documentation.
-Steps for publishing documentation to the public:
+Steps for publishing documentation to the public:
+
1. If you are using this project template for an individual project, go your fork on GitHub.
If you are using this project template for a team project, go to the team fork on GitHub.
1. Click on the `settings` tab.
diff --git a/build.gradle b/build.gradle
index d5e548e85f..ba4a11de1a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,6 +3,7 @@ plugins {
id 'application'
id 'checkstyle'
id 'com.github.johnrengelman.shadow' version '7.1.2'
+ id 'jacoco'
}
repositories {
@@ -12,6 +13,7 @@ repositories {
dependencies {
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0'
+ implementation 'com.opencsv:opencsv:5.6'
}
test {
@@ -29,11 +31,11 @@ test {
}
application {
- mainClass = "seedu.duke.Duke"
+ mainClass = "seedu.lifetracker.LifeTracker"
}
shadowJar {
- archiveBaseName = "duke"
+ archiveBaseName = "lifeTracker"
archiveClassifier = null
}
@@ -43,4 +45,18 @@ checkstyle {
run{
standardInput = System.in
+ enableAssertions = true
+}
+
+jacoco {
+ toolVersion = "0.8.5"
+ reportsDirectory = file("$buildDir/jacoco")
+}
+
+test {
+ finalizedBy jacocoTestReport
+}
+
+jacocoTestReport {
+ dependsOn test
}
diff --git a/data/FoodData.csv b/data/FoodData.csv
new file mode 100644
index 0000000000..0e09ca1401
--- /dev/null
+++ b/data/FoodData.csv
@@ -0,0 +1,186 @@
+ID,Type,Name,Store,Store Number,Energy (Kcal),Protein (g),Total Fat (g),Saturated Fat (g),Dietary Fibre (g),Carbohyrate (g),Sugar (g),Sodium (g)
+0,Dish,Black Pepper Chicken Chop ,Western,1,775,42.4,51.7,,,31.6,6.9,
+1,Dish,Chicken Cutlet ,Western,1,966,47.8,60.1,,,54.9,7.2,
+2,Dish,Grilled Dory Fish ,Western,1,530,45.1,21.3,,,37.2,8.2,
+3,Dish,Fish & Chip ,Western,1,838,46.4,49.1,,,50.7,8.3,
+4,Dish,Black Pepper Ribeye Steak ,Western,1,807,44.9,45.6,,,53.2,9.3,
+5,Dish,Combo Set 1: Ribeye Steak & Grilled Chicken,Western,1,831,43.2,48.7,,,52.5,9,
+6,Dish,Combo Set 2: Ribeye Steak & Grilled Fish,Western,1,680,41.3,33.2,,,52.4,9.2,
+7,Dish,Combo Set 3: Ribeye Steak & Grilled Salmon,Western,1,776,42.4,43.6,,,52.3,9,
+8,Dish,Combo Set 4: Grilled Chicken Chop & Grilled Salmon,Western,1,846,43.7,50.8,,,51.1,9,
+9,Dish,Combo Set 5: Grilled Chicken Chop & Grilled Dory Fish,Western,1,750,42.7,40.3,,,51.3,9.2,
+10,Dish,Arrabiata ,Western,1,295,10.3,5.1,,,50,7.3,
+11,Dish,Pomodoro ,Western,1,341,13.9,2.7,,,69,21.6,
+12,Dish,Creamy Chicken Spaghetti (Small) ,Western,1,755,31.6,54.3,,,34.1,3.7,
+13,Dish,Creamy Chicken Spaghetti (Normal) ,Western,1,822,34,54.7,,,47.2,4,
+14,Dish,Creamy Chicken Spaghetti (Upsize) ,Western,1,901,36.9,55.2,,,62.7,4.3,
+15,Dish,Creamy Chicken Ham & Mushroom Spaghetti (Small) ,Western,1,571,19.2,38.2,,,37.8,4.2,
+16,Dish,Creamy Chicken Ham & Mushroom Spaghetti (Normal) ,Western,1,638,21.7,38.6,,,50.9,4.4,
+17,Dish,Creamy Chicken Ham & Mushroom Spaghetti (Upsize) ,Western,1,717,24.6,39,,,66.4,4.7,
+18,Dish,Prawns & Mushroom Spaghetti (Small) ,Western,1,557,20.5,36.5,,,36.9,4,
+19,Dish,Prawns & Mushroom Spaghetti (Normal) ,Western,1,624,23,36.9,,,50,4.2,
+20,Dish,Prawns & Mushroom Spaghetti (Upsize) ,Western,1,703,25.9,37.3,,,65.4,4.5,
+21,Dish,Hot Chicken Spaghetti (Small) ,Western,1,298,16.6,8.6,,,36.9,7,
+22,Dish,Hot Chicken Spaghetti (Normal) ,Western,1,365,19.1,9,,,50,7.3,
+23,Dish,Hot Chicken Spaghetti (Upsize) ,Western,1,444,22,9.4,,,65.5,7.6,
+24,Dish,Creamy Sausage & Mushroom Spaghetti (Small) ,Western,1,688,28.8,46.7,,,37.6,4,
+25,Dish,Creamy Sausage & Mushroom Spaghetti (Normal) ,Western,1,755,31.3,47,,,50.7,4.2,
+26,Dish,Creamy Sausage & Mushroom Spaghetti (Upsize) ,Western,1,834,34.2,47.5,,,66.1,4.5,
+27,Dish,Alfredo (Small) ,Western,1,651,28.9,42.8,,,37.8,4.2,
+28,Dish,Alfredo (Normal) ,Western,1,718,31.3,43.2,,,50.9,4.4,
+29,Dish,Alfredo (Upsize) ,Western,1,797,34.2,43.7,,,66.4,4.7,
+30,Dish,Chicken Patty Spaghetti ,Western,1,530,29.3,19.1,,,58.4,7.6,
+31,Dish,Chicken Cheese Ball Spaghetti ,Western,1,501,24.3,16.7,,,61.7,9.6,
+32,Dish,Salmon e Funghi Spaghetti (Small) ,Western,1,715,31.2,49.4,,,36.9,4,
+33,Dish,Salmon e Funghi Spaghetti (Normal) ,Western,1,782,33.7,49.7,,,50,4.2,
+34,Dish,Salmon e Funghi Spaghetti (Upsize) ,Western,1,861,36.6,50.2,,,65.4,5,
+35,Dish,Seafood Marinara (Small) ,Western,1,373,36.1,7.8,,,37.9,7,
+36,Dish,Seafood Marinara (Normal) ,Western,1,440,38.5,8.1,,,51,7,
+37,Dish,Seafood Marinara (Upsize) ,Western,1,519,41.4,8.6,,,66.5,8,
+38,Dish,Creamy Fish Pasta (Small) ,Western,1,616,32.1,39,,,34.1,4,
+39,Dish,Creamy Fish Pasta (Normal) ,Western,1,683,34.6,39.4,,,47.2,4,
+40,Dish,Creamy Fish Pasta (Upsize) ,Western,1,762,37.5,39.8,,,62.7,4,
+41,Dish,Baked Beans & Fries & Sausage,Western,1,359,16.8,22,,,21.7,4,
+42,Dish,Baked Beans & Mashed Potato & Sausage ,Western,1,447,18.6,24.6,,,35.6,6,
+43,Side,Mashed Potato,Western,1,89,1.9,2.5,,,13.8,2,
+44,Side,Sunny Side Up,Western,1,102,7,8,,,0.5,0,
+45,Side,French Fries,Western,1,164,1.3,11.6,,,13.5,0,
+46,Side,Hot Dog,Western,1,153,13.4,10.3,,,0.7,0,
+47,Side,Spaghetti,Western,1,157,5.8,0.9,,,30.8,1,
+48,Side,Tasty Rice,Western,1,210,4.2,0.8,,,46.7,0,
+49,Side,Chicken Ham,Western,1,36,3.8,1.9,,,1,0,
+50,Side,Coleslaw,Western,1,68,0.7,4.7,,,4.9,9.4,
+51,Dish,Signature Trio Eggs Spinach Soup (Regular),Ramen,10,256,,,,,,14,
+52,Dish,Signature Trio Eggs Spinach Soup (Small Portion),Ramen,10,119,,,,,,0,
+53,Dish,Seafood Spinach Soup (Regular),Ramen,10,188,,,,,,1,
+54,Dish,Seafood Spinach Soup (Small Portion),Ramen,10,113,,,,,,0,
+55,Dish,Sliced Fish Spinach Soup (Regular),Ramen,10,224,,,,,,0,
+56,Dish,Sliced Fish Spinach Soup (Small Portion),Ramen,10,134,,,,,,0,
+57,Dish,Fried Fish Spinach Soup (Regular),Ramen,10,282,,,,,,0,
+58,Dish,Fried Fish Spinach Soup (Small Portion),Ramen,10,169,,,,,,0,
+59,Dish,Double Mixed Fish Spinach Soup (Regular),Ramen,10,257,,,,,,0,
+60,Dish,Double Mixed Fish Spinach Soup (Small Portion),Ramen,10,191,,,,,,0,
+61,Dish,Fresh Mushrooms with Ramen (Regular),Ramen,10,303,,,,,,5,
+62,Dish,Fresh Mushrooms with Ramen (Small Portion),Ramen,10,182,,,,,,3,
+63,Dish,Mala Dry Ramen w Chicken Cheeseballs,Ramen,10,676,,,,,,8,
+64,Dish,Mala Dry Ramen w Fuzhou Fishballs,Ramen,10,713,,,,,,10,
+65,Dish,Mala Beef Ramen Soup,Ramen,10,644,,,,,,7,
+66,Side,Egg (side),Ramen,10,28,,,,,,0,
+67,Side,Century Egg (side),Ramen,10,1,,,,,,0,
+68,Side,Salted Egg (side),Ramen,10,7,,,,,,0,
+69,Side,Wolfberry (side),Ramen,10,8,,,,,,1,
+70,Side,Spinach (side),Ramen,10,2,,,,,,0,
+71,Side,Minced Pork (side),Ramen,10,135,,,,,,0,
+72,Side,Sliced Fish (side),Ramen,10,59,,,,,,0,
+73,Side,Fried Fish (side),Ramen,10,117,,,,,,0,
+74,Side,Prawns (side),Ramen,10,55,,,,,,0,
+75,Side,Chicken Cheeseballs (side),Ramen,10,94,,,,,,5,
+76,Side,Fuzhou Fishballs (side),Ramen,10,93,,,,,,6,
+77,Side,Sliced Beef (side),Ramen,10,107,,,,,,0,
+78,Side,White Rice (side),Ramen,10,232,,,,,,0,
+79,Side,Thick Bee Hoon (side),Ramen,10,276,,,,,,0,
+80,Side,Thin Bee Hoon (side),Ramen,10,251,,,,,,0,
+81,Side,Brown Rice (side),Ramen,10,218,,,,,,0,
+82,Side,Koka Noodle (side),Ramen,10,286,,,,,,4,
+83,Side,Ee Mee (side),Ramen,10,377,,,,,,2,
+84,Side,Ramen (side),Ramen,10,262,,,,,,4,
+85,Ingredient,Mala Sauce (Non-Spicy Base),Mala,4,46,1.7,0.1,0,0.4,9.7,5.3,1006
+86,Ingredient,Coriander,Mala,4,0,0,0,0,0.1,0,0,1
+87,Ingredient,White Rice,Mala,4,237,4.7,0.8,0.2,0.7,52.6,0.2,8
+88,Ingredient,Sotong Ring,Mala,4,51,8.6,0.8,0.2,0,1.7,1.7,24
+89,Ingredient,Prawn,Mala,4,34,7.8,0.2,0.1,0,0,0,134
+90,Ingredient,Fish Slice,Mala,4,57,12.8,0.5,0.1,0,0.1,0.1,51
+91,Ingredient,Chicken Gizzard,Mala,4,45,8.5,1,0.3,0,0,0,33
+92,Ingredient,Beef Slice,Mala,4,109,11.8,6.9,3.3,0,0,0,32
+93,Ingredient,Shitake Mushroom,Mala,4,16,1,0.2,0,1.2,2,1.1,4
+94,Ingredient,King Oyster Mushroom,Mala,4,13,1.3,0.2,0,0.7,1.4,0.7,2
+95,Ingredient,Xiao Bai Cai,Mala,4,7,0.8,0.1,0,0.5,0.6,0.6,36
+96,Ingredient,Wintermelon,Mala,4,31,0.3,2.4,0.6,0.9,1.7,1,195
+97,Ingredient,Tomato,Mala,4,16,1,0.1,0,0.4,2.6,2.6,11
+98,Ingredient,Potato,Mala,4,45,1.5,0.1,0,1.1,8.6,0.4,3
+99,Ingredient,Lady's Finger,Mala,4,11.2,0.6,0,0,1.1,2.1,2.1,10.8
+100,Ingredient,Kang Kong,Mala,4,9,1.1,0.1,0,0.9,0.4,0,47
+101,Ingredient,Cucumber,Mala,4,20,0.3,0,0,0.3,1.9,1.9,7
+102,Ingredient,Cauliflower,Mala,4,15,2,0,0,1.4,3,2.9,35
+103,Ingredient,Cabbage,Mala,4,9,1.4,0.3,0,0,2.8,0,14
+104,Ingredient,Broccoli,Mala,4,12,1.3,0,0,1.2,0.9,0.9,4
+105,Ingredient,Brinjal,Mala,4,11,0.7,0,0,0.4,2.3,2.3,4
+106,Ingredient,Taugay,Mala,4,437,1.5,0.1,0,0.9,0.8,0.5,1
+107,Ingredient,Potato Starch Noodle,Mala,4,349,0,0,0,0,108.1,0,0
+108,Ingredient,Instant Noodle,Mala,4,170,8.1,11.7,5.9,0.6,52.9,2.4,85
+109,Ingredient,Taiwan Sausage,Mala,4,156,7.2,13,5.8,0,6.2,3.1,287
+110,Ingredient,Seaweed Chicken,Mala,4,82,7.5,12,2.5,1,4.9,1.4,307
+111,Ingredient,Saito Fish Cake,Mala,4,48,12.1,3,1.6,1.1,1.9,0.8,843
+112,Ingredient,Quail Egg,Mala,4,46,4,3.4,1.1,0,0.1,0.1,43
+113,Ingredient,Mushroom Ball,Mala,4,47,5.8,0.5,0,0,3.9,0,0
+114,Ingredient,Mini Fish Ball,Mala,4,210,6.9,1.3,0.2,0.5,1.8,0.6,243
+115,Ingredient,Luncheon Meat,Mala,4,107,6.2,19.3,7.4,0.5,2.8,0,559
+116,Ingredient,Mini Sausage,Mala,4,141,4.5,8.3,3.6,0,3.9,1.9,178
+117,Ingredient,Fish Ball (Fried),Mala,4,99,10.5,9.8,1.2,0.7,2.8,0.9,370
+118,Ingredient,Fish Tau Foo,Mala,4,135,4.8,5.8,0.8,0.7,7,2.8,304
+119,Ingredient,Cuttlefish Ball,Mala,4,21,8.5,7.1,2.8,1.5,9.4,1.5,537
+120,Ingredient,Cuttlefish,Mala,4,11,4.4,0.2,0,0,0.2,0,100
+121,Ingredient,Crabstick,Mala,4,100,1.2,0,0,0,0.6,0,16
+122,Ingredient,Crab Claw,Mala,4,64,3.8,4.3,2,0,11.6,1.9,383
+123,Ingredient,Crab Ball,Mala,4,42,5.8,2,0.6,0.9,5.8,1.5,453
+124,Ingredient,Chickuwa,Mala,4,95,5.5,0.5,0,0,3.2,0,377
+125,Ingredient,Chicken Hotdog,Mala,4,122,5.5,7,1.9,0.5,2.4,0.8,450
+126,Ingredient,Cheese Tofu,Mala,4,33,6.4,9.1,3.6,0.7,3.7,2.1,486
+127,Ingredient,Bermuda Triangle Tofu (Taupok),Mala,4,12,3.3,1.5,0.2,0.2,1.5,0.6,3
+128,Ingredient,White Radish,Mala,4,126,0.6,0.1,0,0.8,2.2,2.2,47
+129,Ingredient,Peanut,Mala,4,170.5,7.4,14.1,2.1,2.5,2.7,1.5,0.3
+130,Ingredient,Thick Beehoon,Mala,4,126.1,2.3,0.4,0.1,0.4,28.3,0,7
+131,Ingredient,Tau Kwa,Mala,4,50,5,2.3,0.4,0.2,2.3,1,4
+132,Ingredient,Lotus Root,Mala,4,51,1.2,0.1,0,2.4,12.3,0.4,34
+133,Ingredient,Kelp,Mala,4,27,1.8,0.4,0.1,0.3,5.2,0.4,526
+134,Ingredient,Enoki Mushroom,Mala,4,13,0.9,0.1,0,0.9,1.8,0.1,1
+135,Ingredient,Black Fungus,Mala,4,19,1.3,0.2,0,2.3,3,0,8
+136,Ingredient,Beancurd Skin (Non-Fried),Mala,4,77,8.2,2.9,0.5,3.4,0.5,0.5,0
+137,Ingredient,Beancurd Skin (Fried),Mala,4,76,4.4,5.5,0.7,1.8,0.3,0.3,0
+138,Ingredient,Mala Sauce (Very Spicy Base),Mala,4,257,0.6,27.7,4.8,1,2,0.5,2
+139,Ingredient,Mala Sauce (Spicy Base),Mala,4,191,0.6,20.2,3.5,1,2,0.5,2
+140,Ingredient,Mala Sauce (Slightly Spicy Base),Mala,4,95,0.3,10.1,1.7,0.5,1,0.2,1
+141,Dish,White Chicken Rice,Chicken Rice,12,533,19.5,17.3,5.7,1.6,74.6,6,5.0
+142,Dish,Char Siew Rice,Chicken Rice,12,697,21.9,29.6,11.2,1.6,86.1,16.7,3.7
+143,Dish,Roasted Pork Rice,Chicken Rice,12,680,22,29.6,11.1,3.1,80.3,5.6,4.5
+144,Dish,Roasted Chicken Noodles (Egg Noodles) - Regular,Chicken Rice,12,320,17.1,7.7,2,2.9,43.3,2.3,1.6
+145,Dish,Roasted Chicken Noodles (Egg Noodles) - Large,Chicken Rice,12,388,25.3,11.5,3.2,3,43.6,2.3,1.7
+146,Dish,Roasted Chicken Noodles (Hor Fun) - Regular,Chicken Rice,12,341,12.8,6.9,2.5,1.5,56.7,1.7,1.6
+147,Dish,Roasted Chicken Noodles (Hor Fun) - Large,Chicken Rice,12,21,10.7,3.7,1.7,57,1.7,1.7,
+148,Dish,White Chicken Noodles (Egg Noodles) - Regular,Chicken Rice,12,307,15.2,7.5,2.2,2.7,42.4,1.7,2.6
+149,Dish,White Chicken Noodles (Egg Noodles) - Large,Chicken Rice,12,365,21.3,11.1,3.6,2.7,42.4,1.7,2.6
+150,Dish,White Chicken Noodles (Hor Fun) - Regular,Chicken Rice,12,328,10.9,6.7,2.7,1.4,55.8,1,2.6
+151,Dish,White Chicken Noodles (Hor Fun) - Large,Chicken Rice,12,386,17,10.4,4.1,1.4,55.8,1,2.7
+152,Dish,Char Siew Noodles (Egg Noodles) - Regular,Chicken Rice,12,410,16.4,13.6,5,2.7,53.5,12.4,1.3
+153,Dish,Char Siew Noodles (Egg Noodles) - Large,Chicken Rice,12,529,23.7,23.4,9.1,2.7,53.8,12.4,1.4
+154,Dish,Char Siew Noodles (Hor Fun) - Regular,Chicken Rice,12,431,12.1,12.9,5.5,1.4,66.9,11.7,1.3
+155,Dish,Char Siew Noodles (Hor Fun) - Large,Chicken Rice,12,550,19.4,22.7,9.6,1.4,67.2,11.7,1.4
+156,Dish,Roasted Pork Noodles (Egg Noodles) - Regular,Chicken Rice,12,395,16.6,13.9,5,4.2,47.8,1.4,2.0
+157,Dish,Roasted Pork Noodles (Egg Noodles) - Large,Chicken Rice,12,511,23.7,23.4,9.1,4.2,48.1,1.4,2.1
+158,Dish,Roasted Pork Noodles (Hor Fun) - Regular,Chicken Rice,12,416,12.3,13.1,5.5,2.8,61.2,0.7,2.0
+159,Dish,Roasted Pork Noodles (Hor Fun) - Large,Chicken Rice,12,533,19.4,22.7,9.6,2.8,61.4,0.7,2.2
+160,Dish,Roasted Chicken Rice + Veg + Half Egg Set Meal,Chicken Rice,12,604,28.1,21.2,5.7,2.4,75.4,6.1,4.2
+161,Dish,White Chicken Rice + Veg + Half Egg Set Meal,Chicken Rice,12,582,24.1,20.9,6.1,2.1,74.2,5.5,5.2
+162,Dish,Char Siew Rice + Veg + Half Egg Set Meal,Chicken Rice,12,746,26.5,33.2,11.6,2.1,85.6,16.2,3.9
+163,Dish,Roasted Pork Rice + Veg + Half Egg Set Meal,Chicken Rice,12,728,26.5,33.2,11.6,3.6,79.9,5.1,4.7
+164,Dish,Curry Chicken Bee Hoon,Chicken Rice,12,744,15.8,34.7,26.9,4.9,90.9,30,6.3
+165,Dish,Curry Chicken Noodles,Chicken Rice,12,777,21.7,37.8,27.6,6,85.8,28.7,6.3
+166,Dish,Chicken Shredded Porridge,Chicken Rice,12,8.3,3.8,1.4,0.2,20.6,0.9,2.2,
+167,Dish,Roasted Pork Rice Soup,Chicken Rice,12,9.7,10.2,4.2,1.7,26,0.6,1.6,
+168,Side,Roasted Chicken,Chicken Rice,12,8.2,3.9,1.2,0.2,1.2,1,0.7,
+169,Side,White Chicken,Chicken Rice,12,6.3,3.7,1.4,0,0.3,0.3,1.7,
+170,Side,Char Siew,Chicken Rice,12,7.5,9.8,4.2,0,11.4,11,0.4,
+171,Side,Roasted Pork,Chicken Rice,12,264,14.9,19.6,8.2,1.5,6,0,1.3
+172,Side,Veg 1 (Cai Xin),Chicken Rice,12,0.8,0.1,0,0.7,0.4,0.5,0.3,
+173,Side,Veg 2 (Nonya Chap Chye),Chicken Rice,12,2.1,1.1,0.2,0.6,1.3,0.7,0.2,
+174,Side,Braised Egg,Chicken Rice,12,8,7,0.9,0,0.6,0.6,0.3,
+175,Side,Sausage,Chicken Rice,12,6.2,9.6,3.8,0.4,2.4,0.5,0.3,
+176,Side,Liver + Gizzards,Chicken Rice,12,17.5,2.6,0.8,0,0.3,0,0.1,
+177,Side,Roasted Chicken (1 Pax),Chicken Rice,12,16.4,7.7,2.4,0.3,1.5,1,0.8,
+178,Side,Roasted Chicken (2 Pax),Chicken Rice,12,32.8,15.4,4.7,0.7,3,2.1,1.7,
+179,Side,Roasted Chicken (3 Pax),Chicken Rice,12,49.3,23.1,7.1,1,4.5,3.1,2.5,
+180,Side,White Chicken (1 Pax),Chicken Rice,12,12.5,7.4,2.8,0,0.3,0.3,1.7,
+181,Side,White Chicken (2 Pax),Chicken Rice,12,24.9,14.7,5.6,0,0.6,0.7,3.4,
+182,Side,White Chicken (3 Pax),Chicken Rice,12,37.4,22.1,8.4,0,0.8,1,5.2,
+183,Side,Plain Chicken Rice,Chicken Rice,12,411,6.9,10,2.9,1.4,73.4,4.7,3.3
+184,Side,White Rice,Chicken Rice,12,5.9,1.1,0.2,0.8,65.8,0.2,11,
diff --git a/data/createFoodData.py b/data/createFoodData.py
new file mode 100644
index 0000000000..6ec339af54
--- /dev/null
+++ b/data/createFoodData.py
@@ -0,0 +1,17 @@
+if __name__ == "__main__":
+ TAB = " "
+
+ with open("FoodData.csv", "r") as data_file, open("FoodData.java", "w") as write_file:
+ write_file.write("package seedu.database;\n\n")
+ write_file.write("public final class FoodData {\n")
+ write_file.write(TAB +"private static final String[] foodData = {\n")
+ foods = data_file.readlines()
+ for food in foods:
+ food = food.replace('\n', '')
+ food_1, food_2 = food[:len(food)//2], food[len(food)//2:]
+ write_file.write(TAB + TAB + f'"{food_1}" +\n' + TAB + TAB + TAB + f'"{food_2}",\n')
+ write_file.write(TAB + "};\n\n")
+ write_file.write(TAB + "public static String[] getFoodData() {\n")
+ write_file.write(TAB + TAB + "return foodData;\n")
+ write_file.write(TAB + "}\n")
+ write_file.write("}\n")
diff --git a/data/exerciseData.csv b/data/exerciseData.csv
new file mode 100644
index 0000000000..886eb67b91
--- /dev/null
+++ b/data/exerciseData.csv
@@ -0,0 +1,2 @@
+Exercise Name,Exercise Description,Calories Burnt
+Running,5km,400.0,1/1/2023
diff --git a/data/mealData.csv b/data/mealData.csv
new file mode 100644
index 0000000000..564d3c7662
--- /dev/null
+++ b/data/mealData.csv
@@ -0,0 +1,2 @@
+Date,Foods,Meal Type
+1/1/2023,0-1-2-0-1-2-0-1-2,Breakfast
diff --git a/data/pdfs/Chicken-Rice.pdf b/data/pdfs/Chicken-Rice.pdf
new file mode 100644
index 0000000000..007a49db9f
Binary files /dev/null and b/data/pdfs/Chicken-Rice.pdf differ
diff --git a/data/pdfs/Ramen-Fish-Soup.pdf b/data/pdfs/Ramen-Fish-Soup.pdf
new file mode 100644
index 0000000000..1c67b37f39
Binary files /dev/null and b/data/pdfs/Ramen-Fish-Soup.pdf differ
diff --git a/data/pdfs/Well-Mala-Hotpot.pdf b/data/pdfs/Well-Mala-Hotpot.pdf
new file mode 100644
index 0000000000..e686e365d4
Binary files /dev/null and b/data/pdfs/Well-Mala-Hotpot.pdf differ
diff --git a/data/pdfs/Western-TE-1.pdf b/data/pdfs/Western-TE-1.pdf
new file mode 100644
index 0000000000..1d906c2d12
Binary files /dev/null and b/data/pdfs/Western-TE-1.pdf differ
diff --git a/data/userData.csv b/data/userData.csv
new file mode 100644
index 0000000000..99082799e3
--- /dev/null
+++ b/data/userData.csv
@@ -0,0 +1,2 @@
+Name,Weight,Height,Age,Gender,TargetWeight
+Marucs ,60.0,175.0,21,male,50.0
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..c40e2a7c84 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,9 +1,10 @@
# About us
-Display | Name | Github Profile | Portfolio
---------|:----:|:--------------:|:---------:
- | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+Display | Name | Github Profile | Portfolio
+--------|:-------------:|:----------------------------------------:|:---------:
+ | Hoo Teng Juan | [Github](https://github.com/) | [Portfolio](./team/tj-hoo.md)
+ | Koh Jing Jie Marcus | [Github](https://github.com/) | [Portfolio](./team/koh-jing-jie-marcus.md)
+ | Hamada Masahiro | [Github](https://github.com/) | [Portfolio](./team/masahiro21.md)
+ | Mustafa Anis Hussain| [Github](https://github.com/MustafaAH10) | [Portfolio](./team/mustafaah10.md)
+ | Koh Ming En | [Github](https://github.com/MingEn82) | [Portfolio](./team/mingen82.md)
+
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 64e1f0ed2b..cc94978236 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,38 +1,726 @@
# Developer Guide
-## Acknowledgements
+- [Acknowledgements](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#acknowledgements)
+- [Design](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design)
+ - [Architecture](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#architecture)
+ - [UI Component](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#ui-component)
+ - [Command Component](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#command-component)
+ - [Storage Component](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#storage-component)
+ - [Interfaces](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#interfaces)
+- [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation)
+ - [Add meal feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#add-meal-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-1)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations)
+ - [List feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#list-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-2)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-1)
+ - [Delete feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#delete-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-3)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-2)
+ - [View feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#view-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-4)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-3)
+ - [Update feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#update-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-5)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-4)
+ - [Nutrition feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#nutrition-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-6)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-5)
+ - [Filter feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#filter-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-7)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-6)
+ - [Exercise feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#exercise-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-8)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-7)
+ - [Track feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#track-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-9)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-8)
+ - [Examples feature](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#examples-feature)
+ - [Implementation](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#implementation-10)
+ - [Design considerations:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#design-considerations-9)
+- [Appendix: Requirements](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#appendix-requirements)
+ - [Product Scope](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#product-scope)
+ - [Target user profile:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#target-user-profile)
+ - [Value proposition:](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#value-proposition)
+ - [User Stories](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#user-stories)
+ - [Non-Functional Requirements](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#non-functional-requirements)
+ - [Glossary](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#glossary)
+ - [Instructions for manual testing](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#instructions-for-manual-testing)
+ - [Launch and Shutdown](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#launch-and-shutdown)
+ - [View user profile](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#view-user-profile)
+ - [Update user profile](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#update-user-profile)
+ - [Adding a meal](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#adding-a-meal)
+ - [List meals or foods in database meals added](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#list-or-foods-in-database-meals-added)
+ - [Deleting a meal](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#deleting-a-meal)
+ - [Filtering foods based on calories](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#filter-foods-based-on-calories)
+ - [Find nutrition of a food](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#find-nutrition-of-a-food)
+ - [Add a exercise](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#add-a-exericse)
+ - [Track calorie intake](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#track-calorie-intake)
+ - [See examples of meal or exercise](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#see-examples-of-meal-or-exercise)
+ - [See list of available commands](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#see-list-of-available-commands)
+ - [Exiting the application](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#exiting-the-program)
+ - [Saving data](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#saving-data)
+ - [Dealing with missing/corrupted data files](https://ay2223s2-cs2113-w15-1.github.io/tp/DeveloperGuide.html#dealing-with-missingcorrupted-data-files)
-{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+---
-## Design & implementation
+### Acknowledgements
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+1. Command, Parser and UI java files are adapted from one of our group member's [Duke Project](https://github.com/MingEn82/ip)
+2. The source for the nutritional data is from the following links, [Western](https://uci.nus.edu.sg/oca/wp-content/uploads/sites/9/2022/10/Western-TE-1.pdf), [Nasi Padang](https://uci.nus.edu.sg/oca/wp-content/uploads/sites/9/2023/03/Nasi-Padang-TE.pdf), [Taiwanese](https://uci.nus.edu.sg/oca/wp-content/uploads/sites/9/2023/03/Taiwanese-TE.pdf), and [Mala](https://uci.nus.edu.sg/oca/wp-content/uploads/sites/9/2023/03/Mala-TE.pdf).
+---
+
+## Design
+
+---
+
+### Architecture
+
+
+
+**Main Components of LifeTracker**
+
+`LifeTracker` is where users will access the application from. It is responsible for:
+
+- At app launch: Initialise the Databases and UI classes
+- At app closure: Saves all updated data to databases
+
+The rest of the Application consists of three components:
+
+- `UI`: Reponsible for I/O between user and application
+- `Command`: Handles execution of user inputs
+- `Storage`: Stores information of the user and meals eaten
+
+---
+
+### UI Component
+
+API: ui.java
+
+
+
+The UI is made up of five classes, `GeneralUi`, `CalorieUi`, `ExampleUi`, `ExerciseUi` and `WeightUi`, and together,
+they improve on the accessibility of the application.
+
+The `UI` component,
+
+- Displays what are the possible inputs at any one time
+- Allows the user to check that a value added is correct
+- Informs the user whenever there is an invalid input
+
+### Command Component
+
+API: commands.java
+
+
+
+How the `Command` component works:
+
+1. When a user first enters something into the CLI, the `CommandParser` subclass from the `Parser` class is used to parse the user command.
+2. Based on the results of the parsing, a specific command object is created (e.g. `AddMealCommand`) which inherits from the abstract `Command` and its `execute` method.
+3. Every command uses the `execute` method differently according to its needs. (For example, `AddMealCommand` would require saving of meals to a single database, while
+ `TrackCalorieCommand` would require reading from various databases for the desired result)
+4. The command can also communicate with the various storage components when it is executed, such as saving and loading of user, meals, foods, exercise data.
+5. In addition, the command also communicates with the UI Component to display the results of the execution of the command back to the user.
+6. In the case of command execution failures, an Exception Object (more precisely, an object of one of its subclasses, e.g. LifeTrackerException) is thrown.
+
+
+
+### Storage Component
+
+API: storage.java
+
+
+
+The `Storage` is the base class which all `Storage` components inherit from. There are currently four storages:
+
+1. `FoodStorage`: For parsing and storing all of the foods supported by _LifeTracker_
+2. `UserStorage`: For storing the user's profile
+3. `MealStorage`: For storing the meals that the user ate
+4. `ExerciseStorage`: For storing the exercises that the user did
+
+#### Interfaces
+
+To ensure that each `Storage` component only implements methods for writing and reading when needed, we created two interfaces
+
+1. `FileReadable`: Has `load()` method for `Storage` component to be able to read from a database
+2. `FileWritable`: Has `write()` method for `Storage` component to be able to write to a database
+
+For example, `FoodStorage` is not meant to be edited by user, hence it does not implement `FileWritable`
+
+# Implementation
+
+This section describes some noteworthy details on how certain features are implemented.
+
+## Add meal feature
+
+### Implementation
+
+The proposed mechanism for adding a meal is facilitated by `AddMealCommand`. It extends `Command` and overrides the
+`execute` method in the `Command` class.
+
+In this command, there are 2 ways for the user to add a meal to storage.
+
+1. Using a one-line command in their CLI in the format `add [DATE] /on [MEAL_TYPE] /type [FOOD_INDEX] /foods`
+2. Typing `add` into the CLI and following the printed prompts to enter the date in the specified format, type of meal and specific food.
+
+
+
+Step 1. As seen from the sequence diagram above, when the AddMealCommand is executed via the `execute` method in
+LifeTracker, the user's input is first parsed to determine how he/she wants to input it. Either method sets the food,
+date and meal type features necessary to create a new meal.
+
+Step 2. The constructor for the `Meal` class is called which instantiates a new instance of Meal using the
+parameters provided.
+
+Step 3. `mealStorage` saves the meal to the database and then `ui` prints out the confirmation of the meal added.
+
+### Design considerations
+
+#### Aspect: How to add meals
+
+- Alternative 1 (current choice): Use a one-line command for the CLI.
+ - Pros: Faster to input for experienced users.
+ - Cons: Format might be difficult for new users.
+- Alternative 2 (current choice): Follow printed prompts for data.
+ - Pros: Usage would be easier for new users.
+ - Cons: Slower to input for experienced users.
+
+Therefore, our group chose to implement both ways.
+
+## List feature
+
+### Implementation
+
+The proposed mechanism for listing stored foods, meals and exercises is facilitated by `ListCommand`. It extends `Command` and overrides the `execute` method in the `Command` class.
+
+Step 1: The user will input either `list foods`, `list meals`, `list exercises` based on which information the user wants to retrieve.
+
+Step 2: Based the input, `ListCommand` will call either `printAllFoods`, `printAllMeals`, or `printAllExercises` method of the `ui` object.
+
+Step 3: The `ui` will retrieve the relevant information from the storage and print out their details.
+
+
+
+### Design Considerations
+
+#### Aspect: How to list all the foods in the database, and the meals and the exercises of the user
+
+- Alternative 1 (current choice): List information based on input command.
+ - Pros: More concise, no unnecessary information.
+ - Cons: Slightly slower to input command.
+- Alternative 2: List all meals, exercises, and foods at once.
+ - Pros: Slightly faster to input command.
+ - Cons: Lots of unnecessary information would be displayed.
+
+## Delete feature
+
+### Implementation
+
+In order to delete a meal or exercise from their meal history, a user has to type either `delete /meal [MEAL_INDEX]` or `delete /exercise [EXERCISE_INDEX]`into the CLI. Users can see
+which meal or exercise they want to delete by viewing the respective csv files or using the list command.
+
+
+
+In the above implementation, DeleteMealCommand parses the user input to obtain the index to delete and proceeds to
+delete it via the method from mealStorage() and prints out the deleted meal to the user.
+
+### Design considerations
+
+#### Aspect: How to delete meals
+
+- Alternative 1 (current choice): Delete items from list based on index.
+ - Pros: Does not needlessly delete wanted items.
+ - Cons: Need to get the index from `list` command first.
+- Alternative 2: Clears all data.
+ - Pros: Faster input, no need for `list` command to retrieve index.
+ - Cons: Deletes data that user might want to keep.
+
+## View feature
+
+### Implementation
+
+The proposed view mechanism is facilitated by `ViewUserCommand`. It extends `Command` and overrides the
+`execute` method in the `Command` class.
+
+It stores the user's data internally as `user` and the meals consumed by the user as `meals`. It also
+initializes the UI for calories as `calorieUI`.
+
+Given below is an example usage scenario and how the view feature behaves at each step.
+
+Step 1. The user launches the application and calls the `view /[fieldname]` command. The `ViewUserCommand` will be
+initialized with the current user and meal storage state. `user` and `meals` will point to the user storage
+and meal state respectively.
+
+The method `parseCommand()` is then called to check and ensure that the `/[fieldname]`
+provided is valid information that can be viewed as well as the number of arguments provided is correct.
+
+
+
+Step 2. Based on the `/[fieldname]` that the user provided the different getter methods will be called in the entity
+`User` to return the appropriate information. In this case, the user has input the command `view /weight` which will
+call the getter method `getWeight()` in the entity `User` to return the current weight of the user and initializes the
+variable `weight` with that value.
+
+If the user's weight is equal to 0.0 then the method `printFieldNotStored()` in `GeneralUi` will be called to notify the
+user that that specific information has not been stored yet. Otherwise, the method `printWeight()` will be called to
+print out the weight of the user.
+
+
+
+For name, weight, height, age and gender there will a check done to see whether the field has information stored in it.
+If the fields are empty the user will be alerted and asked to update it.
+
+### Design considerations
+
+#### Aspect: How to view user data
+
+- Alternative 1 (current choice): Use a one-line for the CLI
+ - Pros: Faster to input for experienced users.
+ - Cons: Format might be difficult for new users.
+- Alternative 2 : Follow printed prompts for data.
+ - Pros: Usage would be easier for new users.
+ - Cons: Slower to input for experienced users.
+
+## Update feature
+
+### Implementation
+
+The proposed update mechanism is facilitated by `UpdateUserCommand`. It extends `Command` and overrides the `execute` method in the `Command` class.
+
+It stores the user's data internally as `user` and the meals consumed by the user as `meals`. It also
+initializes the UI for calories as `calorieUI`.
+
+Given below is an example usage scenario and how the view feature behaves at each step.
+
+It stores the user's data internally as `user`.
+
+Step 1. The user launches the application and calls the `update /[fieldname] [newInfo]` command. The `UpdateUserCommand` class will be
+initialized with the current user storage state. `user` will point to the user storage.
+
+The method `parseCommand()` is then called to check and ensure that the `/[fieldname]`
+provided is valid information that can be updated as well as the number of arguments provided is correct.
+
+
+
+Step 2. Based on the `/[fieldname]` that the user provided the different setter methods will be called in the entity
+`User` to update the appropriate information. In this case, the user has input the command `update /weight [newInfo]` which will
+call the setter method `setWeight()` in the entity `User` to return the set the current weight of the user to the newly
+updated one.
+
+The caloric limit is then recalculated with the calling of `calculateCaloricNeeds()` static method in User
+based on the new information provided and the caloric limit in `user` is then updated with `setCaloricLimit`.
+
+The new weight difference between the current weight and target weight is also shown with the calling of the static
+method `displayNewWeightDifference()`.
+
+The method `updateUser()` in userStorage is then called to update the user's detail in the storage.
+
+
+
+For updates made to weight, height, age and gender, there will be a call to the static method `calculateCaloricNeeds()`
+in the class User. This is done to ensure that with every new change, the caloric limit is recalculated. This recalculated
+caloric limit is will then be the new limit and the method `setCaloricLimit()` is called to update the user's daily caloric
+limit to the new one.
+
+For updates made to weight and targetWeight, there will be a call to the static method `displayNewWeightDifference()` and
+`displayNewTargetWeightDifference()` respectively to show the new difference between target weight and current weight of the user.
+
+At the end of every update, the userStorage will be updated accordingly.
+
+### Design considerations
+
+#### Aspect: How to update user data
+
+- Alternative 1 (current choice): Use a one-line for the CLI
+ - Pros: Faster to input for experienced users.
+ - Cons: Format might be difficult for new users.
+- Alternative 2 : Follow printed prompts for data.
+ - Pros: Usage would be easier for new users.
+ - Cons: Slower to input for experienced users.
+
+## Nutrition feature
+
+### Implementation
+
+The proposed update mechanism is facilitated by `NutritionCommand`. It extends `Command` and overrides the `execute` method in the `Command` class.
+
+Step 1: The user inputs `nutrition` into the command line.
+
+Step 2: The user will then be prompted to enter what food they would like to see the nutrition for.
+
+Step 3: A list of type `food` will then be created called `filteredFoods`, populated by foods from `foodStorage` that contains the user's input.
+
+Step 4: The list will then be displayed to the user, who can pick which food by its index.
+
+Step 5: The nutritional information for that food will then be displayed.
+
+
+
+### Design considerations
+
+#### Aspect: How to view nutritional information for foods
+
+- Alternative 1 (current choice): Follow prompts for information.
+ - Pros: User can get accurate information about the food.
+ - Cons: Slower input.
+- Alternative 2: Use a one line command for the CLI.
+ - Pros: Faster input.
+ - Cons: User might input food that's not in the database and therefore there is no nutritional information available.
+
+## Filter feature
+
+### Implementation
+
+This proposed mechanism for allowing the user to search for meals with a filter, facilitated by `FilterCaloriesCommand`. It extends `Command` and overrides the `execute` method in the `Command` class.
+
+Step 1. The user calls the `filter` command, specifying a particular calorie range through a upper and lower bound.
+
+Step 2. `FilterCaloriesCommand` will parse the lower and upper bound from the input.
+
+Step 3. `FilterCaloriesCommand` will then retrieve the meals that fit within that range from `FoodStorage`.
+
+Step 4. `FilterCaloiresCommand` will then print out the meals that has been filtered based on the lower and upper bound.
+
+
+
+### Design considerations
+
+#### Aspect: How to find foods from the database based on calories
+
+- Alternative 1 (current choice): Use a one-line for the CLI
+ - Pros: Faster to input for experienced users.
+ - Cons: Format might be difficult for new users.
+- Alternative 2 : Follow printed prompts for data.
+ - Pros: Usage would be easier for new users.
+ - Cons: Slower to input for experienced users.
+
+## Exercise feature
+
+### Implementation
+
+The proposed update mechanism is facilitated by `AddExerciseCommand`. It extends `Command` and overrides the `execute` method in the `Command` class.
+
+### Design considerations
+
+#### Aspect: How to add exercises
+
+- Alternative 1 (current choice): Use a one-line command for the CLI.
+ - Pros: Faster to input for experienced users.
+ - Cons: Format might be difficult for new users.
+- Alternative 2 (current choice): Follow printed prompts for data.
+ - Pros: Usage would be easier for new users.
+ - Cons: Slower to input for experienced users.
+
+## Track feature
+
+### Implementation
+
+The mechanism for tracking net calorie intake is facilitated by `TrackCalorieCommand`. It extends `Command` and overrides the `execute` method in the `Command` class.
+
+Step 1: The user will either input `track all` to view all history or `track /start [DATE] /end [DATE]` to filter the results based on dates
+Step 2a: Based the input, `TrackCalorieCommand` will either parse the start date from user input or set the start date to the earliest meal or exercise added by calling `getStartingDate`.
+Step 2b: Based the input, `TrackCalorieCommand` will either parse the end date from user input or set the end date to the latest meal or exercise added by calling `getEndingDate`.
+Step 3: `TrackCalorieCommand` will retrieve the meals and exercises filtered from the starting date by calling `getMealByDate` and `getExerciseByDate` respectively.
+Step 4: `TrackCalorieCommand` will iterate through the filtered meals and exercises day by day and print out the net calorie intake for each day.
+
+
+
+### Design considerations
+
+#### Aspect: How to track the calories of the user
+
+- Alternative 1 (current choice): Use a one-line command for the CLI.
+ - Pros: Faster to input for experienced users.
+ - Cons: Format might be difficult for new users.
+- Alternative 2 (current choice): Follow printed prompts for data.
+ - Pros: Usage would be easier for new users.
+ - Cons: Slower to input for experienced users.
+
+## Examples feature
+
+### Implementation
+
+The proposed mechanism for displaying examples of exercises and meals is facilitated by `ExamplesCommand`. It extends `Command` and overrides
+the `execute` method in the `Command` class.
+
+Step 1. The user calls the `examples` command, specifying whether they wish for `meal` or `exercise` to be displayed.
+
+Step 2. `ExamplesCommand` will parse the user input.
+
+Step 3. `ExamplesCommand` will retrieve either the examples of `meal` or examples of `exercise` based on the user input, from the `ExampleData` database.
+
+Step 4. The examples of `meal` or `exercise` will then be printed out and displayed for the user.
+
+
+
+### Design considerations
+
+#### Aspect: How to list examples of exercises and meals
+
+- Alternative 1 (current choice): List examples based on input command.
+ - Pros: More concise, no unnecessary information.
+ - Cons: Slightly slower to input command.
+- Alternative 2: List all examples.
+ - Pros: Slightly faster to input command.
+ - Cons: Lots of unnecessary information would be displayed.
+
+# Appendix: Requirements
## Product scope
+
### Target user profile
-{Describe the target user profile}
+- Is an NUS student
+- Looking to lose/maintain their weight
+- Looking to make healthier choices in terms of food
+- Can type fast
+- Prefers typing to mouse interactions
+- Is reasonably comfortable using CLI apps
### Value proposition
-{Describe the value proposition: what problem does it solve?}
+For individuals trying to lose weight, managing their daily caloric intake is crucial. However, many may find it
+hard to track and manage their calories. _LifeTracker_ allows users to easily automate the tracking of their calories
+and keep a record of their daily caloric intake.
+
+_LifeTracker_ can also keep track of the exercises that users have done and factor it in to their daily calories lost. This allows
+the user to keep track of their net calorie gain on a daily basis.
+
+### User Stories
+
+
+
Version
+
As a ...
+
I want to ...
+
So that I can ...
+
+
v1.0
+
new user
+
see usage instructions
+
refer to them when I forget how to use the application
+
+
v1.0
+
user
+
calculate my caloric needs based on my height and weight
+
lead a healthy lifestyle within my caloric needs
+
+
v1.0
+
user
+
add a meal
+
keep track of the food I have eaten on a particular day
+
+
v1.0
+
user
+
delete a meal
+
remove a meal if I entered it in wrongly
-## User Stories
+
v1.0
+
user
+
view my previous meals
+
track the calories of each meal
-|Version| As a ... | I want to ... | So that I can ...|
-|--------|----------|---------------|------------------|
-|v1.0|new user|see usage instructions|refer to them when I forget how to use the application|
-|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list|
+
v1.0
+
user
+
key in my weight on a daily basis
+
keep track of my weight loss/gain
+
+
v1.0
+
user
+
see the amount of calories left I have in the day
+
not exceed my daily caloric limit
+
+
v2.0
+
user
+
search for a type of food and view its nutritional contents
+
make a more informed choice about what to eat
+
+
v2.0
+
user
+
search for meals within a specific calorie range
+
decide which meal to consume
+
+
v2.0
+
user
+
enter the type and duration of exercise I have completed
+
keep better track of my physical activies
+
+
v2.1
+
user
+
be inspired to work out
+
stay in shape
+
+
v2.1
+
user
+
search based on a filter
+
have results that better suit my needs
+
## Non-Functional Requirements
-{Give non-functional requirements}
+1. Should work on any mainstream OS as long as it has Java `11` installed.
+2. This app is meant for a single user and will not be able to accurately keep track of the meals, personal information and caloric requirements for different people.
+3. This app is targeted at users who would prefer typing over other input types. Ideally they would have an above-average typing speed and therefore prefer CLI over other interfaces.
## Glossary
-* *glossary item* - Definition
+- _glossary item_ - Definition
+
+___
## Instructions for manual testing
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
+Given below are instructions on how to test the application by yourself manually. You can use these instructions as a starting point for your testing.
+
+### Launch and Shutdown
+
+- Initial launch
+ - Download the jar file from the release page and copy the file into an empty folder
+ - Open a cmd terminal and redirect or cd into the folder the jar file was downloaded into.
+ - Type "java -jar tp.jar" and press enter to run the file.
+
+- Shutdown
+ - Type `bye` into the command line and press enter to exit the application.
+
+### View user profile
+
+Test case: `view /weight`
+
+Expected: Weight information will be shown.
+
+Test case: `view /null`
+
+Expected: "Oops! Invalid field name /null for command view" message will be shown as /null fieldName does not exist.
+
+### Update user profile
+
+Test case: `update /weight 60`
+
+Expected: Amount of weight needed to lose to hit target weight message as well as user settings successfully updated
+message will be shown
+
+Test case: `update /null 60`
+
+Expected: "Oops! Invalid field name /null for command view" message will be shown as /null fieldName does not exist.
+
+Test case: `update /weight 800`
+
+Expected: "800 kg is an impossible value for /weight please enter a valid one!" message is shown as a weight of 800 kg
+is impossible to attain.
+
+Test case: `update /weight abc`
+
+Expected: "abc is not of valid format for /weight please try again!" message as weight only accepts numerical values.
+
+### Adding a meal
+
+Test case: `add /on 3/3/2023 /type Lunch /foods Spaghetti, Alfredo (Small)`
+
+Expected: Spaghetti and Alfredo are added to the list. Details of the food such as calories are shown in the status message.
+
+Test case: `add`
+
+Expected: Application will then ask for date of meal, type of meal, and food, and will then display the foods in the database containing the food that was added. Food is then added to the list and details of the food such as calories are shown in the status message.
+
+Test case: `add /on dummy /type dummy /foods dummy`
+
+Expected: No food is added. Error details are shown in the status message, such as "_dummy_ is not a valid date", "Invalid meal type" or "no food found with _dummy_".
+
+### List meals or foods in database meals added
+
+Test case: `list meals`
+
+Expected: A list of meals eaten today would be displayed.
+
+Test case: `list foods`
+
+Expected: A list of all foods in the databse would be displayed.
+
+Test case: `list dummy`
+
+Expected: An error message would be displayed.
+
+### Deleting a meal
+
+Prerequisite: List all meals eaten using the list command. At least 1 meal in the list.
+
+Test case: `delete 1`
+
+Expected: First meal is deleted from the list. Details of the deleted meal are shown in the status message.
+
+Test case: `delete 0`
+
+Expected: No meal is deleted. Error details shown in the status message.
+
+Other incorrect delete commands to try: delete, delete x, (where x is larger than the list size)
+
+Expected: Similar to previous.
+
+### Filter foods based on calories
+
+Test case: `filter 400 600`
+
+Expected: A list of all meals within that range will be displayed
+
+Test case: `filter 400 300`
+
+Expected: An error message will be displayed
+
+### Find nutrition of a food
+
+Prerequisite: Food needs to exist in the database.
+
+Test case: `nutrition`
+
+Expected: Prompt will ask you to enter the food you would like to see the nutrition for. A menu displaying all foods which contain the food entered will appear, which you can then enter the index to see the specific food.
+
+### Add a exericse
+
+Test case: `exercise /type running /description 5km /calories 500 /on 5/5/2023`
+
+Expected: An exercise of running for 5km that burnt 500 calories on 5/5/2023 is added.
+
+Test case: `exercise /type dummy /description dummy /calories dummy /on dummy`
+
+Expected: No exercise is added, error message will be displayed.
+
+### Track calorie intake
+
+Test case: `track /start 5/5/2023 /end 6/5/2023`
+
+Expected: Calories consumed, calories burnt and net calories for 5/5/2023 and 6/5/2023 would be displayed in the status message.
+
+Test case: `track /start dummy /end dummy`
+
+Expected: Error message will be dislayed.
+
+### See examples of meal or exercise
+
+Test case: `examples exercise`
+
+Expected: Examples of different types of exercise will be displayed
+
+Test case: `examples weight`
+
+Expected: An error message will be displayed
+
+### See list of available commands
+
+Test case: `help`
+
+Expected: List of available commands for this application will be displayed.
+
+### Exiting the application
+
+Test case: `bye`
+
+Expected: Application exits.
+
+### Saving data
+
+Meal data, user data and exercise data will be saved in ./data/mealData.csv, ./data/userData.csv, ./data/exerciseData.csv respectively.
+
+### Dealing with missing/corrupted data files
+
+Delete the ./data/mealData.csv, ./data/userData.csv, ./data/exerciseData.csv files for corrupted data and restart the programme.
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..8fc98c9187 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,13 @@
-# Duke
+# LifeTracker
-{Give product intro here}
+LifeTracker is a desktop application used for encouraging users to lead a healthier life by tracking their net calorie intake. The user interacts with it using a CLI. LifeTracker is written in Java 11 and has about 4 kLoC.
Useful links:
* [User Guide](UserGuide.md)
* [Developer Guide](DeveloperGuide.md)
* [About Us](AboutUs.md)
+ * [Koh Ming En](./team/mingen82.md)
+ * [Koh Jing Jie Marcus](./team/koh-jing-jie-marcus.md)
+ * [Mustafa Anis Hussain](./team/mustafaah10.md)
+ * [Hoo Teng Juan](./team/tj-hoo.md)
+ * [Hamada Masahiro](./team/masahiro21.md)
diff --git a/docs/UG-images/add-example.PNG b/docs/UG-images/add-example.PNG
new file mode 100644
index 0000000000..66840da318
Binary files /dev/null and b/docs/UG-images/add-example.PNG differ
diff --git a/docs/UG-images/add-example2.PNG b/docs/UG-images/add-example2.PNG
new file mode 100644
index 0000000000..f76a06f88c
Binary files /dev/null and b/docs/UG-images/add-example2.PNG differ
diff --git a/docs/UG-images/bye-example.PNG b/docs/UG-images/bye-example.PNG
new file mode 100644
index 0000000000..4505af64c2
Binary files /dev/null and b/docs/UG-images/bye-example.PNG differ
diff --git a/docs/UG-images/delete-example.PNG b/docs/UG-images/delete-example.PNG
new file mode 100644
index 0000000000..097a47ce49
Binary files /dev/null and b/docs/UG-images/delete-example.PNG differ
diff --git a/docs/UG-images/examples-example.PNG b/docs/UG-images/examples-example.PNG
new file mode 100644
index 0000000000..883e146ac3
Binary files /dev/null and b/docs/UG-images/examples-example.PNG differ
diff --git a/docs/UG-images/exercise-example.PNG b/docs/UG-images/exercise-example.PNG
new file mode 100644
index 0000000000..9195cc60a0
Binary files /dev/null and b/docs/UG-images/exercise-example.PNG differ
diff --git a/docs/UG-images/filter-example.PNG b/docs/UG-images/filter-example.PNG
new file mode 100644
index 0000000000..7fa42ad3dc
Binary files /dev/null and b/docs/UG-images/filter-example.PNG differ
diff --git a/docs/UG-images/list-exercises-example.PNG b/docs/UG-images/list-exercises-example.PNG
new file mode 100644
index 0000000000..0fc9efc07c
Binary files /dev/null and b/docs/UG-images/list-exercises-example.PNG differ
diff --git a/docs/UG-images/list-foods-example.PNG b/docs/UG-images/list-foods-example.PNG
new file mode 100644
index 0000000000..f2da670161
Binary files /dev/null and b/docs/UG-images/list-foods-example.PNG differ
diff --git a/docs/UG-images/list-meals-example.PNG b/docs/UG-images/list-meals-example.PNG
new file mode 100644
index 0000000000..6aeedc3fa3
Binary files /dev/null and b/docs/UG-images/list-meals-example.PNG differ
diff --git a/docs/UG-images/nutrition-example.PNG b/docs/UG-images/nutrition-example.PNG
new file mode 100644
index 0000000000..3c04194014
Binary files /dev/null and b/docs/UG-images/nutrition-example.PNG differ
diff --git a/docs/UG-images/track-example.PNG b/docs/UG-images/track-example.PNG
new file mode 100644
index 0000000000..d71ead79c1
Binary files /dev/null and b/docs/UG-images/track-example.PNG differ
diff --git a/docs/UG-images/update-example.PNG b/docs/UG-images/update-example.PNG
new file mode 100644
index 0000000000..e58423558b
Binary files /dev/null and b/docs/UG-images/update-example.PNG differ
diff --git a/docs/UG-images/update-menu.PNG b/docs/UG-images/update-menu.PNG
new file mode 100644
index 0000000000..04070e59e6
Binary files /dev/null and b/docs/UG-images/update-menu.PNG differ
diff --git a/docs/UG-images/view-example.PNG b/docs/UG-images/view-example.PNG
new file mode 100644
index 0000000000..f40a1eb3ab
Binary files /dev/null and b/docs/UG-images/view-example.PNG differ
diff --git a/docs/UG-images/view-menu.PNG b/docs/UG-images/view-menu.PNG
new file mode 100644
index 0000000000..c94a0ae938
Binary files /dev/null and b/docs/UG-images/view-menu.PNG differ
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..1531c5ba17 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,42 +1,336 @@
-# User Guide
+# ***LifeTracker User Guide***
## Introduction
-{Give a product intro}
+**_LifeTracker_** is an application that allows users who are health conscious automate the tracking of their calories and keep a record of
+their calorie intake history.
-## Quick Start
+The app also allows users to keep track of their daily exercises to compute their calorie loss.
+
+Their net calorie gain/loss can then be viewed.
+- [Quick Start](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#quick-start)
+- [Features](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#features)
+ - [Viewing User Profile](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#viewing-user-profile-view)
+ - [Updating User Profile](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#updating-user-profile-update)
+ - [Adding a meal](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#adding-a-meal-add)
+ - [Listing foods](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#listing-foods-list)
+ - [Listing meals](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#listing-meals-list)
+ - [Listing exercises](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#listing-exercises-list)
+ - [Deleting meals](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#deleting-meals-delete)
+ - [Filtering foods](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#filtering-foods-filter)
+ - [Viewing nutrition content of foods](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#view-nutrition-content-of-food-nutrition)
+ - [Adding an exercise](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#adding-an-exercise-exercise)
+ - [Tracking net calorie intake](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#tracking-net-calorie-intake-track)
+ - [Displaying examples of meals and exercises](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#displaying-examples-of-meals-and-exercises-examples)
+ - [Exiting the application](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#exiting-the-application-bye)
+- [FAQ](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#faq)
+- [Command Summary](https://ay2223s2-cs2113-w15-1.github.io/tp/UserGuide.html#command-summary)
-{Give steps to get started quickly}
+## Quick Start
1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+2. Down the latest version of `LifeTracker` from [here](https://github.com/AY2223S2-CS2113-W15-1/tp).
+3. Copy the file to the folder you want ot use as the home folder for your LifeTracker.
+4. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar lifetracker.jar` command to run the application.
+5. Type the command in the command box and press Enter to execute it.
+6. Refer to the features below for details of each command.
+
+## Features
+
+* View and Update user profile
+* Add meal
+* Delete meal
+* Add Exercise
+* Calculate caloric needs
+* Calculate amount of calories left in the day
+* Find the nutrition of a certain kind of food
+* Filter foods based on calories
+* Track Calorie Intake
+
+### Viewing User Profile: `view`
+
+To view user's profile.
+User can simply input a single line command to view the specific information in their user profile using the format
+below.
+
+Format: `view /[fieldName]`
+
+Here is a table of the information that the user can choose to view alongside the field name of it:
+
+
+
Information
+
/[fieldName]
+
+
Name
+
/name
+
+
Weight
+
/weight
+
+
Height
+
/height
+
+
Age
+
/age
+
+
Gender
+
/gender
+
+
Daily caloric limit
+
/caloricLimit
+
+
Calories remaining for today
+
/caloriesLeft
+
+
Target weight
+
/targetWeight
+
+
+
+Example:
+
+
+
+
+### Updating User Profile: `update`
+
+Allows the user to update any of their information.
+User can simply input a single line command to update the specific information in their user profile using the format
+below.
+
+Format: `update /[fieldName] [newInfo]`
+
+Here is a table of the information that the user can choose to update alongside the field name of it:
+
+
+
Information
+
/[fieldName]
+
Comments
+
+
Name
+
/name
+
For more than one name, separate with an underscore. E.g Firstname_LastName
+
+
Weight
+
/weight
+
Weight can only take in numbers between 0 and 700 kg.
+
+
Height
+
/height
+
Height can only take in numbers between 0 and 300 cm.
+
+
Age
+
/age
+
Age can only take in numbers between 0 and 120 years old.
+
+
Gender
+
/gender
+
Gender can only take in male or female as arguments.
+
+
Target weight
+
/targetWeight
+
TargetWeight can only take in numbers between 0 and 700 kg.
+
+
+
+Example:
+
+
+
+### Adding a meal: `add`
+
+Adds a new meal to database
+
+Format: `add /on [date] /type [MealType] /foods [foods]`
+
+* The `date` should be in `d/M/yyyy` format
+* The `MealType` can be one of the following
+ * Breakfast
+ * Lunch
+ * Dinner
+* The `foods` is a list of foods seperated by `, ` (Comma with a space after)
+
+Example of usage:
+
+`add /on 3/3/2023 /type Lunch /foods Spaghetti, Alfredo (Small)`
+
+
+
+#### Alternatives
+
+For users who are not experienced with typing fast on keyboards, *LifeTracker* offers a menu option to add meal
+
+Format: `add`
+
+
+
+### Listing foods: `list`
+
+For users to view all foods currently supported in the *LifeTracker* database
+
+Format: `list foods`
+
+Example:
+
-## Features
+### Listing meals: `list`
-{Give detailed description of each feature}
+For users to view previously added meals
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+Format: `list meals`
-Format: `todo n/TODO_NAME d/DEADLINE`
+Example:
+
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+### Listing exercises: `list`
-Example of usage:
+For users to view previously added exercises
-`todo n/Write the rest of the User Guide d/next week`
+Format `list exercises`
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
+Example:
+
+
+### Deleting meals and exercises: `delete`
+
+For users to remove previously added meals and exercises
+
+Format: `delete /[meal, exercise] [index]`
+
+* The `index` should be a positive integer and must be less than number of meals/exercises added
+* It is recommended to run `list meals/exercises` beforehand to get the index of the meal/exercise you want to delete
+
+Example:
+
+
+### Filtering foods: `filter`
+
+For users to filter the foods by their calorie content. The user inputs the lower and higher bound that they want to filter the food by,
+in terms of the calorie content of the food.
+
+The list of food within the range will then be displayed, from which the user can choose from.
+
+Format: `filter [lower_bound] [upper_bound]`
+
+* The lower and upper bound should be a `float` value
+* The lower bound should be lower than or equal to the upper bound
+
+Example:
+
+
+### View nutrition content of food: `nutrition`
+
+For users to view the nutrition content of the food. The user first needs to search for the food, then the nutrition content of the food will be printed.
+
+Format: `nutrition`
+
+* The first food search should be in English
+* To select the particular food filtered, an integer should be inputted
+
+Example:
+
+
+### Adding an exercise: `exercise`
+
+For user to input the exercise done previously.
+
+Format: `exercise /type [exercise_name] /description [exercise_description] /calories [calories_burnt] /on [date]`
+
+* The `exercise name` and `exercise description` accepts any input
+* The `calories` should be in `float` format
+* The `date` should be in `d/M/yyyy` format
+
+Example:
+
+
+### Tracking net calorie intake: `track`
+
+For user to track their previous net calorie intake.
+
+There are 2 options to run this command:
+
+1) For user to view all their calorie history from past meals and exercises input
+Format: `track all`
+
+2) For user to view calorie history within a specified time-frame
+Format: `track /start [start_date] /end [end_date]`
+
+* The dates should be in `d/M/yyyy` format
+
+Output:
+
+
+### Displaying examples of meals and exercises: `examples`
+
+For user to gain some inspiration on exercises to do, as well as some idea on the meals that they can eat.
+
+Format: `examples [meal/exercise]`
+
+Example:
+
+
+### Exiting the application: `bye`
+Allows user to exit the appliction.
+
+Format: `bye`
+
+Output:
+
## FAQ
**Q**: How do I transfer my data to another computer?
-**A**: {your answer here}
+**A**: Do copy the `data` folder and its contents to the new computer
+
+**Q**: Where do you get the data for the food from?
+
+**A**: The nutrition data is based on food from NUS TechnoEdge canteen, as this application would be mainly targeted at NUS Engineering students who eats there regularly.
## Command Summary
-{Give a 'cheat sheet' of commands here}
+Note:
+1) Fields within square brackets are variable and are to be changed according to user needs.
+2) Fields with a comma inside the square brackets indicate that any of the multiple options can be input according to user needs.
+
+
+
Action
+
Format, Examples
+
+
View
+
view /[fieldName]
+
+
Update
+
update /[fieldName]
+
+
Add
+
add /on [date] /type [MealType] /foods [foods] OR add
+
+
List
+
list [foods, meals, exercises]
+
+
Delete
+
delete /[meal, exercise] [index]
+
+
Filter
+
filter [lower_bound] [upper_bound]
+
+
Nutrition
+
nutrition
+
+
Exercise
+
exercise /type [exercise_name] /description [exercise_description] /calories [calories_burnt] /on [date]
+
+
Track
+
track all OR track /start [start_date] /end [end_date]
+
+
Examples
+
examples [meal, exercise]
+
+
Help
+
help
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+
Exit
+
bye
+
+
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..14dbfd18e2
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,7 @@
+# basic options
+title: LifeTracker
+description: Get your desired body shape with this application!
+
+# Build settings
+markdown: kramdown
+remote_theme: benbalter/retlab
diff --git a/docs/architecture.PNG b/docs/architecture.PNG
new file mode 100644
index 0000000000..36ca02a3a2
Binary files /dev/null and b/docs/architecture.PNG differ
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index ab75b391b8..0000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# John Doe - Project Portfolio Page
-
-## Overview
-
-
-### Summary of Contributions
diff --git a/docs/team/koh-jing-jie-marcus.md b/docs/team/koh-jing-jie-marcus.md
new file mode 100644
index 0000000000..417c36e9b5
--- /dev/null
+++ b/docs/team/koh-jing-jie-marcus.md
@@ -0,0 +1,39 @@
+# Koh Jing Jie Marcus - Project Portfolio Page
+
+## Project: [LifeTracker](https://github.com/AY2223S2-CS2113-W15-1/tp)
+Our project, LifeTracker, is a calorie tracker CLI program. It allows the user to record down their daily net calorie gain, where the user can input the meals
+he has consumed as well as the exercises that he has done.
+
+In doing so, the user can better manage his daily calorie gain in order to meet their particular needs.
+
+## Summary of Contributions
+
+### Commands
+Commands are the ways in which the user interacts with our program, through the usage of particular inputs that are defined as commands.
+These are the main commands that I worked on.
+
+`filter` command
+* Allows the user to filter meals based on their calorie content
+
+`examples` command
+* Displays examples of exercises and meals
+
+### Database
+* Added the `ExampleData` database to store examples of meals and exercises to be used in the `examples` command
+
+### Contribution to team-based tasks
+Implemented the Ui used for LifeTracker, as well as the Ui for the indivdual commands. The Ui is used to improve the accessibility of the program to any potential users,
+to ulimately make the program easier to use by streamlining the process for the user. The Ui consists of:
+* General Ui - Handle the general commands as well as start up and exit of the program
+* Calorie Ui - Handle the Ui for the commands relating to calories
+* Exercise Ui - Handle the Ui for the `exercise` command
+* Weight Ui - Handle the Ui for the commands that involve the weight of the user
+* Example Ui - Handle the Ui for the `examples` command
+
+## UG/DG
+* Added Documentation for the `filter` and `examples` command
+
+* Added explanation of program and user stories
+
+## Code Contributed
+[RepoSense Link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=authorship&zFR=false&tabAuthor=Koh-Jing-Jie-Marcus&tabRepo=AY2223S2-CS2113-W15-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
diff --git a/docs/team/masahiro21.md b/docs/team/masahiro21.md
new file mode 100644
index 0000000000..6db3a039ce
--- /dev/null
+++ b/docs/team/masahiro21.md
@@ -0,0 +1,64 @@
+# Hamada Masahiro - Project Portfolio Page
+
+## Overview
+Our project, LifeTracker, is a calorie tracker CLI program. It allows the user to record down their daily net calorie gain, where the user can input the meals
+he has consumed as well as the exercises that he has done.
+
+In doing so, the user can better manage his daily calorie gain in order to meet their particular needs.
+
+Given below are my contributions to the project.
+
+## Summary of Contributions
+
+### Code Contributed
+
+[RepoSense](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=authorship&tabAuthor=Masahiro21&tabRepo=AY2223S2-CS2113-W15-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+### Commands
+Our project implements a variety of command which allows the user to input and keep track of their information
+via the CLI. They form the backbone of our project, and it is the key to it functioning smoothly. Below are the list of
+commands I have worked on.
+
+`view` command: Allows the user to view their information.
+* Implemented the code to allow users to view their information
+
+`update` command: Allows the user to update their information stored.
+* Added methods to allow update command to handle updates to name, age and gender
+
+`help` command: Allows the user to view a help menu that gives them a quick guide on how to use the program.
+* Abstracted print statements into UI
+
+### Entity
+`user` entity: The entity that initialises all the user's information.
+* Expanded the information that the entity holds to include age and gender
+* Implemented getter and setter methods for newly added information
+* Modified calculateCaloricNeeds method to factor in age and gender
+
+### Contribution to team-based tasks
+- Created and implemented the `view` command to allow users to view their information
+- Enhanced `view` and `update` commands to allow for better user experience
+
+### Unit Testing
+- Wrote JUnit tests for the following commands: `ViewUserCommand`, `UpdateUserCommand`
+- Wrote JUnit tests for the following entities: `User`
+
+### Enhancement to existing features
+* Modified `view` command to be able to take in one-liner inputs from the user to view their information
+ * Shortens the process of user viewing their information
+
+* Modified `update` command to allow names to be longer than one word.
+ * Allows for freedom of choice in names for user.
+
+* Modified `update` command to be able to take in one-liner inputs from the user to view their information
+ * Shortens the process of user updating their information
+
+## Project Management
+* Managed release `v2.0` on GitHub
+* Managed release `v2.0c` on GitHub
+
+## UG/DG
+* Added the introduction to the UG as well as a framework of explanation for the other members to build off
+* Added documentation for the `view` command and `update` command in user guide.
+* Added Sequence Diagrams and explanation for `view` and `update` command in developer guide.
+* Added explanation of program and user stories
+
diff --git a/docs/team/mingen82.md b/docs/team/mingen82.md
new file mode 100644
index 0000000000..1538fb7a97
--- /dev/null
+++ b/docs/team/mingen82.md
@@ -0,0 +1,91 @@
+# Koh Ming En's Project PortFolio Page
+
+## Project: [LifeTracker](https://github.com/AY2223S2-CS2113-W15-1/tp)
+
+LifeTracker is a desktop application used for encouraging users to lead a healthier life by tracking their net calorie intake. The user interacts with it using a CLI. LifeTracker is written in Java 11 and has about 4 kLoC.
+
+Given below are my contributions to the project.
+
+### Databases
+
+The databases generated by LifeTracker stores all of the users information. The primary file type used in this project is `csv` and I used the `OpenCSV v5.6` library to read and write to the databases. The databases I created are:
+
+1. Food Database
+2. Meal Database
+3. Exercise Database
+
+The sections below will discuss each database, its implementation and its contribution to the project.
+
+#### Food Database
+
+- What it does: Stores a copy of food sold in Technoedge and its nutritional value
+- Justification: This enables a more streamlined user experience as the user did not need to recall the exact food eaten and its nutritional value before inputting it in LifeTracker. The database also included methods to filter the foods for use in other parts of the project.
+- Highlights: The database was designed to be as general as possible, such that it could be "plugged" into any part of the project and used.
+
+#### Meal Database
+
+- What it does: Stores the meals that the user previouslty ate, including date of meal, type of meal (Breakfast, Lunch, Dinner) and food eaten.
+- Justfication: The information stored is used to calculate the calories consumed per day so that the user is able to better manage their weight.
+
+#### Exercise Database
+
+- What it does: Stores the exercises that the user previously did, the amount of calories burnt and the date of exercise
+- Justification: The information stored is used to calculate the calories burnt per day so that the user is able to better manage their weight.
+- Highlights: The enhancement complemented the existing meal database, which tracked the meals that the user ate. The database was planned and implemented such that changes to existing code was minimised, thus ensuring low coupling. The existing command to track calories which had to be updated, was done in a way to not break its usage in other parts of the code.
+
+### Entities
+
+To complement the database, I also created entities to hold the information from the databases. These are the entities I created and a brief description of what they do.
+
+1. `Food`: Holds the name of food, the store that sells it, and the nutritional content of the food. Has 3 child classes that further divides the food
+ - `Dish`: A main course
+ - `Side`: A side dish
+ - `Ingredient`: Combined to make a full dish
+2. `Meal`: Holds the date of meal eaten, the type of meal, and foods eaten.
+3. `User`: Holds the user current information
+
+### Exceptions
+
+For error handling, I also created some custome exceptions. These are the exceptions I created and a brief description of their purpose.
+
+1. `LifeTrackerException`: Base Custom Exception that the rest of the exceptions inherits from
+2. `InvalidArgumentsException`: Raised when the user included arguments in the command that cannot be parsed.
+3. `InvalidDateException`: Raised when the user included dates that cannot be parsed.
+4. `InvalidIndexException`: Raised when the user selected an option that is out of selectable range.
+5. `InvalidMealException`: Raised when the user entered an invalid type of meal
+6. `MissingArgumentException`: Raised when the user did not include some arguments for the command
+7. `UnableToSaveDatabaseException`: Raised when the information entered could not be saved.
+
+## Code Contributed
+
+[RepoSense Link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=w15-1&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=authorship&zFR=false&tabAuthor=MingEn82&tabRepo=AY2223S2-CS2113-W15-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+## Project Management
+
+- Released `v1.0` on Github
+- Managed uploading of UML diagrams to repository
+- Resolved `Gradle` and `Runtest` violations
+
+## Enhancements to existing features
+
+- Implemented Sorting for meals by date (PR [#75](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/b51b2fbfa99f3aed6490800f12bb1b00d99227d4))
+- Implemented single line CLI option for `add` command (PR [#77](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/4b3770b91a8aefbeef7a2d26904b3d26149923d2))
+- Enhanced tracking to include exercises on top of meals (PR [#99](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/4479d9b54e84461fe17506f3f19554bb99b0aca9))
+
+## Documentation
+
+- User Guide:
+ - Added documentation for `add`, `update`, `view`, `delete`, `filter`, `nutrition`, `exercise` and `track` (PR [#100](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/23a885bb27918f787c7c58a248178cd4a9865210#diff-b50feaf9240709b6b02fb9584696b012c2a69feeba89e409952cc2f401f373fb))
+- Developer Guide:
+ - Added documentation for `Storage` components (PR [#100](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/23a885bb27918f787c7c58a248178cd4a9865210#diff-b50feaf9240709b6b02fb9584696b012c2a69feeba89e409952cc2f401f373fb))
+ - Added UML class diagram for `Storage` components (PR [#100](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/23a885bb27918f787c7c58a248178cd4a9865210#diff-b50feaf9240709b6b02fb9584696b012c2a69feeba89e409952cc2f401f373fb))
+ - Added documentation for `TrackCalorieCommand` and `ListCommand` (PR [#197](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/8e17d1c08c93884053e1f29d0d2bff539cc105d6))
+ - Added Sequence diagrams to describe the flow of `TrackCalorieCommand` and `ListCommand` (PR [#197](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/8e17d1c08c93884053e1f29d0d2bff539cc105d6))
+
+## Community
+
+- Helped my groupmates with their parts of the project (PR [#55](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/c0f3dfea3f2730c03a8ebfc212de40bb919bc19c), [#86](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/3fa74ef706a130ea8cceb75aa5fbc497294bf9fa))
+
+## Tools
+
+- Integrated a third party library ([OpenCSV](https://mvnrepository.com/artifact/com.opencsv/opencsv/5.6)) to the project (PR [#41](https://github.com/AY2223S2-CS2113-W15-1/tp/commit/c5dea64be66692bab992ce8a5572dd76ebcf8a62#diff-49a96e7eea8a94af862798a45174e6ac43eb4f8b4bd40759b5da63ba31ec3ef7))
diff --git a/docs/team/mingen82.pdf b/docs/team/mingen82.pdf
new file mode 100644
index 0000000000..8c94761336
Binary files /dev/null and b/docs/team/mingen82.pdf differ
diff --git a/docs/team/mustafaah10.md b/docs/team/mustafaah10.md
new file mode 100644
index 0000000000..6abc979c9f
--- /dev/null
+++ b/docs/team/mustafaah10.md
@@ -0,0 +1,54 @@
+# Mustafa's Project Portfolio Page
+
+## Project: [LifeTracker](https://github.com/AY2223S2-CS2113-W15-1/tp)
+
+LifeTracker is a desktop application used for encouraging users to lead a healthier life by tracking their meals, exercises and net calorie intake. The user interacts with it using a CLI.
+Given below are my contributions to the project.
+
+### General
+
+#### LifeTracker
+ - Created the main executable `LifeTracker` which initialises the various databases upon first starting the programme and continuously takes in and executes the user input thereafter.
+
+#### Command Parser
+ - Created the class `CommandParser` for parsing of user input to decide which command needs to be executed by the programme.
+
+#### Commands
+
+I worked on some commands which help the user to input the relevant data into the CLI so that it can be tracked and recorded into the app's databases. Some examples are as follows:
+#### Add Exercise Command
+ - Handled the `AddExerciseCommand` for users to add exercise into the exercise database. Handles the parsing and exceptions for fields like the exercise name, description, date, calories etc.
+#### Delete Command
+ - Handled the `DeleteCommand` for users to delete a meal or exercise from their respective databases.
+#### Track Command
+ - Handled the `TrackCalorieCommand` for users to track their overall history or see their history within some specified dates.
+#### List Command
+ - Handled the `ListCommand` which enables users to see all meals/ foods/ exercises in the current storage database.
+
+### Entities
+#### Exercise
+ - Created the `Exercise` entity to be used which stores values in its fields for the exercise name, its description, the calories burnt and the date it was performed.
+
+### Unit Testing
+ - Wrote JUnit tests for the following commands: `DeleteCommand`, `TrackCalorieCommand`, `FilterCaloriesCommand`, `ListCommand`, `ExitCommand`
+
+### Contributions to Developer Guide
+ - Created the class diagram for the `Command` components
+ - Created sequence diagrams for `AddMealCommand` and `DeleteCommand`
+ - Added documentation for above diagrams and execution
+
+### Contributions to team-based tasks
+ - Created the logger which logs events like when the user started the app, meals and exercises added, when exceptions occurred.
+ - Created a local log file which is written to by the logger mentioned above.
+
+## Code Contributed
+[RepoSense Link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=mustafaah10&breakdown=true)
+
+## Project Management
+- Helped to fix bugs discovered in our Team's product during user testing.
+- Managed milestone releases and assisted in distributing and keeping track of issues via issue-tracker
+
+## Enhancements to existing features
+ - Combined the deletion of meals and exercises into a single command since they used similar functionality
+ - Implemented tracking within specified dates instead of just seeing all the history at once
+ - Implemented a way for users to see their net calories burnt and consumed on a date when they add a meal or exercise
\ No newline at end of file
diff --git a/docs/team/tj-hoo.md b/docs/team/tj-hoo.md
new file mode 100644
index 0000000000..c661041209
--- /dev/null
+++ b/docs/team/tj-hoo.md
@@ -0,0 +1,44 @@
+# Hoo Teng Juan's Project Portfolio Page
+
+## Project: [LifeTracker](https://github.com/AY2223S2-CS2113-W15-1/tp)
+
+LifeTracker is a desktop application used by those who wish to lead a healthier
+life by tracking their net calorie intake as well as their exercise. The user interacts with it using a Command Line Interface. It is written in Java, and has about 4 kLoC.
+
+Given below are my contributions to the project.
+
+## Summary of Contribution
+### Code contributed: [RepoSense Link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=w15-1&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=authorship&tabAuthor=TJ-Hoo&tabRepo=AY2223S2-CS2113-W15-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=functional-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+## Enhancements implemented:
+
+### Commands
+- `Nutrition`: Allows user to see the nutritional data of foods in the database.
+- `Help`: Allows user to see the list of available commands for this application.
+
+### Database
+- Updated some wrong values in `FoodData`.
+- Added data from Nasi Padang stall to `FoodData`.
+
+### Other
+- Updated `Food` within entities and `FoodStorage` within storage to be able to return nutritional data.
+- Created `CaloricIntake` entity to hold the calculation of the user's the daily caloric intake.
+
+## Contributions to the UG:
+- Added documentation for `nutrition` command.
+- Added FAQ and command summary sections.
+
+## Contributions to the DG:
+- Added UI component UML.
+- Added documentation for command component description and 2nd UML.
+- Added documentation for `nutrition` command.
+- Added instructions for manual testing section.
+- Added design and considerations for all proposed implementations.
+
+## Contributions to team-based tasks:
+- Target user profile of DG.
+- Non-Functional Requirements section of DG.
+- Update user stories of DG.
+
+## Review/mentoring contributions:
+- Fixed gradle errors.
diff --git a/docs/uml/AddMealCommand1.png b/docs/uml/AddMealCommand1.png
new file mode 100644
index 0000000000..a93f3e1fcd
Binary files /dev/null and b/docs/uml/AddMealCommand1.png differ
diff --git a/docs/uml/Command-class-diagram.png b/docs/uml/Command-class-diagram.png
new file mode 100644
index 0000000000..3d87918b83
Binary files /dev/null and b/docs/uml/Command-class-diagram.png differ
diff --git a/docs/uml/DeleteMealCommand1.png b/docs/uml/DeleteMealCommand1.png
new file mode 100644
index 0000000000..2e2f460dc1
Binary files /dev/null and b/docs/uml/DeleteMealCommand1.png differ
diff --git a/docs/uml/ExamplesCommand.png b/docs/uml/ExamplesCommand.png
new file mode 100644
index 0000000000..380e732733
Binary files /dev/null and b/docs/uml/ExamplesCommand.png differ
diff --git a/docs/uml/FilterCaloriesCommand.png b/docs/uml/FilterCaloriesCommand.png
new file mode 100644
index 0000000000..5da9da3927
Binary files /dev/null and b/docs/uml/FilterCaloriesCommand.png differ
diff --git a/docs/uml/ListCommand.PNG b/docs/uml/ListCommand.PNG
new file mode 100644
index 0000000000..2afabd4f18
Binary files /dev/null and b/docs/uml/ListCommand.PNG differ
diff --git a/docs/uml/NutritionCommand.png b/docs/uml/NutritionCommand.png
new file mode 100644
index 0000000000..5d38ba0549
Binary files /dev/null and b/docs/uml/NutritionCommand.png differ
diff --git a/docs/uml/TrackCaloriesCommand.PNG b/docs/uml/TrackCaloriesCommand.PNG
new file mode 100644
index 0000000000..d51c3aaf76
Binary files /dev/null and b/docs/uml/TrackCaloriesCommand.PNG differ
diff --git a/docs/uml/UI-class-diagram.png b/docs/uml/UI-class-diagram.png
new file mode 100644
index 0000000000..056409ad62
Binary files /dev/null and b/docs/uml/UI-class-diagram.png differ
diff --git a/docs/uml/UML.pptx b/docs/uml/UML.pptx
new file mode 100644
index 0000000000..78e2547b8c
Binary files /dev/null and b/docs/uml/UML.pptx differ
diff --git a/docs/uml/UpdateUserCommandSD1.png b/docs/uml/UpdateUserCommandSD1.png
new file mode 100644
index 0000000000..827bc25002
Binary files /dev/null and b/docs/uml/UpdateUserCommandSD1.png differ
diff --git a/docs/uml/UpdateUserCommandSD2.png b/docs/uml/UpdateUserCommandSD2.png
new file mode 100644
index 0000000000..396f14a7d6
Binary files /dev/null and b/docs/uml/UpdateUserCommandSD2.png differ
diff --git a/docs/uml/ViewUserCommandSD1.png b/docs/uml/ViewUserCommandSD1.png
new file mode 100644
index 0000000000..abf360ed0f
Binary files /dev/null and b/docs/uml/ViewUserCommandSD1.png differ
diff --git a/docs/uml/ViewUserCommandSD2.png b/docs/uml/ViewUserCommandSD2.png
new file mode 100644
index 0000000000..c624dd4684
Binary files /dev/null and b/docs/uml/ViewUserCommandSD2.png differ
diff --git a/docs/uml/ViewUserCommandSD3.png b/docs/uml/ViewUserCommandSD3.png
new file mode 100644
index 0000000000..9aef8cb6b7
Binary files /dev/null and b/docs/uml/ViewUserCommandSD3.png differ
diff --git a/docs/uml/architecture.PNG b/docs/uml/architecture.PNG
new file mode 100644
index 0000000000..36ca02a3a2
Binary files /dev/null and b/docs/uml/architecture.PNG differ
diff --git a/docs/uml/architecture.puml b/docs/uml/architecture.puml
new file mode 100644
index 0000000000..90ede5aef4
--- /dev/null
+++ b/docs/uml/architecture.puml
@@ -0,0 +1,54 @@
+@startuml architecture
+!include style.puml
+
+allow_mixing
+skinparam classFontColor automatic
+skinparam classHeaderBackgroundColor MODEL_COLOR_T4
+
+database Storage STORAGE_COLOR {
+
+}
+
+class UI UI_COLOR {
+
+}
+
+class User {
+
+}
+
+class Food {
+
+}
+
+class Meal {
+
+}
+
+class Command LOGIC_COLOR {
+
+}
+
+class LifeTracker STORAGE_COLOR_T1 {
+
+}
+
+LifeTracker -up-> UI
+LifeTracker -right-> Storage
+
+actor user USER_COLOR
+
+user ..> UI
+UI -> Command
+
+Storage ..> Meal
+Storage ..> Food
+Storage ..> User
+Meal *--left-- "1..*" Food
+
+Command --> User
+Command --> Meal
+Command --> Storage
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/uml/architecture.svg b/docs/uml/architecture.svg
new file mode 100644
index 0000000000..50aed32153
--- /dev/null
+++ b/docs/uml/architecture.svg
@@ -0,0 +1,185 @@
+Storage UI User Food Meal Command LifeTracker user 1..*
\ No newline at end of file
diff --git a/docs/uml/commands-class-diagram.png b/docs/uml/commands-class-diagram.png
new file mode 100644
index 0000000000..255958c61d
Binary files /dev/null and b/docs/uml/commands-class-diagram.png differ
diff --git a/docs/uml/storage-class-diagram.PNG b/docs/uml/storage-class-diagram.PNG
new file mode 100644
index 0000000000..73c6b38990
Binary files /dev/null and b/docs/uml/storage-class-diagram.PNG differ
diff --git a/docs/uml/style.puml b/docs/uml/style.puml
new file mode 100644
index 0000000000..2c46e043f2
--- /dev/null
+++ b/docs/uml/style.puml
@@ -0,0 +1,75 @@
+/'
+ 'Commonly used styles and colors across diagrams.
+ 'Refer to https://plantuml-documentation.readthedocs.io/en/latest for a more
+ 'comprehensive list of skinparams.
+ '/
+
+
+'T1 through T4 are shades of the original color from lightest to darkest
+
+!define UI_COLOR #1D8900
+!define UI_COLOR_T1 #83E769
+!define UI_COLOR_T2 #3FC71B
+!define UI_COLOR_T3 #166800
+!define UI_COLOR_T4 #0E4100
+
+!define LOGIC_COLOR #3333C4
+!define LOGIC_COLOR_T1 #C8C8FA
+!define LOGIC_COLOR_T2 #6A6ADC
+!define LOGIC_COLOR_T3 #1616B0
+!define LOGIC_COLOR_T4 #101086
+
+!define MODEL_COLOR #9D0012
+!define MODEL_COLOR_T1 #F97181
+!define MODEL_COLOR_T2 #E41F36
+!define MODEL_COLOR_T3 #7B000E
+!define MODEL_COLOR_T4 #51000A
+
+!define STORAGE_COLOR #A38300
+!define STORAGE_COLOR_T1 #FFE374
+!define STORAGE_COLOR_T2 #EDC520
+!define STORAGE_COLOR_T3 #806600
+!define STORAGE_COLOR_T2 #544400
+
+!define USER_COLOR #000000
+
+skinparam BackgroundColor #FFFFFFF
+
+skinparam Shadowing false
+
+skinparam Class {
+ FontColor #FFFFFF
+ BorderThickness 1
+ BorderColor #FFFFFF
+ StereotypeFontColor #FFFFFF
+ FontName Arial
+}
+
+skinparam Actor {
+ BorderColor USER_COLOR
+ Color USER_COLOR
+ FontName Arial
+}
+
+skinparam Sequence {
+ MessageAlign center
+ BoxFontSize 15
+ BoxPadding 0
+ BoxFontColor #FFFFFF
+ FontName Arial
+}
+
+skinparam Participant {
+ FontColor #FFFFFFF
+ Padding 20
+}
+
+skinparam MinClassWidth 50
+skinparam ParticipantPadding 10
+skinparam Shadowing false
+skinparam DefaultTextAlignment center
+skinparam packageStyle Rectangle
+
+hide footbox
+hide members
+hide circle
\ No newline at end of file
diff --git a/docs/uml/user-stories.png b/docs/uml/user-stories.png
new file mode 100644
index 0000000000..12da2abf58
Binary files /dev/null and b/docs/uml/user-stories.png differ
diff --git a/myLogFile.log b/myLogFile.log
new file mode 100644
index 0000000000..45b173c350
--- /dev/null
+++ b/myLogFile.log
@@ -0,0 +1,2 @@
+Apr 10, 2023 9:49:59 PM seedu.logger.LogFileHandler logInfo
+INFO: User exited the programme.
diff --git a/src/main/java/seedu/commands/AddExerciseCommand.java b/src/main/java/seedu/commands/AddExerciseCommand.java
new file mode 100644
index 0000000000..642439dd43
--- /dev/null
+++ b/src/main/java/seedu/commands/AddExerciseCommand.java
@@ -0,0 +1,101 @@
+package seedu.commands;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.format.ResolverStyle;
+
+import seedu.constants.DateConstants;
+import seedu.entities.Exercise;
+import seedu.exceptions.InvalidArgumentsException;
+import seedu.exceptions.InvalidCommandException;
+import seedu.exceptions.InvalidDateException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.ExerciseUi;
+import seedu.ui.GeneralUi;
+
+public class AddExerciseCommand extends Command {
+ private String commandWord;
+ private String userInput;
+ private String exerciseName;
+ private String exerciseDescription;
+ private float calorieBurnt;
+ private LocalDate date;
+ private DateTimeFormatter dtf;
+
+ public AddExerciseCommand(String commandWord, String userInput) {
+ this.commandWord = commandWord;
+ this.userInput = userInput;
+ }
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage) throws LifeTrackerException {
+ this.dtf = DateConstants.PARSE_DTF;
+ this.parseCommand();
+ Exercise newExercise = new Exercise(exerciseName, exerciseDescription, calorieBurnt, date);
+ exerciseStorage.saveExercise(newExercise);
+ ui.printMotivateMessage();
+ ExerciseUi.addedExercise(newExercise);
+ ui.displayDayCalories(exerciseStorage, date, mealStorage);
+ }
+
+ private void parseCommand() throws LifeTrackerException {
+ int exerciseNameIndex;
+ int exerciseDescriptionIndex;
+ int calorieBurntIndex;
+ int dateIndex;
+ String dateString;
+ String exerciseNameIdentifier = "/type";
+ String exerciseDescriptionIdentifier = "/description";
+ String calorieBurntIdentifier = "/calories";
+ String dateIdentifier = "/on";
+
+ exerciseNameIndex = userInput.indexOf(exerciseNameIdentifier);
+ if (exerciseNameIndex == -1) {
+ throw new MissingArgumentsException(commandWord, exerciseNameIdentifier);
+ } else if (exerciseNameIndex > commandWord.length() + 1) {
+ throw new InvalidCommandException();
+ }
+ exerciseDescriptionIndex = userInput.indexOf(exerciseDescriptionIdentifier);
+ if (exerciseDescriptionIndex == -1) {
+ throw new MissingArgumentsException(commandWord, exerciseDescriptionIdentifier);
+ }
+ calorieBurntIndex = userInput.indexOf(calorieBurntIdentifier);
+ if (calorieBurntIndex == -1) {
+ throw new MissingArgumentsException(commandWord, calorieBurntIdentifier);
+ }
+ dateIndex = userInput.indexOf(dateIdentifier);
+ if (dateIndex == -1) {
+ throw new MissingArgumentsException(commandWord, dateIdentifier);
+ }
+
+ exerciseName = userInput.substring(
+ exerciseNameIndex+exerciseNameIdentifier.length(), exerciseDescriptionIndex-1).trim();
+ exerciseDescription = userInput.substring(
+ exerciseDescriptionIndex+exerciseDescriptionIdentifier.length(), calorieBurntIndex-1).trim();
+ try {
+ calorieBurnt = Float.parseFloat(userInput.substring(
+ calorieBurntIndex+calorieBurntIdentifier.length(), dateIndex-1).trim());
+ } catch (NumberFormatException e) {
+ throw new InvalidArgumentsException(commandWord, calorieBurntIdentifier);
+ }
+
+ dateString = userInput.substring(dateIndex+dateIdentifier.length()).trim();
+ try {
+ if (dateString.matches("\\d{1,2}/")) {
+ throw new InvalidDateException(dateString);
+ }
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu")
+ .withResolverStyle(ResolverStyle.STRICT);
+ date = LocalDate.parse(dateString, formatter);
+ } catch (DateTimeParseException e) {
+ throw new InvalidDateException(dateString);
+ }
+ }
+}
diff --git a/src/main/java/seedu/commands/AddMealCommand.java b/src/main/java/seedu/commands/AddMealCommand.java
new file mode 100644
index 0000000000..d876c878ff
--- /dev/null
+++ b/src/main/java/seedu/commands/AddMealCommand.java
@@ -0,0 +1,217 @@
+package seedu.commands;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.format.ResolverStyle;
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.definitions.MealTypes;
+import seedu.entities.Food;
+import seedu.entities.Meal;
+import seedu.exceptions.InvalidCommandException;
+import seedu.exceptions.InvalidDateException;
+import seedu.exceptions.InvalidIndexException;
+import seedu.exceptions.InvalidMealException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.exceptions.NoFoodsException;
+import seedu.logger.LogFileHandler;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+
+public class AddMealCommand extends Command {
+
+ private String commandWord;
+ private String userInput;
+ private String dateString;
+ private LocalDate date;
+ private String mealTypeString;
+ private MealTypes mealType;
+ private String foodName;
+ private int choice;
+ private Meal meal;
+ private ArrayList foods;
+
+ public AddMealCommand(String commandWord, String userInput) {
+ this.commandWord = commandWord;
+ this.userInput = userInput;
+ }
+
+
+ /**
+ * Executes adding meal to database
+ * Supports two modes of adding meal to database
+ * 1. add command without arguments: prompts user to input necessary information
+ * 2. add command with arguments: parses arguments to get information
+ * @param ui handles i/o with user
+ * @param foodStorage for getting food information
+ * @param mealStorage for storing meal information
+ * @param userStorage
+ * @param exerciseStorage
+ * @throws LifeTrackerException
+ */
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ foods = new ArrayList();
+ dateString = "";
+ mealTypeString = "";
+ mealType = null;
+ if (commandWord.length() == userInput.length()) {
+ getDetails(ui, foodStorage);
+ } else {
+ parseCommand(ui, foodStorage);
+ }
+
+ if (foods.size() == 0) {
+ throw new NoFoodsException();
+ }
+ meal = new Meal(foods, date, mealType);
+ mealStorage.saveMeal(meal);
+ ui.printNewMealAdded(meal);
+ ui.displayDayCalories(exerciseStorage, date, mealStorage);
+ LogFileHandler.logInfo(meal.toString());
+ }
+
+
+
+ /**
+ * Prompts user for meal details
+ * @param ui
+ * @param foodStorage
+ * @throws LifeTrackerException
+ */
+ private void getDetails(GeneralUi ui, FoodStorage foodStorage) throws LifeTrackerException {
+ boolean toContinue = true;
+ System.out.println("Enter date of meal (d/M/yyyy):");
+ try {
+ dateString = ui.readLine();
+ if (dateString.matches("\\d{1,2}/")) {
+ throw new InvalidDateException(dateString);
+ }
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu")
+ .withResolverStyle(ResolverStyle.STRICT);
+ date = LocalDate.parse(dateString, formatter);
+ } catch (DateTimeParseException e) {
+ throw new InvalidDateException(dateString);
+ }
+
+ System.out.println(System.lineSeparator() + "Enter type of meal (Breakfast/Lunch/Dinner):");
+ mealTypeString = ui.readLine();
+ if ((mealType = MealTypes.fromString(mealTypeString)) == null) {
+ throw new InvalidMealException(mealTypeString);
+ }
+
+ do {
+ System.out.println(System.lineSeparator() + "Enter food:");
+ foodName = ui.readLine();
+
+ List filteredFoods = foodStorage.getFoodsByName(foodName);
+ if (filteredFoods.size() == 0) {
+ throw new LifeTrackerException(System.lineSeparator() + "No food found with " + foodName);
+ }
+
+ System.out.println(System.lineSeparator() + "These are the food with " + foodName);
+ System.out.println("Please select which food:");
+ for (int i = 0; i < filteredFoods.size(); i++) {
+ System.out.printf("%d) %s" + System.lineSeparator(), i + 1, filteredFoods.get(i).toString());
+ }
+
+ choice = ui.readInt();
+ if (choice <= 0 || choice > filteredFoods.size()) {
+ throw new InvalidIndexException(choice);
+ }
+
+ foods.add(filteredFoods.get(choice - 1));
+
+ System.out.println(System.lineSeparator() + "Type 1 to add more food. Type any other number to quit");
+ choice = ui.readInt();
+ if (choice != 1) {
+ toContinue = false;
+ }
+
+ } while (toContinue);
+ }
+
+
+ /**
+ * Parses command for meal information
+ * @param ui
+ * @param foodStorage
+ * @throws LifeTrackerException
+ */
+ private void parseCommand(GeneralUi ui, FoodStorage foodStorage) throws LifeTrackerException {
+ int dateIndex;
+ int mealTypeIndex;
+ int foodIndex;
+ int choice;
+ String dateString;
+ String mealTypeString;
+ String foodString;
+ String[] foodList;
+ String dateIdentifier = "/on";
+ String mealTypeIdentifier = "/type";
+ String foodIdentifier = "/foods";
+
+ dateIndex = userInput.indexOf(dateIdentifier);
+ if (dateIndex == -1) {
+ throw new MissingArgumentsException(commandWord, dateIdentifier);
+ } else if (dateIndex > commandWord.length()+1) {
+ throw new InvalidCommandException();
+ }
+ mealTypeIndex = userInput.indexOf(mealTypeIdentifier);
+ if (mealTypeIndex == -1) {
+ throw new MissingArgumentsException(commandWord, mealTypeIdentifier);
+ }
+ foodIndex = userInput.indexOf(foodIdentifier);
+ if (foodIndex == -1) {
+ throw new MissingArgumentsException(commandWord, foodIdentifier);
+ }
+
+ dateString = userInput.substring(dateIndex+dateIdentifier.length(), mealTypeIndex-1).trim();
+ mealTypeString = userInput.substring(mealTypeIndex+mealTypeIdentifier.length(), foodIndex-1).trim();
+ foodString = userInput.substring(foodIndex+foodIdentifier.length());
+
+ try {
+ if (dateString.matches("\\d{1,2}/")) {
+ throw new InvalidDateException(dateString);
+ }
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu")
+ .withResolverStyle(ResolverStyle.STRICT);
+ date = LocalDate.parse(dateString, formatter);
+ } catch (DateTimeParseException e) {
+ throw new InvalidDateException(dateString);
+ }
+ mealType = MealTypes.fromString(mealTypeString);
+ foodList = foodString.split(", ");
+
+ for (int i = 0; i < foodList.length; i++) {
+ foodList[i] = foodList[i].trim();
+ List filteredFoods = foodStorage.getFoodsByName(foodList[i]);
+ if (filteredFoods.size() == 0) {
+ System.out.println(System.lineSeparator() + "No food found with " + foodList[i]);
+ continue;
+ }
+ System.out.println(System.lineSeparator() + "These are the food with " + foodList[i]);
+ System.out.println("Please select which food:");
+ for (int j = 0; j < filteredFoods.size(); j++) {
+ System.out.printf("%d) %s" + System.lineSeparator(), j + 1, filteredFoods.get(j).toString());
+ }
+
+ choice = ui.readInt();
+ try {
+ foods.add(filteredFoods.get(choice - 1));
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidIndexException(choice);
+ }
+ System.out.println("You chose: " + filteredFoods.get(choice - 1) + System.lineSeparator());
+ }
+ }
+}
diff --git a/src/main/java/seedu/commands/Command.java b/src/main/java/seedu/commands/Command.java
new file mode 100644
index 0000000000..78c2691b4a
--- /dev/null
+++ b/src/main/java/seedu/commands/Command.java
@@ -0,0 +1,39 @@
+package seedu.commands;
+
+import seedu.exceptions.LifeTrackerException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+/**
+ * Superclass for commands
+ */
+public abstract class Command {
+ private boolean isExit;
+
+ public Command(){
+ setIsExit(false);
+ }
+
+ /**
+ * For exit command
+ * @param exit
+ */
+ public void setIsExit(boolean exit) {
+ this.isExit = exit;
+ }
+
+ /**
+ * To determine whether to exit LifeTracker
+ * @return true if exiting application, false otherwise
+ */
+ public boolean isExit() {
+ return this.isExit;
+ }
+
+ public abstract void execute(GeneralUi ui , FoodStorage foodStorage,
+ MealStorage mealStorage, UserStorage userStorage, ExerciseStorage exerciseStorage)
+ throws LifeTrackerException;
+}
diff --git a/src/main/java/seedu/commands/DeleteCommand.java b/src/main/java/seedu/commands/DeleteCommand.java
new file mode 100644
index 0000000000..8d882f5b9c
--- /dev/null
+++ b/src/main/java/seedu/commands/DeleteCommand.java
@@ -0,0 +1,84 @@
+package seedu.commands;
+
+import seedu.entities.Exercise;
+import seedu.entities.Meal;
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.InvalidCommandException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.exceptions.InvalidIndexException;
+import seedu.logger.LogFileHandler;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+/**
+ * Command to delete meal from database
+ */
+public class DeleteCommand extends Command{
+ private String itemType;
+ private int index;
+
+ public DeleteCommand(String commandWord, String userInput) throws LifeTrackerException {
+ parseInput(userInput);
+ }
+
+ /**
+ * For parsing the index of meal to be deleted from database
+ * @param commandDescriptor full command with arguments
+ * @throws LifeTrackerException
+ */
+ private void parseInput(String commandDescriptor) throws LifeTrackerException{
+
+ String[] commandParts = commandDescriptor.split(" ");
+ if (commandParts.length == 1) {
+ throw new MissingArgumentsException("delete", "[/meal, /exercise]");
+ } else if (commandParts.length > 3) {
+ throw new ExtraArgumentsException();
+ } else if (!commandParts[1].equals("/meal") && !commandParts[1].equals("/exercise")) {
+ throw new InvalidCommandException();
+ }
+ this.itemType = commandParts[1].substring(1);
+ try {
+ this.index = Integer.parseInt(commandParts[2]) - 1;
+ } catch (Exception e) {
+ throw new LifeTrackerException("Please enter an index to delete!");
+ }
+ }
+
+ /**
+ * Removes meal from database if valid index was given
+ * @param ui For handling i/o with user
+ * @param foodStorage
+ * @param mealStorage To remove meal from database
+ * @param userStorage
+ * @param exerciseStorage
+ * @throws LifeTrackerException if invalid index was given
+ */
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage,
+ MealStorage mealStorage, UserStorage userStorage, ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ if (this.itemType.equals("meal")) {
+ try{
+ Meal deletedMeal = mealStorage.deleteMeal(this.index);
+ ui.printMealDeleted(deletedMeal);
+ LogFileHandler.logInfo(deletedMeal.toString());
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidIndexException(index + 1);
+ }
+ } else if (this.itemType.equals("exercise")) {
+ try{
+ Exercise deletedExercise = exerciseStorage.deleteExercise(this.index);
+ ui.printExerciseDeleted(deletedExercise);
+ LogFileHandler.logInfo(deletedExercise.toString());
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidIndexException(index + 1);
+ }
+ } else {
+ throw new InvalidCommandException();
+ }
+ }
+}
diff --git a/src/main/java/seedu/commands/ExamplesCommand.java b/src/main/java/seedu/commands/ExamplesCommand.java
new file mode 100644
index 0000000000..54df27e4b3
--- /dev/null
+++ b/src/main/java/seedu/commands/ExamplesCommand.java
@@ -0,0 +1,44 @@
+package seedu.commands;
+
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.ExampleUi;
+import seedu.ui.GeneralUi;
+
+public class ExamplesCommand extends Command{
+
+ private String input;
+
+ public ExamplesCommand(String command, String type) throws LifeTrackerException {
+ String[] split = type.split(" ");
+ if (command.length() == type.length() || split.length < 2) {
+ throw new MissingArgumentsException(command, "[exercise/meal]");
+ } else if (split.length > 2) {
+ throw new ExtraArgumentsException();
+ }
+ this.input = split[1];
+ }
+
+ public void printExamples(String input, GeneralUi ui) throws LifeTrackerException {
+ ExampleUi exampleUi = new ExampleUi();
+ if(input.equals("meal")) {
+ exampleUi.displayMealExamples();
+ } else if (input.equals("exercise")) {
+ exampleUi.displayExerciseExamples();
+ } else {
+ throw new LifeTrackerException("You can only input exercise/meal for this command!");
+ }
+ }
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage,
+ MealStorage mealStorage, UserStorage userStorage, ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ printExamples(input, ui);
+ }
+}
diff --git a/src/main/java/seedu/commands/ExitCommand.java b/src/main/java/seedu/commands/ExitCommand.java
new file mode 100644
index 0000000000..e4a73c786d
--- /dev/null
+++ b/src/main/java/seedu/commands/ExitCommand.java
@@ -0,0 +1,32 @@
+package seedu.commands;
+
+import java.io.IOException;
+
+import seedu.exceptions.LifeTrackerException;
+import seedu.logger.LogFileHandler;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+/**
+ * For exiting the program
+ */
+public class ExitCommand extends Command{
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ setIsExit(true);
+ ui.printGoodbye();
+ LogFileHandler.logInfo("User exited the programme.");
+ try {
+ mealStorage.write();
+ userStorage.write();
+ exerciseStorage.write();
+ } catch (IOException e) {
+ LogFileHandler.logInfo("Error saving databases!");
+ }
+ }
+}
diff --git a/src/main/java/seedu/commands/FilterCaloriesCommand.java b/src/main/java/seedu/commands/FilterCaloriesCommand.java
new file mode 100644
index 0000000000..9262c8a295
--- /dev/null
+++ b/src/main/java/seedu/commands/FilterCaloriesCommand.java
@@ -0,0 +1,77 @@
+package seedu.commands;
+
+import seedu.entities.Food;
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.InvalidArgumentsException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.exceptions.NegativeFieldInfoException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+import java.util.List;
+
+public class FilterCaloriesCommand extends Command {
+ private float caloriesLowerLimit;
+ private float caloriesUpperLimit;
+
+ public FilterCaloriesCommand(String command, String type) throws LifeTrackerException {
+ String[] split = type.split(" ");
+ if (command.length() == type.length() || split.length < 2) {
+ throw new MissingArgumentsException(command, "requires both lower limit and upper limit");
+ } else if (split.length > 3) {
+ throw new ExtraArgumentsException();
+ }
+
+ try {
+ this.caloriesLowerLimit = Float.parseFloat(split[1]);
+ } catch (NumberFormatException e) {
+ throw new InvalidArgumentsException(command, "lower calorie value");
+ }
+ try {
+ this.caloriesUpperLimit = Float.parseFloat(split[2]);
+ } catch (NumberFormatException e) {
+ throw new InvalidArgumentsException(command, "upper calorie value");
+ }
+
+ if (caloriesLowerLimit < 0) {
+ throw new NegativeFieldInfoException(command, "lower calorie value");
+ }
+
+ if (caloriesUpperLimit < 0) {
+ throw new NegativeFieldInfoException(command, "upper calorie value");
+ }
+
+ }
+ private void showCaloriesFilteredFoods(FoodStorage foodStorage, List caloriesFilteredFoods)
+ throws LifeTrackerException {
+
+ if (caloriesFilteredFoods.size() == 0) {
+ throw new LifeTrackerException(System.lineSeparator() + "No food found within calorie range");
+ }
+ System.out.printf("Here are foods that contain calories within the %.2f and %.2f range\n",
+ caloriesLowerLimit, caloriesUpperLimit);
+ for (int i = 0; i < caloriesFilteredFoods.size(); i++) {
+ System.out.printf("%d) %s" + System.lineSeparator(), i+1, caloriesFilteredFoods.get(i).toString());
+ }
+ }
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+
+ if (caloriesLowerLimit > caloriesUpperLimit) {
+ throw new LifeTrackerException("Lower calorie limit should not be greater than upper calorie limit!");
+ }
+ System.out.println("This is the lower calorie limit (float):");
+ System.out.println(caloriesLowerLimit);
+ System.out.println("This is the upper calorie limit (float):");
+ System.out.println(caloriesUpperLimit);
+
+ List caloriesFilteredFoods = foodStorage.getFoodsByCalories(caloriesLowerLimit, caloriesUpperLimit);
+ showCaloriesFilteredFoods(foodStorage, caloriesFilteredFoods);
+ }
+}
diff --git a/src/main/java/seedu/commands/HelpCommand.java b/src/main/java/seedu/commands/HelpCommand.java
new file mode 100644
index 0000000000..c226ecf142
--- /dev/null
+++ b/src/main/java/seedu/commands/HelpCommand.java
@@ -0,0 +1,18 @@
+package seedu.commands;
+
+import seedu.exceptions.LifeTrackerException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+public class HelpCommand extends Command {
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ ui.printHelpMenu();
+ }
+}
diff --git a/src/main/java/seedu/commands/ListCommand.java b/src/main/java/seedu/commands/ListCommand.java
new file mode 100644
index 0000000000..12dc076f15
--- /dev/null
+++ b/src/main/java/seedu/commands/ListCommand.java
@@ -0,0 +1,39 @@
+package seedu.commands;
+
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+public class ListCommand extends Command {
+ private String argument;
+
+ public ListCommand(String commandWord, String userInput) throws LifeTrackerException {
+ String[] commandParts = userInput.split(" ");
+ if (commandWord.length() == userInput.length() || userInput.split(" ").length < 2) {
+ throw new MissingArgumentsException(commandWord, "[meals/foods/exercises]");
+ } else if (commandParts.length > 2) {
+ throw new ExtraArgumentsException();
+ }
+ this.argument = userInput.split(" ")[1];
+ }
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage,
+ MealStorage mealStorage, UserStorage userStorage, ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ if (argument.equals("meals")) {
+ ui.printAllMeals(mealStorage);
+ } else if (argument.equals("foods")) {
+ ui.printAllFoods(foodStorage);
+ } else if (argument.equals("exercises")) {
+ ui.printAllExercises(exerciseStorage);
+ } else {
+ throw new LifeTrackerException("You can only list foods/meals/exercises !");
+ }
+ }
+}
diff --git a/src/main/java/seedu/commands/NutritionCommand.java b/src/main/java/seedu/commands/NutritionCommand.java
new file mode 100644
index 0000000000..ea8f761db3
--- /dev/null
+++ b/src/main/java/seedu/commands/NutritionCommand.java
@@ -0,0 +1,58 @@
+package seedu.commands;
+
+import java.util.List;
+
+import seedu.entities.Food;
+import seedu.exceptions.InvalidIndexException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+public class NutritionCommand extends Command {
+ String foodName;
+ int choice;
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ System.out.println(System.lineSeparator() + "What food would you like to see the nutrients for?");
+ foodName = ui.readLine();
+
+ List filteredFoods = foodStorage.getFoodsByName(foodName);
+ if (filteredFoods.size() == 0) {
+ throw new LifeTrackerException(System.lineSeparator() + "No food found with " + foodName);
+ }
+
+ System.out.println(System.lineSeparator() + "These are the food with " + foodName);
+ System.out.println("Please select which food:");
+ for (int i = 0; i < filteredFoods.size(); i++) {
+ System.out.printf("%d) %s" + System.lineSeparator(), i + 1, filteredFoods.get(i).toString());
+ }
+
+ choice = ui.readInt();
+ if (choice <= 0 || choice > filteredFoods.size()) {
+ throw new InvalidIndexException(choice);
+ }
+
+ Food foodToBeAnalysed = (filteredFoods.get(choice - 1));
+ float protein = foodToBeAnalysed.getProtein();
+ System.out.println("Protein(g): " + protein);
+ float totalFat = foodToBeAnalysed.getTotalFat();
+ System.out.println("Total Fat(g): " + totalFat);
+ float saturatedFat = foodToBeAnalysed.getSaturatedFat();
+ System.out.println("Saturated Fat(g): " + saturatedFat);
+ float dietaryFibre = foodToBeAnalysed.getDietaryFibre();
+ System.out.println("Dietary Fibre(g): " + dietaryFibre);
+ float carbohydrates = foodToBeAnalysed.getCarbohydrates();
+ System.out.println("Carbohydrates(g): " + carbohydrates);
+ float sugar = foodToBeAnalysed.getSugar();
+ System.out.println("Sugar(g): " + sugar);
+ float sodium = foodToBeAnalysed.getSodium();
+ System.out.println("Sodium(g): " + sodium);
+
+ }
+}
diff --git a/src/main/java/seedu/commands/TrackCalorieCommand.java b/src/main/java/seedu/commands/TrackCalorieCommand.java
new file mode 100644
index 0000000000..120e59a4ee
--- /dev/null
+++ b/src/main/java/seedu/commands/TrackCalorieCommand.java
@@ -0,0 +1,157 @@
+package seedu.commands;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.constants.DateConstants;
+import seedu.entities.Exercise;
+import seedu.entities.Meal;
+import seedu.exceptions.InvalidCommandException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.parser.DateParser;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+public class TrackCalorieCommand extends Command {
+ private String commandWord;
+ private String userInput;
+ private LocalDate startDate;
+ private LocalDate endDate;
+ private DateTimeFormatter dtf;
+
+
+ public TrackCalorieCommand(String commandWord, String userInput) {
+ this.commandWord = commandWord;
+ this.userInput = userInput;
+ }
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage) throws LifeTrackerException {
+ ArrayList meals = mealStorage.getMeals();
+ ArrayList exercises = exerciseStorage.getExercises();
+ String[] userInputArgs = userInput.split("\\s+");
+ if (userInputArgs.length == 1){
+ throw new MissingArgumentsException(commandWord, "[all] / [/start, /end]");
+ } else if (userInputArgs[1].equals("all") && userInputArgs.length == 2){
+ this.startDate = getStartingDate(meals, exercises);
+ this.endDate = getEndingDate(meals, exercises);
+ getMealsWithinDates(mealStorage, exerciseStorage, ui, startDate, endDate);
+ } else if (userInputArgs.length > 5){
+ throw new InvalidCommandException();
+ } else {
+ parseUserInput();
+ getMealsWithinDates(mealStorage, exerciseStorage, ui, startDate, endDate);
+ }
+ }
+
+ private void parseUserInput() throws LifeTrackerException {
+ dtf = DateConstants.PARSE_DTF;
+ int startDateIndex;
+ int endDateIndex;
+ String startDateIdentifier = "/start";
+ String endDateIdentifier = "/end";
+
+ startDateIndex = userInput.indexOf(startDateIdentifier);
+ if (startDateIndex == -1) {
+ throw new MissingArgumentsException(commandWord, startDateIdentifier);
+ }
+ endDateIndex = userInput.indexOf(endDateIdentifier);
+ if (endDateIndex == -1) {
+ throw new MissingArgumentsException(commandWord, endDateIdentifier);
+ }
+ String startDateString = userInput.substring(startDateIndex + startDateIdentifier.length(), endDateIndex-1)
+ .trim();
+ String endDateString = userInput.substring(endDateIndex + endDateIdentifier.length()).trim();
+ this.startDate = DateParser.parse(startDateString, dtf);
+ this.endDate = DateParser.parse(endDateString, dtf);
+ }
+
+ private void getMealsWithinDates(MealStorage mealStorage, ExerciseStorage exerciseStorage, GeneralUi ui,
+ LocalDate startDate, LocalDate endDate)
+ throws LifeTrackerException {
+ List filteredMeals;
+ List filteredExercises;
+
+ double caloriesConsumed;
+ double caloriesBurnt;
+ DateTimeFormatter dtf = DateConstants.PARSE_DTF;
+ if (startDate == null || endDate == null) {
+ System.out.println("No Meals and Exercises Found!");
+ return;
+ }
+ if (startDate.isAfter(endDate)){
+ throw new LifeTrackerException("Oops! End date cannot be before Start date!");
+ }
+ System.out.println("Showing your history from " + startDate + " to " + endDate);
+ while (startDate.compareTo(endDate) <= 0) {
+ caloriesConsumed = caloriesBurnt = 0;
+ filteredMeals = mealStorage.getMealByDate(startDate);
+ filteredExercises = exerciseStorage.getExercisesByDate(startDate);
+
+ if (filteredMeals.size() == 0 && filteredExercises.size() == 0) {
+ startDate = startDate.plusDays(1);
+ continue;
+ }
+
+ ui.printLine();
+ System.out.printf("Date: %s\n", startDate.format(dtf));
+
+ if (filteredMeals.size() > 0) {
+ for (Meal meal : filteredMeals) {
+ caloriesConsumed += meal.getTotalCalories();
+ }
+ System.out.println("Calories consumed: " + caloriesConsumed);
+ }
+ if (filteredExercises.size() > 0) {
+ for (Exercise exercise : filteredExercises) {
+ caloriesBurnt += exercise.getCaloriesBurnt();
+ }
+ System.out.println("Calories burnt: " + caloriesBurnt);
+ }
+
+ System.out.println("Net calories: " + (caloriesConsumed - caloriesBurnt));
+
+ startDate = startDate.plusDays(1);
+ }
+ }
+
+ private LocalDate getStartingDate(ArrayList meals, ArrayList exercises) {
+ if (meals.size() == 0 && exercises.size() > 0) {
+ return exercises.get(0).getDate();
+ } else if (meals.size() > 0 && exercises.size() == 0) {
+ return meals.get(0).getDate();
+ } else if (meals.size() > 0 && exercises.size() > 0) {
+ if (meals.get(0).getDate().compareTo(exercises.get(0).getDate()) < 0) {
+ return meals.get(0).getDate();
+ } else {
+ return exercises.get(0).getDate();
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private LocalDate getEndingDate(ArrayList meals, ArrayList exercises) {
+ if (meals.size() == 0 && exercises.size() > 0) {
+ return exercises.get(exercises.size()-1).getDate();
+ } else if (meals.size() > 0 && exercises.size() == 0) {
+ return meals.get(meals.size()-1).getDate();
+ } else if (meals.size() > 0 && exercises.size() > 0) {
+ if (meals.get(meals.size()-1).getDate().compareTo(exercises.get(exercises.size()-1).getDate()) > 0) {
+ return meals.get(meals.size()-1).getDate();
+ } else {
+ return exercises.get(exercises.size()-1).getDate();
+ }
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/commands/UpdateUserCommand.java b/src/main/java/seedu/commands/UpdateUserCommand.java
new file mode 100644
index 0000000000..28a3b62885
--- /dev/null
+++ b/src/main/java/seedu/commands/UpdateUserCommand.java
@@ -0,0 +1,195 @@
+package seedu.commands;
+
+import seedu.entities.User;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.InvalidFieldNameException;
+import seedu.exceptions.InvalidFieldInfoFormatException;
+import seedu.exceptions.NegativeFieldInfoException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.ImpossibleValueException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+import java.util.regex.Pattern;
+
+public class UpdateUserCommand extends Command {
+ private String fieldName;
+ private String command;
+ private String userInput;
+ private String updatedInfo;
+
+ public UpdateUserCommand(String command, String userInput){
+ this.command = command;
+ this.userInput = userInput;
+ }
+
+ public boolean isValidFieldName(String fieldName){
+ switch(fieldName){
+ case "/name":
+ return true;
+ case "/weight":
+ return true;
+ case "/height":
+ return true;
+ case "/age":
+ return true;
+ case "/gender":
+ return true;
+ case "/targetWeight":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public void parseCommand() throws LifeTrackerException{
+ String[] userInputSplit = userInput.split(" ");
+ if(command.length() == userInput.length() || userInputSplit.length < 3){
+ throw new MissingArgumentsException(command, "[user information field]/ [new information]");
+ } else if (userInputSplit.length > 3) {
+ throw new ExtraArgumentsException();
+ }
+ fieldName = userInputSplit[1];
+ updatedInfo = userInputSplit[2];
+ if(!isValidFieldName(fieldName)){
+ throw new InvalidFieldNameException(command, fieldName);
+ }
+ }
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ User user = userStorage.getUser();
+ this.parseCommand();
+ switch (fieldName){
+ case "/name":
+ user.setName(updateName());
+ break;
+ case "/weight":
+ user.setWeight(updateWeight());
+ user.setCaloricLimit(
+ User.calculateCaloricNeeds(user.getWeight(), user.getHeight(), user.getAge(), user.getGender())
+ );
+ User.displayNewWeightDifference(user.getWeight(), user.getTargetWeight());
+ break;
+ case "/height":
+ user.setHeight(updateHeight());
+ user.setCaloricLimit(
+ User.calculateCaloricNeeds(user.getWeight(), user.getHeight(), user.getAge(), user.getGender())
+ );
+ break;
+ case "/age":
+ user.setAge(updateAge());
+ user.setCaloricLimit(
+ User.calculateCaloricNeeds(user.getWeight(), user.getHeight(), user.getAge(), user.getGender())
+ );
+ break;
+ case "/gender":
+ user.setGender(updateGender());
+ user.setCaloricLimit(
+ User.calculateCaloricNeeds(user.getWeight(), user.getHeight(), user.getAge(), user.getGender())
+ );
+ break;
+ case "/targetWeight":
+ user.setTargetWeight(updateTargetWeight());
+ User.displayNewTargetWeightDifference(user.getWeight(), user.getTargetWeight());
+ break;
+ default:
+ break;
+ }
+ userStorage.updateUser(user);
+ }
+
+ public String updateName() throws LifeTrackerException{
+ String nameString = updatedInfo;
+ Pattern p = Pattern.compile("[^a-zA-Z_]");
+ String replaced = nameString.replaceAll("_+", " ");
+ boolean hasSpecialChar = p.matcher(nameString).find();
+ if (hasSpecialChar || replaced.isBlank()) {
+ throw new InvalidFieldInfoFormatException(fieldName, updatedInfo);
+ }else {
+ return replaced;
+ }
+ }
+ public float updateWeight() throws LifeTrackerException {
+ String weightString = "dummy";
+
+ weightString = updatedInfo;
+ if (!weightString.matches("[+-]?([0-9]*[.])?[0-9]+")) {
+ throw new InvalidFieldInfoFormatException(fieldName, updatedInfo);
+ }
+ float weight = Float.parseFloat(weightString);
+ if(weight < 0){
+ throw new NegativeFieldInfoException(command, fieldName);
+ }else if(weight > 700){
+ throw new ImpossibleValueException(fieldName,weightString + " kg");
+ }
+ return weight;
+ }
+
+ public float updateHeight() throws LifeTrackerException {
+ String heightString = "dummy";
+ heightString = updatedInfo;
+ if (!heightString.matches("[+-]?([0-9]*[.])?[0-9]+")) {
+ throw new InvalidFieldInfoFormatException(fieldName, updatedInfo);
+ }
+
+ float height = Float.parseFloat(heightString);
+ if(height < 0 ){
+ throw new NegativeFieldInfoException(command, fieldName);
+ }else if(height > 300){
+ throw new ImpossibleValueException(fieldName,heightString + " cm");
+ }
+ return height;
+ }
+
+ public int updateAge() throws LifeTrackerException{
+ String ageString = "dummy";
+
+ ageString = updatedInfo;
+ if(!ageString.matches("[+-]?([0-9]*[.])?[0-9]+")){
+ throw new InvalidFieldInfoFormatException(fieldName, updatedInfo);
+ }
+
+ int age = Integer.parseInt(ageString);
+ if(age < 0){
+ throw new NegativeFieldInfoException(command, fieldName);
+ }else if(age > 120){
+ throw new ImpossibleValueException(fieldName,ageString + " years old");
+ }
+ return age;
+ }
+
+ public String updateGender() throws LifeTrackerException {
+ String genderString = "dummy";
+
+ genderString = updatedInfo;
+ if (genderString.equalsIgnoreCase("male") | genderString.equalsIgnoreCase("female") ) {
+ return genderString;
+ }else{
+ throw new InvalidFieldInfoFormatException(fieldName, updatedInfo);
+ }
+ }
+
+ public float updateTargetWeight() throws LifeTrackerException {
+ String targetWeightString = "dummy";
+
+ targetWeightString = updatedInfo;
+ if(!targetWeightString.matches("[+-]?([0-9]*[.])?[0-9]+")) {
+ throw new InvalidFieldInfoFormatException(fieldName, updatedInfo);
+ }
+
+
+ float targetWeight = Float.parseFloat(targetWeightString);
+ if(targetWeight < 0){
+ throw new NegativeFieldInfoException(command, fieldName);
+ }else if(targetWeight > 700){
+ throw new ImpossibleValueException(fieldName,targetWeightString + " kg");
+ }
+ return targetWeight;
+ }
+}
diff --git a/src/main/java/seedu/commands/ViewUserCommand.java b/src/main/java/seedu/commands/ViewUserCommand.java
new file mode 100644
index 0000000000..32f90cf5ba
--- /dev/null
+++ b/src/main/java/seedu/commands/ViewUserCommand.java
@@ -0,0 +1,131 @@
+package seedu.commands;
+
+import java.time.LocalDate;
+import seedu.entities.CaloricIntake;
+import seedu.entities.User;
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.exceptions.InvalidFieldNameException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+import seedu.ui.CalorieUi;
+
+
+public class ViewUserCommand extends Command {
+ private String fieldName;
+ private String command;
+ private String userInput;
+
+ public ViewUserCommand(String command, String userInput){
+ this.command = command;
+ this.userInput = userInput;
+ }
+
+ public boolean isValidFieldName(String fieldName){
+ switch(fieldName){
+ case "/name":
+ return true;
+ case "/weight":
+ return true;
+ case "/height":
+ return true;
+ case "/age":
+ return true;
+ case "/gender":
+ return true;
+ case "/caloricLimit":
+ return true;
+ case "/caloriesLeft":
+ return true;
+ case "/targetWeight":
+ return true;
+ default:
+ return false;
+ }
+ }
+ public void parseCommand() throws LifeTrackerException{
+ String[] userInputSplit = userInput.split(" ");
+ if(command.length() == userInput.length() || userInputSplit.length < 2){
+ throw new MissingArgumentsException(command, "[fieldName]");
+ } else if (userInputSplit.length > 2) {
+ throw new ExtraArgumentsException();
+ }
+ fieldName = userInputSplit[1];
+
+ if(!isValidFieldName(fieldName)){
+ throw new InvalidFieldNameException(command, fieldName);
+ }
+
+ }
+
+ @Override
+ public void execute(GeneralUi ui, FoodStorage foodStorage, MealStorage mealStorage, UserStorage userStorage,
+ ExerciseStorage exerciseStorage)
+ throws LifeTrackerException {
+ User user = userStorage.getUser();
+ this.parseCommand();
+ CalorieUi calorieUi = new CalorieUi();
+ CaloricIntake meals = new CaloricIntake(mealStorage.getMealByDate(LocalDate.now()));
+ switch (fieldName) {
+ case "/name":
+ String name = user.getName();
+ if(name.isBlank()){
+ ui.printFieldNotStored();
+ }else{
+ ui.printName(name);
+ }
+ break;
+ case "/weight":
+ float weight = user.getWeight();
+ if(weight == 0.0){
+ ui.printFieldNotStored();
+ }else {
+ ui.printWeight(weight);
+ }
+ break;
+ case "/height":
+ float height = user.getHeight();
+ if(height == 0.0){
+ ui.printFieldNotStored();
+ }else {
+ ui.printHeight(height);
+ }
+ break;
+ case "/age":
+ int age = user.getAge();
+ if(age == 0){
+ ui.printFieldNotStored();
+ }else{
+ ui.printAge(age);
+ }
+ break;
+ case "/gender":
+ String gender = user.getGender();
+ if(gender.isBlank()){
+ ui.printFieldNotStored();
+ }else {
+ ui.printGender(gender);
+ }
+ break;
+ case "/caloricLimit":
+ double caloricLimit = user.getCaloricLimit();
+ calorieUi.showDailyCaloricLimit(caloricLimit);
+ break;
+ case "/caloriesLeft":
+ double calorieIntake = meals.getTotalDailyCalories();
+ double caloriesLeft = user.getCaloriesLeft(calorieIntake);
+ calorieUi.showRemainingIntake(caloriesLeft);
+ break;
+ case "/targetWeight":
+ float targetWeight = user.getTargetWeight();
+ System.out.println("Target Weight: " + targetWeight + " kg");
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/src/main/java/seedu/constants/DateConstants.java b/src/main/java/seedu/constants/DateConstants.java
new file mode 100644
index 0000000000..171425ff8a
--- /dev/null
+++ b/src/main/java/seedu/constants/DateConstants.java
@@ -0,0 +1,13 @@
+package seedu.constants;
+
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+public class DateConstants {
+ public static final String PARSE_FORMAT = "d/M/yyyy";
+ public static final String DATABASE_FORMAT = "d/M/yyyy";
+ public static final DateTimeFormatter PARSE_DTF =
+ DateTimeFormatter.ofPattern(PARSE_FORMAT, Locale.ENGLISH);
+ public static final DateTimeFormatter DATABASE_DTF =
+ DateTimeFormatter.ofPattern(DATABASE_FORMAT, Locale.ENGLISH);
+}
diff --git a/src/main/java/seedu/database/ExampleData.java b/src/main/java/seedu/database/ExampleData.java
new file mode 100644
index 0000000000..48d4c49530
--- /dev/null
+++ b/src/main/java/seedu/database/ExampleData.java
@@ -0,0 +1,41 @@
+package seedu.database;
+
+public class ExampleData {
+ private static final String[] exerciseExampleData = {
+ "Weight Lifting: General, 30 minutes workout, 108",
+ "Aerobics: water, 30 minutes workout, 144",
+ "Stretching, 30 minutes workout, 144",
+ "Yoga, 30 minutes workout, 144",
+ "Calisthenics: moderate, 30 minutes workout, 162",
+ "Frisbee, 30 minutes workout, 108",
+ "Volleyball, 30 minutes workout, 108",
+ "Water Volleyball, 30 minutes workout, 108",
+ "Walking, 30 minutes workout, 133",
+ "Badminton, 30 minutes workout, 141",
+ "Softball, 30 minutes workout, 180",
+ "Dancing, 30 minutes workout, 216",
+ "Swimming, 30 minutes workout, 216",
+ "Soccer, 30 minutes workout, 252",
+ "Rock Climbing, 30 minutes workout, 282",
+ "Jogging, 30 minutes workout; 5 mph (12 min/mile), 288",
+ "Martial Arts, 30 minutes workout, 360",
+ "Running, 30 minutes workout, 10mph (6 min/mile)",
+ };
+
+ private static final String[] mealExampleData = {
+ "Creamy Chicken Spaghetti (Small) from Western",
+ "Alfredo (Small) from Western",
+ "Seafood Marinara (Small) from Western",
+ "Fresh Mushrooms with Ramen (Regular) from Ramen",
+ "Double Mixed Fish Spinach Soup (Regular) from Ramen",
+ "Fried Fish Spinach Soup (Regular) from Ramen",
+ };
+
+ public static String[] getExampleExerciseData() {
+ return exerciseExampleData;
+ }
+
+ public static String[] getExampleMealData() {
+ return mealExampleData;
+ }
+}
diff --git a/src/main/java/seedu/database/ExerciseData.java b/src/main/java/seedu/database/ExerciseData.java
new file mode 100644
index 0000000000..14842d5227
--- /dev/null
+++ b/src/main/java/seedu/database/ExerciseData.java
@@ -0,0 +1,27 @@
+package seedu.database;
+
+public class ExerciseData {
+ private static final String[] exerciseData = {
+ "Weight Lifting: General, 30 minutes workout, 108",
+ "Aerobics: water, 30 minutes workout, 144",
+ "Stretching, 30 minutes workout, 144",
+ "Yoga, 30 minutes workout, 144",
+ "Calisthenics: moderate, 30 minutes workout, 162",
+ "Frisbee, 30 minutes workout, 108",
+ "Volleyball, 30 minutes workout, 108",
+ "Water Volleyball, 30 minutes workout, 108",
+ "Walking, 30 minutes workout, 133",
+ "Badminton, 30 minutes workout, 141",
+ "Softball, 30 minutes workout, 180",
+ "Dancing, 30 minutes workout, 216",
+ "Swimming, 30 minutes workout, 216",
+ "Soccer, 30 minutes workout, 252",
+ "Rock Climbing, 30 minutes workout, 282",
+ "Running, 30 minutes workout; 5 mph (12 min/mile), 288",
+ "Martial Arts, 30 minutes workout, 360",
+ };
+
+ public static String[] getExerciseData() {
+ return exerciseData;
+ }
+}
diff --git a/src/main/java/seedu/database/FoodData.java b/src/main/java/seedu/database/FoodData.java
new file mode 100644
index 0000000000..b95cc37f08
--- /dev/null
+++ b/src/main/java/seedu/database/FoodData.java
@@ -0,0 +1,458 @@
+package seedu.database;
+
+public final class FoodData {
+ private static final String[] foodData = {
+ "ID,Type,Name,Store,Store Number,Energy (Kcal),Protein (g),Total Fat (g)," +
+ "Saturated Fat (g),Dietary Fibre (g),Carbohyrate (g),Sugar (g),Sodium (g)",
+ "0,Dish,Black Pepper Chicken Chop ," +
+ "Western,1,775,42.4,51.7,,,31.6,6.9,",
+ "1,Dish,Chicken Cutlet ,Wester" +
+ "n,1,966,47.8,60.1,,,54.9,7.2,",
+ "2,Dish,Grilled Dory Fish ,West" +
+ "ern,1,530,45.1,21.3,,,37.2,8.2,",
+ "3,Dish,Fish & Chip ,Western" +
+ ",1,838,46.4,49.1,,,50.7,8.3,",
+ "4,Dish,Black Pepper Ribeye Steak ," +
+ "Western,1,807,44.9,45.6,,,53.2,9.3,",
+ "5,Dish,Combo Set 1: Ribeye Steak & Grilled" +
+ " Chicken,Western,1,831,43.2,48.7,,,52.5,9,",
+ "6,Dish,Combo Set 2: Ribeye Steak & Grille" +
+ "d Fish,Western,1,680,41.3,33.2,,,52.4,9.2,",
+ "7,Dish,Combo Set 3: Ribeye Steak & Grille" +
+ "d Salmon,Western,1,776,42.4,43.6,,,52.3,9,",
+ "8,Dish,Combo Set 4: Grilled Chicken Chop & Gr" +
+ "illed Salmon,Western,1,846,43.7,50.8,,,51.1,9,",
+ "9,Dish,Combo Set 5: Grilled Chicken Chop & Grill" +
+ "ed Dory Fish,Western,1,750,42.7,40.3,,,51.3,9.2,",
+ "10,Dish,Arrabiata ,Wester" +
+ "n,1,295,10.3,5.1,,,50,7.3,",
+ "11,Dish,Pomodoro ,Western" +
+ ",1,341,13.9,2.7,,,69,21.6,",
+ "12,Dish,Creamy Chicken Spaghetti (Smal" +
+ "l) ,Western,1,755,31.6,54.3,,,34.1,3.7,",
+ "13,Dish,Creamy Chicken Spaghetti (Nor" +
+ "mal) ,Western,1,822,34,54.7,,,47.2,4,",
+ "14,Dish,Creamy Chicken Spaghetti (Upsiz" +
+ "e) ,Western,1,901,36.9,55.2,,,62.7,4.3,",
+ "15,Dish,Creamy Chicken Ham & Mushroom Spaghett" +
+ "i (Small) ,Western,1,571,19.2,38.2,,,37.8,4.2,",
+ "16,Dish,Creamy Chicken Ham & Mushroom Spaghett" +
+ "i (Normal) ,Western,1,638,21.7,38.6,,,50.9,4.4,",
+ "17,Dish,Creamy Chicken Ham & Mushroom Spaghet" +
+ "ti (Upsize) ,Western,1,717,24.6,39,,,66.4,4.7,",
+ "18,Dish,Prawns & Mushroom Spaghetti (Sm" +
+ "all) ,Western,1,557,20.5,36.5,,,36.9,4,",
+ "19,Dish,Prawns & Mushroom Spaghetti (N" +
+ "ormal) ,Western,1,624,23,36.9,,,50,4.2,",
+ "20,Dish,Prawns & Mushroom Spaghetti (Ups" +
+ "ize) ,Western,1,703,25.9,37.3,,,65.4,4.5,",
+ "21,Dish,Hot Chicken Spaghetti (Smal" +
+ "l) ,Western,1,298,16.6,8.6,,,36.9,7,",
+ "22,Dish,Hot Chicken Spaghetti (Norm" +
+ "al) ,Western,1,365,19.1,9,,,50,7.3,",
+ "23,Dish,Hot Chicken Spaghetti (Upsiz" +
+ "e) ,Western,1,444,22,9.4,,,65.5,7.6,",
+ "24,Dish,Creamy Sausage & Mushroom Spaghetti" +
+ " (Small) ,Western,1,688,28.8,46.7,,,37.6,4,",
+ "25,Dish,Creamy Sausage & Mushroom Spaghetti" +
+ " (Normal) ,Western,1,755,31.3,47,,,50.7,4.2,",
+ "26,Dish,Creamy Sausage & Mushroom Spaghetti " +
+ "(Upsize) ,Western,1,834,34.2,47.5,,,66.1,4.5,",
+ "27,Dish,Alfredo (Small) ,Weste" +
+ "rn,1,651,28.9,42.8,,,37.8,4.2,",
+ "28,Dish,Alfredo (Normal) ,West" +
+ "ern,1,718,31.3,43.2,,,50.9,4.4,",
+ "29,Dish,Alfredo (Upsize) ,West" +
+ "ern,1,797,34.2,43.7,,,66.4,4.7,",
+ "30,Dish,Chicken Patty Spaghetti ,W" +
+ "estern,1,530,29.3,19.1,,,58.4,7.6,",
+ "31,Dish,Chicken Cheese Ball Spaghetti" +
+ " ,Western,1,501,24.3,16.7,,,61.7,9.6,",
+ "32,Dish,Salmon e Funghi Spaghetti (Sma" +
+ "ll) ,Western,1,715,31.2,49.4,,,36.9,4,",
+ "33,Dish,Salmon e Funghi Spaghetti (Nor" +
+ "mal) ,Western,1,782,33.7,49.7,,,50,4.2,",
+ "34,Dish,Salmon e Funghi Spaghetti (Ups" +
+ "ize) ,Western,1,861,36.6,50.2,,,65.4,5,",
+ "35,Dish,Seafood Marinara (Small) " +
+ ",Western,1,373,36.1,7.8,,,37.9,7,",
+ "36,Dish,Seafood Marinara (Normal" +
+ ") ,Western,1,440,38.5,8.1,,,51,7,",
+ "37,Dish,Seafood Marinara (Upsize)" +
+ " ,Western,1,519,41.4,8.6,,,66.5,8,",
+ "38,Dish,Creamy Fish Pasta (Small)" +
+ " ,Western,1,616,32.1,39,,,34.1,4,",
+ "39,Dish,Creamy Fish Pasta (Normal)" +
+ " ,Western,1,683,34.6,39.4,,,47.2,4,",
+ "40,Dish,Creamy Fish Pasta (Upsize)" +
+ " ,Western,1,762,37.5,39.8,,,62.7,4,",
+ "41,Dish,Baked Beans & Fries & Saus" +
+ "age,Western,1,359,16.8,22,,,21.7,4,",
+ "42,Dish,Baked Beans & Mashed Potato & Sa" +
+ "usage ,Western,1,447,18.6,24.6,,,35.6,6,",
+ "43,Side,Mashed Potato,West" +
+ "ern,1,89,1.9,2.5,,,13.8,2,",
+ "44,Side,Sunny Side Up,We" +
+ "stern,1,102,7,8,,,0.5,0,",
+ "45,Side,French Fries,Weste" +
+ "rn,1,164,1.3,11.6,,,13.5,0,",
+ "46,Side,Hot Dog,Western," +
+ "1,153,13.4,10.3,,,0.7,0,",
+ "47,Side,Spaghetti,Wester" +
+ "n,1,157,5.8,0.9,,,30.8,1,",
+ "48,Side,Tasty Rice,Wester" +
+ "n,1,210,4.2,0.8,,,46.7,0,",
+ "49,Side,Chicken Ham,Wes" +
+ "tern,1,36,3.8,1.9,,,1,0,",
+ "50,Side,Coleslaw,Western" +
+ ",1,68,0.7,4.7,,,4.9,9.4,",
+ "51,Dish,Signature Trio Eggs Spinach " +
+ "Soup (Regular),Ramen,10,256,0.0,0.0,0.0,0.0,0.0,0.0,",
+ "52,Dish,Signature Trio Eggs Spinach So" +
+ "up (Small Portion),Ramen,10,119,,,,,,0,",
+ "53,Dish,Seafood Spinach Soup " +
+ "(Regular),Ramen,10,188,,,,,,1,",
+ "54,Dish,Seafood Spinach Soup (Sm" +
+ "all Portion),Ramen,10,113,,,,,,0,",
+ "55,Dish,Sliced Fish Spinach Sou" +
+ "p (Regular),Ramen,10,224,,,,,,0,",
+ "56,Dish,Sliced Fish Spinach Soup (" +
+ "Small Portion),Ramen,10,134,,,,,,0,",
+ "57,Dish,Fried Fish Spinach Soup" +
+ " (Regular),Ramen,10,282,,,,,,0,",
+ "58,Dish,Fried Fish Spinach Soup (S" +
+ "mall Portion),Ramen,10,169,,,,,,0,",
+ "59,Dish,Double Mixed Fish Spinach " +
+ "Soup (Regular),Ramen,10,257,,,,,,0,",
+ "60,Dish,Double Mixed Fish Spinach Sou" +
+ "p (Small Portion),Ramen,10,191,,,,,,0,",
+ "61,Dish,Fresh Mushrooms with Ram" +
+ "en (Regular),Ramen,10,303,,,,,,5,",
+ "62,Dish,Fresh Mushrooms with Ramen " +
+ "(Small Portion),Ramen,10,182,,,,,,3,",
+ "63,Dish,Mala Dry Ramen w Chicken" +
+ " Cheeseballs,Ramen,10,676,,,,,,8,",
+ "64,Dish,Mala Dry Ramen w Fuzhou" +
+ " Fishballs,Ramen,10,713,,,,,,10,",
+ "65,Dish,Mala Beef Ramen " +
+ "Soup,Ramen,10,644,,,,,,7,",
+ "66,Side,Egg (side)," +
+ "Ramen,10,28,,,,,,0,",
+ "67,Side,Century Egg (s" +
+ "ide),Ramen,10,1,,,,,,0,",
+ "68,Side,Salted Egg (si" +
+ "de),Ramen,10,7,,,,,,0,",
+ "69,Side,Wolfberry (si" +
+ "de),Ramen,10,8,,,,,,1,",
+ "70,Side,Spinach (sid" +
+ "e),Ramen,10,2,,,,,,0,",
+ "71,Side,Minced Pork (si" +
+ "de),Ramen,10,135,,,,,,0,",
+ "72,Side,Sliced Fish (si" +
+ "de),Ramen,10,59,,,,,,0,",
+ "73,Side,Fried Fish (sid" +
+ "e),Ramen,10,117,,,,,,0,",
+ "74,Side,Prawns (side" +
+ "),Ramen,10,55,,,,,,0,",
+ "75,Side,Chicken Cheeseballs" +
+ " (side),Ramen,10,94,,,,,,5,",
+ "76,Side,Fuzhou Fishballs " +
+ "(side),Ramen,10,93,,,,,,6,",
+ "77,Side,Sliced Beef (si" +
+ "de),Ramen,10,107,,,,,,0,",
+ "78,Side,White Rice (sid" +
+ "e),Ramen,10,232,,,,,,0,",
+ "79,Side,Thick Bee Hoon (s" +
+ "ide),Ramen,10,276,,,,,,0,",
+ "80,Side,Thin Bee Hoon (s" +
+ "ide),Ramen,10,251,,,,,,0,",
+ "81,Side,Brown Rice (sid" +
+ "e),Ramen,10,218,,,,,,0,",
+ "82,Side,Koka Noodle (si" +
+ "de),Ramen,10,286,,,,,,4,",
+ "83,Side,Ee Mee (side)" +
+ ",Ramen,10,377,,,,,,2,",
+ "84,Side,Ramen (side)" +
+ ",Ramen,10,262,,,,,,4,",
+ "85,Ingredient,Mala Sauce (Non-Spicy Bas" +
+ "e),Mala,4,46,1.7,0.1,0,0.4,9.7,5.3,1.0",
+ "86,Ingredient,Coriander," +
+ "Mala,4,0,0,0,0,0.1,0,0,0.0",
+ "87,Ingredient,White Rice,Mala,4" +
+ ",237,4.7,0.8,0.2,0.7,52.6,0.2,0.0",
+ "88,Ingredient,Sotong Ring,Mala" +
+ ",4,51,8.6,0.8,0.2,0,1.7,1.7,0.0",
+ "89,Ingredient,Prawn,Mala," +
+ "4,34,7.8,0.2,0.1,0,0,0,0.1",
+ "90,Ingredient,Fish Slice,Mala," +
+ "4,57,12.8,0.5,0.1,0,0.1,0.1,0.1",
+ "91,Ingredient,Chicken Gizzard" +
+ ",Mala,4,45,8.5,1,0.3,0,0,0,0.1",
+ "92,Ingredient,Beef Slice,Mal" +
+ "a,4,109,11.8,6.9,3.3,0,0,0,0.1",
+ "93,Ingredient,Shitake Mushroom" +
+ ",Mala,4,16,1,0.2,0,1.2,2,1.1,0.0",
+ "94,Ingredient,King Oyster Mushroom" +
+ ",Mala,4,13,1.3,0.2,0,0.7,1.4,0.7,0.0",
+ "95,Ingredient,Xiao Bai Cai,Mal" +
+ "a,4,7,0.8,0.1,0,0.5,0.6,0.6,0.1",
+ "96,Ingredient,Wintermelon,Mala" +
+ ",4,31,0.3,2.4,0.6,0.9,1.7,1,0.2",
+ "97,Ingredient,Tomato,Mala," +
+ "4,16,1,0.1,0,0.4,2.6,2.6,0.0",
+ "98,Ingredient,Potato,Mala,4" +
+ ",45,1.5,0.1,0,1.1,8.6,0.4,3",
+ "99,Ingredient,Lady's Finger,Mala" +
+ ",4,11.2,0.6,0,0,1.1,2.1,2.1,0.0",
+ "100,Ingredient,Kang Kong,Mal" +
+ "a,4,9,1.1,0.1,0,0.9,0.4,0,0.1",
+ "101,Ingredient,Cucumber,Mal" +
+ "a,4,20,0.3,0,0,0.3,1.9,1.9,0.0",
+ "102,Ingredient,Cauliflower," +
+ "Mala,4,15,2,0,0,1.4,3,2.9,0.1",
+ "103,Ingredient,Cabbage,Mal" +
+ "a,4,9,1.4,0.3,0,0,2.8,0,0.0",
+ "104,Ingredient,Broccoli,Mal" +
+ "a,4,12,1.3,0,0,1.2,0.9,0.9,0.0",
+ "105,Ingredient,Brinjal,Mala" +
+ ",4,11,0.7,0,0,0.4,2.3,2.3,0.0",
+ "106,Ingredient,Taugay,Mala,4" +
+ ",437,1.5,0.1,0,0.9,0.8,0.5,0.0",
+ "107,Ingredient,Potato Starch Noo" +
+ "dle,Mala,4,349,0,0,0,0,108.1,0,0",
+ "108,Ingredient,Instant Noodle,Mala" +
+ ",4,170,8.1,11.7,5.9,0.6,52.9,2.4,0.1",
+ "109,Ingredient,Taiwan Sausage,Ma" +
+ "la,4,156,7.2,13,5.8,0,6.2,3.1,0.3",
+ "110,Ingredient,Seaweed Chicken,M" +
+ "ala,4,82,7.5,12,2.5,1,4.9,1.4,0.3",
+ "111,Ingredient,Saito Fish Cake,Ma" +
+ "la,4,48,12.1,3,1.6,1.1,1.9,0.8,0.8",
+ "112,Ingredient,Quail Egg,Mal" +
+ "a,4,46,4,3.4,1.1,0,0.1,0.1,0.0",
+ "113,Ingredient,Mushroom Ball," +
+ "Mala,4,47,5.8,0.5,0,0,3.9,0,0",
+ "114,Ingredient,Mini Fish Ball,Mala" +
+ ",4,210,6.9,1.3,0.2,0.5,1.8,0.6,0.2",
+ "115,Ingredient,Luncheon Meat,Mala" +
+ ",4,107,6.2,19.3,7.4,0.5,2.8,0,0.6",
+ "116,Ingredient,Mini Sausage,Mala" +
+ ",4,141,4.5,8.3,3.6,0,3.9,1.9,0.2",
+ "117,Ingredient,Fish Ball (Fried),Ma" +
+ "la,4,99,10.5,9.8,1.2,0.7,2.8,0.9,0.4",
+ "118,Ingredient,Fish Tau Foo,Mala" +
+ ",4,135,4.8,5.8,0.8,0.7,7,2.8,0.3",
+ "119,Ingredient,Cuttlefish Ball,Mal" +
+ "a,4,21,8.5,7.1,2.8,1.5,9.4,1.5,0.5",
+ "120,Ingredient,Cuttlefish,Ma" +
+ "la,4,11,4.4,0.2,0,0,0.2,0,0.1",
+ "121,Ingredient,Crabstick,Ma" +
+ "la,4,100,1.2,0,0,0,0.6,0,0.1",
+ "122,Ingredient,Crab Claw,Mala" +
+ ",4,64,3.8,4.3,2,0,11.6,1.9,0.4",
+ "123,Ingredient,Crab Ball,Mala," +
+ "4,42,5.8,2,0.6,0.9,5.8,1.5,0.5",
+ "124,Ingredient,Chickuwa,Mal" +
+ "a,4,95,5.5,0.5,0,0,3.2,0,0.4",
+ "125,Ingredient,Chicken Hotdog,Mal" +
+ "a,4,122,5.5,7,1.9,0.5,2.4,0.8,0.5",
+ "126,Ingredient,Cheese Tofu,Mala," +
+ "4,33,6.4,9.1,3.6,0.7,3.7,2.1,0.5",
+ "127,Ingredient,Bermuda Triangle Tofu (Ta" +
+ "upok),Mala,4,12,3.3,1.5,0.2,0.2,1.5,0.6,3",
+ "128,Ingredient,White Radish,Mal" +
+ "a,4,126,0.6,0.1,0,0.8,2.2,2.2,0.1",
+ "129,Ingredient,Peanut,Mala,4,17" +
+ "0.5,7.4,14.1,2.1,2.5,2.7,1.5,0.3",
+ "130,Ingredient,Thick Beehoon,Mala" +
+ ",4,126.1,2.3,0.4,0.1,0.4,28.3,0,7",
+ "131,Ingredient,Tau Kwa,Mala" +
+ ",4,50,5,2.3,0.4,0.2,2.3,1,4",
+ "132,Ingredient,Lotus Root,Mala" +
+ ",4,51,1.2,0.1,0,2.4,12.3,0.4,34",
+ "133,Ingredient,Kelp,Mala,4,2" +
+ "7,1.8,0.4,0.1,0.3,5.2,0.4,0.5",
+ "134,Ingredient,Enoki Mushroom,M" +
+ "ala,4,13,0.9,0.1,0,0.9,1.8,0.1,1",
+ "135,Ingredient,Black Fungus," +
+ "Mala,4,19,1.3,0.2,0,2.3,3,0,8",
+ "136,Ingredient,Beancurd Skin (Non-Frie" +
+ "d),Mala,4,77,8.2,2.9,0.5,3.4,0.5,0.5,0",
+ "137,Ingredient,Beancurd Skin (Fried)" +
+ ",Mala,4,76,4.4,5.5,0.7,1.8,0.3,0.3,0",
+ "138,Ingredient,Mala Sauce (Very Spicy " +
+ "Base),Mala,4,257,0.6,27.7,4.8,1,2,0.5,2",
+ "139,Ingredient,Mala Sauce (Spicy Bas" +
+ "e),Mala,4,191,0.6,20.2,3.5,1,2,0.5,2",
+ "140,Ingredient,Mala Sauce (Slightly Spicy" +
+ " Base),Mala,4,95,0.3,10.1,1.7,0.5,1,0.2,1",
+ "141,Dish,White Chicken Rice,Chicken Ri" +
+ "ce,12,533,19.5,17.3,5.7,1.6,74.6,6,5.0",
+ "142,Dish,Char Siew Rice,Chicken Rice,1" +
+ "2,697,21.9,29.6,11.2,1.6,86.1,16.7,3.7",
+ "143,Dish,Roasted Pork Rice,Chicken Ric" +
+ "e,12,680,22,29.6,11.1,3.1,80.3,5.6,4.5",
+ "144,Dish,Roasted Chicken Noodles (Egg Noodles) - Reg" +
+ "ular,Chicken Rice,12,320,17.1,7.7,2,2.9,43.3,2.3,1.6",
+ "145,Dish,Roasted Chicken Noodles (Egg Noodles) - Lar" +
+ "ge,Chicken Rice,12,388,25.3,11.5,3.2,3,43.6,2.3,1.7",
+ "146,Dish,Roasted Chicken Noodles (Hor Fun) - Regula" +
+ "r,Chicken Rice,12,341,12.8,6.9,2.5,1.5,56.7,1.7,1.6",
+ "147,Dish,Roasted Chicken Noodles (Hor Fun) - La" +
+ "rge,Chicken Rice,12,21,10.7,3.7,1.7,57,1.7,1.7,",
+ "148,Dish,White Chicken Noodles (Egg Noodles) - Regul" +
+ "ar,Chicken Rice,12,307,15.2,7.5,2.2,2.7,42.4,1.7,2.6",
+ "149,Dish,White Chicken Noodles (Egg Noodles) - Large" +
+ ",Chicken Rice,12,365,21.3,11.1,3.6,2.7,42.4,1.7,2.6",
+ "150,Dish,White Chicken Noodles (Hor Fun) - Regula" +
+ "r,Chicken Rice,12,328,10.9,6.7,2.7,1.4,55.8,1,2.6",
+ "151,Dish,White Chicken Noodles (Hor Fun) - Large" +
+ ",Chicken Rice,12,386,17,10.4,4.1,1.4,55.8,1,2.6",
+ "152,Dish,Char Siew Noodles (Egg Noodles) - Regular" +
+ ",Chicken Rice,12,410,16.4,13.6,5,2.7,53.5,12.4,1.3",
+ "153,Dish,Char Siew Noodles (Egg Noodles) - Large,C" +
+ "hicken Rice,12,529,23.7,23.4,9.1,2.7,53.8,12.4,1.4",
+ "154,Dish,Char Siew Noodles (Hor Fun) - Regular,Ch" +
+ "icken Rice,12,431,12.1,12.9,5.5,1.4,66.9,11.7,1.3",
+ "155,Dish,Char Siew Noodles (Hor Fun) - Large,Chi" +
+ "cken Rice,12,550,19.4,22.7,9.6,1.4,67.2,11.7,1.4",
+ "156,Dish,Roasted Pork Noodles (Egg Noodles) - Regul" +
+ "ar,Chicken Rice,12,395,16.6,13.9,5,4.2,47.8,1.4,2.0",
+ "157,Dish,Roasted Pork Noodles (Egg Noodles) - Large" +
+ ",Chicken Rice,12,511,23.7,23.4,9.1,4.2,48.1,1.4,2.1",
+ "158,Dish,Roasted Pork Noodles (Hor Fun) - Regular," +
+ "Chicken Rice,12,416,12.3,13.1,5.5,2.8,61.2,0.7,2.0",
+ "159,Dish,Roasted Pork Noodles (Hor Fun) - Large,C" +
+ "hicken Rice,12,533,19.4,22.7,9.6,2.8,61.4,0.7,2.2",
+ "160,Dish,Roasted Chicken Rice + Veg + Half Egg Set Me" +
+ "al,Chicken Rice,12,604,28.1,21.2,5.7,2.4,75.4,6.1,4.2",
+ "161,Dish,White Chicken Rice + Veg + Half Egg Set Mea" +
+ "l,Chicken Rice,12,582,24.1,20.9,6.1,2.1,74.2,5.5,5.2",
+ "162,Dish,Char Siew Rice + Veg + Half Egg Set Meal,C" +
+ "hicken Rice,12,746,26.5,33.2,11.6,2.1,85.6,16.2,3.9",
+ "163,Dish,Roasted Pork Rice + Veg + Half Egg Set Meal" +
+ ",Chicken Rice,12,728,26.5,33.2,11.6,3.6,79.9,5.1,4.7",
+ "164,Dish,Curry Chicken Bee Hoon,Chicken R" +
+ "ice,12,744,15.8,34.7,26.9,4.9,90.9,30,6.3",
+ "165,Dish,Curry Chicken Noodles,Chicken Ri" +
+ "ce,12,777,21.7,37.8,27.6,6,85.8,28.7,6.3",
+ "166,Dish,Chicken Shredded Porridge,Chick" +
+ "en Rice,12,8.3,3.8,1.4,0.2,20.6,0.9,2.2,",
+ "167,Dish,Roasted Pork Rice Soup,Chicke" +
+ "n Rice,12,9.7,10.2,4.2,1.7,26,0.6,1.6,",
+ "168,Side,Roasted Chicken,Chicken " +
+ "Rice,12,8.2,3.9,1.2,0.2,1.2,1,7,",
+ "169,Side,White Chicken,Chicken Ri" +
+ "ce,12,6.3,3.7,1.4,0,0.3,0.3,1.7,",
+ "170,Side,Char Siew,Chicken Ric" +
+ "e,12,7.5,9.8,4.2,0,11.4,11,0.4,",
+ "171,Side,Roasted Pork,Chicken Rice" +
+ ",12,264,14.9,19.6,8.2,1.5,6,0,1.3",
+ "172,Side,Veg 1 (Cai Xin),Chicken " +
+ "Rice,12,0.8,0.1,0,0.7,0.4,0.5,0.3,",
+ "173,Side,Veg 2 (Nonya Chap Chye),Chick" +
+ "en Rice,12,2.1,1.1,0.2,0.6,1.3,0.7,0.2,",
+ "174,Side,Braised Egg,Chicken " +
+ "Rice,12,8,7,0.9,0,0.6,0.6,0.3,",
+ "175,Side,Sausage,Chicken Rice," +
+ "12,6.2,9.6,3.8,0.4,2.4,0.5,0.3,",
+ "176,Side,Liver + Gizzards,Chicken" +
+ " Rice,12,17.5,2.6,0.8,0,0.3,0,0.0,",
+ "177,Side,Roasted Chicken (1 Pax),Chick" +
+ "en Rice,12,16.4,7.7,2.4,0.3,1.5,1.8,",
+ "178,Side,Roasted Chicken (2 Pax),Chicke" +
+ "n Rice,12,32.8,15.4,4.7,0.7,3,2.1,1.7,",
+ "179,Side,Roasted Chicken (3 Pax),Chicke" +
+ "n Rice,12,49.3,23.1,7.1,1,4.5,3.1,2.5,",
+ "180,Side,White Chicken (1 Pax),Chicke" +
+ "n Rice,12,12.5,7.4,2.8,0,0.3,0.3,1.7,",
+ "181,Side,White Chicken (2 Pax),Chicken" +
+ " Rice,12,24.9,14.7,5.6,0,0.6,0.7,3.4,",
+ "182,Side,White Chicken (3 Pax),Chicke" +
+ "n Rice,12,37.4,22.1,8.4,0,0.8,1,5.2,",
+ "183,Side,Plain Chicken Rice,Chicken Ri" +
+ "ce,12,411,6.9,10,2.9,1.4,73.4,4.7,3.3",
+ "184,Side,White Rice,Chicken Rice" +
+ ",12,5.9,1.1,0.2,0.8,65.8,0.2,11,",
+ "185,Dish,Mee Rebus,Nasi Padang," +
+ "13,372,19.8,15.3,,,37.6,4.4,0.0",
+ "186,Dish,Mee Siam,Nasi Padang," +
+ "13,317,15.5,13.0,,,33.8,5.2,0.0",
+ "187,Dish,Mee Soto,Nasi Padang," +
+ "13,557,21.6,36.1,,,37.1,7.2,0.0",
+ "188,Dish,Mee Bundung,Nasi Padang," +
+ "13,407,33.2,8.6,,,46.8,17.3,0.0",
+ "189,Dish,Lotong,Nasi Padang," +
+ "13,1187,33.9,33.7,,,184.7,11.8,0.0",
+ "190,Dish,Mee Goreng,Nasi Padang," +
+ "13,324, 14.6,14.4,,,32.8,4.4,0.0",
+ "191,Dish,Fried Kway Teow,Nasi Padang," +
+ "13,414, 31.6,14.3,,,39.6,3.9,0.0",
+ "192,Dish,Fried Been Hoon,Nasi Padang," +
+ "13,356,30.4,12.7,,,29.0,5.0,0.0",
+ "193,Dish,Mee Hong Kong,Nasi Padang," +
+ "13,291,15.6,8.7,,,36.1,4.2,0.0",
+ "194,Dish,Nasi Goreng Pattaya,Nasi Padang," +
+ "13,620,27.4,29.7,,,60.5,9.0,0.0",
+ "195,Dish,Chicken Briyani,Nasi Padang," +
+ "13,866,40.6,47.2,,,68.5,5.0,0.0",
+ "196,Dish,Nasi Lemak Set 1 (Chicken Wing + Egg),Nasi Padang," +
+ "13,1204,35.4,56.2,,,140.0,4.8,0.0",
+ "197,Dish,Nasi Lemak Set 2 (Fish Fillet + Hotdog + Ikan Bilis),Nasi Padang," +
+ "13,1211,48.5,50.2,,,141.2,4.5,0.0",
+ "198,Side,Curry Puff (Potato),Nasi Padang," +
+ "13,425,5.6, 1.2,,,29.2,2.0,0.0",
+ "199,Side,Curry Puff (Sardine),Nasi Padang," +
+ "13,461,11.4,35.7,,,22.2,1.1,0.0",
+ "200,Side,Curry Puff (Chicken),Nasi Padang," +
+ "13,409,8.4,30.6,,,23.4,0.7,0.0",
+ "201,Side,Spring Roll,Nasi Padang," +
+ "13,212,2.5,17.2,,,10.6,3.6,0.0",
+ "202,Side,Samosa,Nasi Padang," +
+ "13,156,2.9,11.2,,,9.3,1.8,0.0",
+ "203,Side,Tahu Goreng,Nasi Padang," +
+ "13,305,11.7,22.1,,,15.6,7.5,0.0",
+ "204,Side,Malay Cake (Ma lai Go),Nasi Padang," +
+ "13,214,4.9,6.2,,,35.0,26.2,0.0",
+ "205,Side,Kuih Lopes,Nasi Padang," +
+ "13,480,5.0,25.0,,,54.5,25.4,0.0",
+ "206,Side,Kuih Ongol Ubi (Ubi Kayu),Nasi Padang," +
+ "13,279,2.2,17.7,,,26.5,13.0,0.0",
+ "207,Side,Fried Chicken Wing,Nasi Padang," +
+ "13,348,15.1,29.8,,,4.9,0.0,0.0",
+ "208,Side,Stir-Fried Beansprouts,Nasi Padang," +
+ "13,25,1.6,1.5,,,1.0,0.6",
+ "209,Side, Kangkung Belacan,Nasi Padang," +
+ "13,39,1.3,3.0,,,1.4,0.6,0.0",
+ "210,Side,Braised Egg and Chicken,Nasi Padang," +
+ "13,209,31.1,7.8,,,3.5,3.0,0.0",
+ "211,Side,Beef Rendang,Nasi Padang," +
+ "13,260,18.2,18.1,,6.5,3.9,0.0",
+ "212,Side,Gulai Ayam (Chicken Curry),Nasi Padang," +
+ "13,265,23.8,16.8,,,5.4,3.5,0.0",
+ "213,Side,Sayur Lodeh (Vegetable Curry),Nasi Padang," +
+ "13,141,5.7,8.8,,,10.2,5.4,0.0",
+ "214,Side,Sambal Goreng Tempeh (Fried Spicy Tempeh),Nasi Padang," +
+ "13,776,6.8,76.7,,,15.7,11.9,0.0",
+ "215,Side,Chicken Porridge,Nasi Padang," +
+ "13,216,13.1,6.5,,,25.1,0.6,0.0",
+ "216,Side,Nasi Goreng,Nasi Padang," +
+ "13,544,11.6,13.8,,,91.4,3.7,0.0",
+ "217,Side,Assam Pedas,Nasi Padang," +
+ "13,86,12.3,3.2,,,1.7,1.1,0.0",
+ "218,Side,Sotong,Nasi Padang," +
+ "13,83,8.6,2.8,,,5.0,4.7",
+ "219,Side,Chicken Rendang,Nasi Padang," +
+ "13,238,22.6,12.8,,,7.2,4.3,0.0",
+ "220,Side,Fish Cutlet,Nasi Padang," +
+ "13,138,7.0,8.5,,,8.0,0.4,",
+ "221,Side,Chicken Ngoyang,Nasi Padang," +
+ "13,649,20.3,43.1,,,45.0,4.9,0.0",
+ "222,Side,Rissoles,Nasi Padang," +
+ "13,226,6.0,12.9,,,20.8,1.1,0.0",
+ };
+
+ public static String[] getFoodData() {
+ return foodData;
+ }
+}
diff --git a/src/main/java/seedu/definitions/FoodTypes.java b/src/main/java/seedu/definitions/FoodTypes.java
new file mode 100644
index 0000000000..ab2b4a7920
--- /dev/null
+++ b/src/main/java/seedu/definitions/FoodTypes.java
@@ -0,0 +1,18 @@
+package seedu.definitions;
+
+public enum FoodTypes {
+ INGREDIENT("Ingredient"),
+ DISH("Dish"),
+ SIDE("Side");
+
+ private String foodType;
+
+ private FoodTypes(String foodType) {
+ this.foodType = foodType;
+ }
+
+ @Override
+ public String toString() {
+ return foodType;
+ }
+}
diff --git a/src/main/java/seedu/definitions/MealTypes.java b/src/main/java/seedu/definitions/MealTypes.java
new file mode 100644
index 0000000000..bb481ef6ee
--- /dev/null
+++ b/src/main/java/seedu/definitions/MealTypes.java
@@ -0,0 +1,47 @@
+package seedu.definitions;
+
+import seedu.exceptions.InvalidMealException;
+
+public enum MealTypes {
+ BREAKFAST("Breakfast", 0),
+ LUNCH("Lunch", 1),
+ DINNER("Dinner", 2);
+
+ private String mealType;
+ private int order;
+
+ private MealTypes(String mealType, int order) {
+ this.mealType = mealType;
+ this.order = order;
+ }
+
+ @Override
+ public String toString() {
+ return mealType;
+ }
+
+ public int getOrder() {
+ return this.order;
+ }
+
+ public int isBefore(MealTypes other) {
+ return this.getOrder() < other.getOrder() ? -1 : 1;
+ }
+
+ public static MealTypes fromString(String mealType) throws InvalidMealException {
+ for (MealTypes mt : MealTypes.values()) {
+ if (mt.mealType.equalsIgnoreCase(mealType)) {
+ return mt;
+ }
+ }
+ throw new InvalidMealException(mealType);
+ }
+
+ public static String getSupportedMealTypes() {
+ String output = "";
+ for (MealTypes mt : MealTypes.values()) {
+ output += mt.toString() + ", ";
+ }
+ return output.substring(0, output.length() - 2);
+ }
+}
diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java
deleted file mode 100644
index 5c74e68d59..0000000000
--- a/src/main/java/seedu/duke/Duke.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package seedu.duke;
-
-import java.util.Scanner;
-
-public class Duke {
- /**
- * Main entry-point for the java.duke.Duke application.
- */
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- System.out.println("What is your name?");
-
- Scanner in = new Scanner(System.in);
- System.out.println("Hello " + in.nextLine());
- }
-}
diff --git a/src/main/java/seedu/entities/CaloricIntake.java b/src/main/java/seedu/entities/CaloricIntake.java
new file mode 100644
index 0000000000..2d281f8271
--- /dev/null
+++ b/src/main/java/seedu/entities/CaloricIntake.java
@@ -0,0 +1,31 @@
+package seedu.entities;
+
+import java.util.List;
+
+public class CaloricIntake {
+ private List dailyCalories;
+ private float totalDailyCalories;
+
+ public CaloricIntake(List dailyCalories) {
+ this.dailyCalories = dailyCalories;
+ calculateTotalCalories();
+ }
+
+ public List getDailyCalories() {
+ return this.dailyCalories;
+ }
+
+ public void setDailyCalories(List dailyCalories) {
+ this.dailyCalories = dailyCalories;
+ }
+
+ public float getTotalDailyCalories() {
+ return this.totalDailyCalories;
+ }
+
+ public void calculateTotalCalories() {
+ for (Meal meal : dailyCalories) {
+ this.totalDailyCalories += meal.getTotalCalories();
+ }
+ }
+}
diff --git a/src/main/java/seedu/entities/Dish.java b/src/main/java/seedu/entities/Dish.java
new file mode 100644
index 0000000000..cdcecd611c
--- /dev/null
+++ b/src/main/java/seedu/entities/Dish.java
@@ -0,0 +1,9 @@
+package seedu.entities;
+
+public class Dish extends Food {
+ public Dish(int id, String name, String storeName, int storeNumber, float calories, float protein, float totalFat,
+ float saturatedFat, float dietaryFibre, float carbohydrates, float sugar, float sodium) {
+ super(id, name, storeName, storeNumber, calories, protein, totalFat, saturatedFat,dietaryFibre,
+ carbohydrates, sugar, sodium);
+ }
+}
diff --git a/src/main/java/seedu/entities/Exercise.java b/src/main/java/seedu/entities/Exercise.java
new file mode 100644
index 0000000000..fef6f01749
--- /dev/null
+++ b/src/main/java/seedu/entities/Exercise.java
@@ -0,0 +1,81 @@
+package seedu.entities;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+public class Exercise implements Comparable{
+ protected String exerciseName;
+ protected float caloriesBurnt;
+ protected String exerciseDescription;
+ protected LocalDate date;
+
+ public Exercise(String exerciseName, String exerciseDescription, float caloriesBurnt, LocalDate date){
+ this.exerciseName = exerciseName;
+ this.exerciseDescription = exerciseDescription;
+ this.caloriesBurnt = caloriesBurnt;
+ this.date = date;
+ }
+
+ public String[] toWriteFormat(String csvDelimiter, DateTimeFormatter dtf) {
+ String[] output = new String[4];
+ output[0] = exerciseName;
+ output[1] = exerciseDescription;
+ output[2] = Float.toString(caloriesBurnt);
+ output[3] = date.format(dtf);
+ return output;
+ }
+
+ @Override
+ public String toString() {
+ return "Exercise: " + exerciseName + System.lineSeparator() +
+ "Description: " + exerciseDescription + System.lineSeparator() +
+ "Calories Burnt: " + caloriesBurnt + System.lineSeparator() +
+ "Date of Exercise: " + date + System.lineSeparator();
+ }
+
+
+ public String getExerciseName() {
+ return this.exerciseName;
+ }
+
+ public void setExerciseName(String exerciseName) {
+ this.exerciseName = exerciseName;
+ }
+
+ public float getCaloriesBurnt() {
+ return this.caloriesBurnt;
+ }
+
+ public void setCaloriesBurnt(float caloriesBurnt) {
+ this.caloriesBurnt = caloriesBurnt;
+ }
+
+ public String getExerciseDescription() {
+ return this.exerciseDescription;
+ }
+
+ public void setExerciseDescription(String exerciseDescription) {
+ this.exerciseDescription = exerciseDescription;
+ }
+
+ public LocalDate getDate() {
+ return this.date;
+ }
+
+ public void setDate(LocalDate date) {
+ this.date = date;
+ }
+
+ @Override
+ public int compareTo(Exercise otherExercise) {
+ if (getDate() == null || otherExercise.getDate() == null) {
+ return 0;
+ }
+ int comparator = this.getDate().compareTo(otherExercise.getDate());
+ if (comparator != 0) {
+ return comparator;
+ } else {
+ return Float.compare(this.getCaloriesBurnt(), otherExercise.getCaloriesBurnt());
+ }
+ }
+}
diff --git a/src/main/java/seedu/entities/Food.java b/src/main/java/seedu/entities/Food.java
new file mode 100644
index 0000000000..4f94901c40
--- /dev/null
+++ b/src/main/java/seedu/entities/Food.java
@@ -0,0 +1,134 @@
+package seedu.entities;
+
+public abstract class Food {
+ protected int id;
+ protected String name;
+ protected String storeName;
+ protected int storeNumber;
+ protected float calories;
+ protected float protein;
+ protected float totalFat;
+ protected float saturatedFat;
+ protected float dietaryFibre;
+ protected float carbohydrates;
+ protected float sugar;
+ protected float sodium;
+
+ public Food(int id, String name, String storeName, int storeNumber, float calories, float protein, float totalFat,
+ float saturatedFat, float dietaryFibre, float carbohydrates, float sugar, float sodium) {
+ this.id = id;
+ this.name = name;
+ this.storeName = storeName;
+ this.storeNumber = storeNumber;
+ this.calories = calories;
+ this.protein = protein;
+ this.totalFat = totalFat;
+ this.saturatedFat = saturatedFat;
+ this.dietaryFibre = dietaryFibre;
+ this.carbohydrates = carbohydrates;
+ this.sugar = sugar;
+ this.sodium = sodium;
+ }
+
+ public int getId() {
+ return this.id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getStoreName() {
+ return this.storeName;
+ }
+
+ public void setStoreName(String storeName) {
+ this.storeName = storeName;
+ }
+
+ public int getStoreNumber() {
+ return this.storeNumber;
+ }
+
+ public void setStoreNumber(int storeNumber) {
+ this.storeNumber = storeNumber;
+ }
+
+ public float getCalories() {
+ return this.calories;
+ }
+
+ public void setCalories(float calories) {
+ this.calories = calories;
+ }
+
+ public float getProtein() {
+ return protein;
+ }
+
+ public void setProtein(float protein) {
+ this.protein = protein;
+ }
+
+ public float getTotalFat() {
+ return totalFat;
+ }
+
+ public void setTotalFat(float totalFat) {
+ this.totalFat = totalFat;
+ }
+
+ public float getSaturatedFat() {
+ return saturatedFat;
+ }
+
+ public void setSaturatedFat(float saturatedFat) {
+ this.saturatedFat = saturatedFat;
+ }
+
+ public float getDietaryFibre() {
+ return dietaryFibre;
+ }
+
+ public void setDietaryFibre(float dietaryFibre) {
+ this.dietaryFibre = dietaryFibre;
+ }
+
+ public float getCarbohydrates() {
+ return carbohydrates;
+ }
+
+ public void setCarbohydrates(float carbohydrates) {
+ this.carbohydrates = carbohydrates;
+ }
+
+ public float getSugar() {
+ return sugar;
+ }
+
+ public void setSugar(float sugar) {
+ this.sugar = sugar;
+ }
+
+ public float getSodium() {
+ return sodium;
+ }
+
+ public void setSodium(float sodium) {
+ this.sodium = sodium;
+ }
+
+ @Override
+ public String toString() {
+ return this.name + " from " + this.storeName;
+ }
+
+}
diff --git a/src/main/java/seedu/entities/Ingredient.java b/src/main/java/seedu/entities/Ingredient.java
new file mode 100644
index 0000000000..af792893eb
--- /dev/null
+++ b/src/main/java/seedu/entities/Ingredient.java
@@ -0,0 +1,10 @@
+package seedu.entities;
+
+public class Ingredient extends Food {
+ public Ingredient(int id, String name, String storeName, int storeNumber, float calories, float protein,
+ float totalFat, float saturatedFat, float dietaryFibre, float carbohydrates, float sugar,
+ float sodium) {
+ super(id, name, storeName, storeNumber, calories, protein, totalFat, saturatedFat,dietaryFibre,
+ carbohydrates, sugar, sodium);
+ }
+}
diff --git a/src/main/java/seedu/entities/Meal.java b/src/main/java/seedu/entities/Meal.java
new file mode 100644
index 0000000000..41eb18aa29
--- /dev/null
+++ b/src/main/java/seedu/entities/Meal.java
@@ -0,0 +1,105 @@
+package seedu.entities;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import seedu.constants.DateConstants;
+import seedu.definitions.MealTypes;
+
+public class Meal implements Comparable {
+ private ArrayList foods;
+ private LocalDate date;
+ private double totalCalories;
+ private MealTypes identifier;
+
+ public Meal(ArrayList foods, LocalDate date, MealTypes identifier) {
+ this.foods = foods;
+ this.date = date;
+ this.identifier = identifier;
+ calculateTotalCalories();
+ }
+
+ public ArrayList getFoods() {
+ return this.foods;
+ }
+
+ public void setFoods(ArrayList foods) {
+ this.foods = foods;
+ }
+
+ public void addFoods(ArrayList foods) {
+ for (Food food : foods) {
+ this.foods.add(food);
+ }
+ }
+
+ public LocalDate getDate() {
+ return this.date;
+ }
+
+ public void setDate(LocalDate date) {
+ this.date = date;
+ }
+
+ public double getTotalCalories() {
+ return this.totalCalories;
+ }
+
+ public void setTotalCalories(double totalCalories) {
+ this.totalCalories = totalCalories;
+ }
+
+ public MealTypes getIdentifier() {
+ return this.identifier;
+ }
+
+ public void setIdentifier(MealTypes identifier) {
+ this.identifier = identifier;
+ }
+
+ public void calculateTotalCalories() {
+ for (Food food : foods) {
+ this.totalCalories += food.getCalories();
+ }
+ }
+
+ public String[] toWriteFormat(String delimiter, String dateFormat) {
+ String[] output = new String[3];
+ output[0] = date.format(DateTimeFormatter.ofPattern(dateFormat, Locale.ENGLISH));
+ String[] foodArray = new String[foods.size()];
+ for (int i = 0; i < foods.size(); i++) {
+ foodArray[i] = String.valueOf(foods.get(i).getId());
+ }
+ output[1] = String.join(delimiter, foodArray);
+ output[2] = this.identifier.toString();
+ return output;
+ }
+
+ @Override
+ public String toString() {
+ String output = this.identifier + " was consumed on " +
+ date.format(DateTimeFormatter.ofPattern(DateConstants.PARSE_FORMAT, Locale.ENGLISH)) +
+ System.lineSeparator();
+ output += "Total Calories are: " + this.totalCalories + System.lineSeparator();
+ output += "Here are the foods you ate:" + System.lineSeparator();
+ for (int i = 0; i < foods.size(); i++) {
+ output += (i+1) + ") " + foods.get(i).toString() + System.lineSeparator();
+ }
+ return output;
+ }
+
+ @Override
+ public int compareTo(Meal otherMeal) {
+ if (getDate() == null || otherMeal.getDate() == null) {
+ return 0;
+ }
+ int comparator = this.getDate().compareTo(otherMeal.getDate());
+ if (comparator != 0) {
+ return comparator;
+ } else {
+ return this.getIdentifier().isBefore(otherMeal.getIdentifier());
+ }
+ }
+}
diff --git a/src/main/java/seedu/entities/Side.java b/src/main/java/seedu/entities/Side.java
new file mode 100644
index 0000000000..7ca8b9da54
--- /dev/null
+++ b/src/main/java/seedu/entities/Side.java
@@ -0,0 +1,9 @@
+package seedu.entities;
+
+public class Side extends Food {
+ public Side(int id, String name, String storeName, int storeNumber, float calories, float protein, float totalFat,
+ float saturatedFat, float dietaryFibre, float carbohydrates, float sugar, float sodium) {
+ super(id, name, storeName, storeNumber, calories, protein, totalFat, saturatedFat, dietaryFibre,
+ carbohydrates, sugar, sodium);
+ }
+}
diff --git a/src/main/java/seedu/entities/User.java b/src/main/java/seedu/entities/User.java
new file mode 100644
index 0000000000..7e184473aa
--- /dev/null
+++ b/src/main/java/seedu/entities/User.java
@@ -0,0 +1,155 @@
+package seedu.entities;
+
+import java.util.Objects;
+
+import seedu.logger.LogFileHandler;
+
+public class User {
+ private String name;
+ private float weight;
+ private float height;
+ private int age;
+ private String gender;
+ private float targetWeight;
+ private double caloricLimit;
+
+ public User() {
+ this.name = "";
+ this.weight = 0;
+ this.height = 0;
+ this.age = 0;
+ this.gender = "";
+ this.caloricLimit = 0;
+ this.targetWeight = 0;
+ }
+
+ public User(String name, float weight, float height, int age, String gender, float targetWeight) {
+ this.name = name;
+ this.weight = weight;
+ this.height = height;
+ this.age = age;
+ this.gender = gender;
+ this.targetWeight = targetWeight;
+ this.caloricLimit = calculateCaloricNeeds(weight, height, age, gender);
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setCaloricLimit(double caloricLimit) {
+ this.caloricLimit = caloricLimit;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public float getWeight() {
+ return this.weight;
+ }
+
+ public void setWeight(float weight) {
+ this.weight = weight;
+ }
+ public float getTargetWeight() {
+ return this.targetWeight;
+ }
+ public void setTargetWeight(float targetWeight) {
+ this.targetWeight = targetWeight;
+ }
+
+ public float getHeight() {
+ return this.height;
+ }
+
+ public void setHeight(float height) {
+ this.height = height;
+ }
+
+ public int getAge() {
+ return this.age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getGender() {
+ return this.gender;
+ }
+
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
+
+ public static void displayNewWeightDifference (float weight, float targetWeight) {
+ float actualDifference = weight - targetWeight;
+ float difference = 0;
+ if (actualDifference > 0) {
+ difference = actualDifference;
+ System.out.println("You need to lose " + difference + "kg to reach your target weight: " +
+ targetWeight + "kg");
+ } else if (actualDifference < 0) {
+ difference = actualDifference * (-1);
+ System.out.println("You need to gain " + difference + "kg to reach your target weight: " +
+ targetWeight + "kg");
+ } else {
+ System.out.println("Congrats! You have reached your target weight!");
+ }
+ }
+
+ public static void displayNewTargetWeightDifference (float weight, float targetWeight) {
+ float actualDifference = weight - targetWeight;
+ float difference = 0;
+ if (actualDifference > 0) {
+ difference = actualDifference;
+ System.out.println("With your updated target weight, you now need to lose " + difference +
+ "kg to reach it.");
+ } else if (actualDifference < 0) {
+ difference = actualDifference * (-1);
+ System.out.println("With your updated target weight, you now need to gain " + difference +
+ "kg to reach it.");
+ } else {
+ System.out.println("Congrats! You have reached your target weight!");
+ }
+ }
+
+ public static double calculateCaloricNeeds (float weight, float height, int age, String gender) {
+ double caloricNeeds;
+ switch(gender.toLowerCase()) {
+ case "male":
+ caloricNeeds = 66 + (13.7 * weight) + (5 * height) - (4.7 * age);
+ assert caloricNeeds > 0: "Caloric Needs should be more than O";
+ return caloricNeeds;
+ case "female":
+ caloricNeeds = 655 + (9.6 * weight) + (1.8 * height) - (4.7 * age);
+ assert caloricNeeds > 0: "Caloric Needs should be more than O";
+ return caloricNeeds;
+ default:
+ LogFileHandler.logWarning("Gender not provided, cannot calculate caloric needs accurately");
+ return 0;
+ }
+ }
+
+ public double getCaloricLimit() {
+ return Math.round(this.caloricLimit);
+ }
+
+ public double getCaloriesLeft(double calorieIntake) {
+ return Math.round(caloricLimit - calorieIntake);
+ }
+
+ public String[] toWriteFormat() {
+ String weight = Float.toString(this.weight);
+ assert !Objects.equals(weight, "0") : "Weight should be non 0";
+ String height = Float.toString(this.height);
+ assert !Objects.equals(height, "0"): "Height should be non 0";
+ String age = Integer.toString(this.age);
+ assert !Objects.equals(age, "0"): "Age should be non 0";
+ String targetWeight = Float.toString(this.targetWeight);
+ assert !Objects.equals(targetWeight, "0"): "Target Weight should be non 0";
+ String[] value = { this.name, weight, height, age, this.gender, targetWeight };
+ return value;
+ }
+}
diff --git a/src/main/java/seedu/exceptions/ExtraArgumentsException.java b/src/main/java/seedu/exceptions/ExtraArgumentsException.java
new file mode 100644
index 0000000000..0a448cffcd
--- /dev/null
+++ b/src/main/java/seedu/exceptions/ExtraArgumentsException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class ExtraArgumentsException extends LifeTrackerException{
+ public ExtraArgumentsException() {
+ super("Oops! Too many arguments in your input!");
+ }
+}
diff --git a/src/main/java/seedu/exceptions/ImpossibleValueException.java b/src/main/java/seedu/exceptions/ImpossibleValueException.java
new file mode 100644
index 0000000000..2d4d8190ec
--- /dev/null
+++ b/src/main/java/seedu/exceptions/ImpossibleValueException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class ImpossibleValueException extends LifeTrackerException{
+ public ImpossibleValueException(String commandWord, String argument) {
+ super(argument + " is an impossible value for " + commandWord + " please enter a valid one!");
+ }
+}
diff --git a/src/main/java/seedu/exceptions/InvalidArgumentsException.java b/src/main/java/seedu/exceptions/InvalidArgumentsException.java
new file mode 100644
index 0000000000..d97a73c2ff
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidArgumentsException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class InvalidArgumentsException extends LifeTrackerException {
+ public InvalidArgumentsException(String commandWord, String argument) {
+ super("Error: Invalid arguments for " + argument + " for command " + commandWord);
+ }
+}
diff --git a/src/main/java/seedu/exceptions/InvalidChoiceException.java b/src/main/java/seedu/exceptions/InvalidChoiceException.java
new file mode 100644
index 0000000000..13967329f8
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidChoiceException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class InvalidChoiceException extends LifeTrackerException{
+ public InvalidChoiceException() {
+ super("This is an invalid choice! Please input a valid choice!");
+ }
+}
diff --git a/src/main/java/seedu/exceptions/InvalidCommandException.java b/src/main/java/seedu/exceptions/InvalidCommandException.java
new file mode 100644
index 0000000000..e565defbab
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidCommandException.java
@@ -0,0 +1,8 @@
+package seedu.exceptions;
+
+public class InvalidCommandException extends LifeTrackerException{
+
+ public InvalidCommandException() {
+ super("Please enter a valid command.");
+ }
+}
diff --git a/src/main/java/seedu/exceptions/InvalidDateException.java b/src/main/java/seedu/exceptions/InvalidDateException.java
new file mode 100644
index 0000000000..8da7774ef9
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidDateException.java
@@ -0,0 +1,13 @@
+package seedu.exceptions;
+
+import seedu.constants.DateConstants;
+
+public class InvalidDateException extends LifeTrackerException {
+
+ public InvalidDateException(String dateString) {
+ super("Oops! " + dateString + " is not a valid date!" +
+ " Please format the date as: " + DateConstants.PARSE_FORMAT + "." +
+ "\n" + "Also check whether the date you've entered exists!");
+ }
+
+}
diff --git a/src/main/java/seedu/exceptions/InvalidFieldInfoFormatException.java b/src/main/java/seedu/exceptions/InvalidFieldInfoFormatException.java
new file mode 100644
index 0000000000..f150fbca07
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidFieldInfoFormatException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class InvalidFieldInfoFormatException extends LifeTrackerException{
+ public InvalidFieldInfoFormatException(String commandWord, String argument) {
+ super(argument + " is not of valid format for " + commandWord + " please try again!");
+ }
+}
diff --git a/src/main/java/seedu/exceptions/InvalidFieldNameException.java b/src/main/java/seedu/exceptions/InvalidFieldNameException.java
new file mode 100644
index 0000000000..2a64120600
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidFieldNameException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class InvalidFieldNameException extends LifeTrackerException{
+ public InvalidFieldNameException(String commandWord, String argument) {
+ super("Oops! Invalid field name " + argument + " for command " + commandWord);
+ }
+}
diff --git a/src/main/java/seedu/exceptions/InvalidIndexException.java b/src/main/java/seedu/exceptions/InvalidIndexException.java
new file mode 100644
index 0000000000..40444c84b1
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidIndexException.java
@@ -0,0 +1,9 @@
+package seedu.exceptions;
+
+public class InvalidIndexException extends LifeTrackerException {
+
+ public InvalidIndexException(int index) {
+ super(index + " is not a valid index!");
+ }
+
+}
diff --git a/src/main/java/seedu/exceptions/InvalidMealException.java b/src/main/java/seedu/exceptions/InvalidMealException.java
new file mode 100644
index 0000000000..b0531de842
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidMealException.java
@@ -0,0 +1,11 @@
+package seedu.exceptions;
+
+import seedu.definitions.MealTypes;
+
+public class InvalidMealException extends LifeTrackerException {
+ public InvalidMealException(String input) {
+ super(System.lineSeparator() + "Invalid meal type: " + input +
+ "! Supported meal types: " + MealTypes.getSupportedMealTypes());
+ }
+
+}
diff --git a/src/main/java/seedu/exceptions/LifeTrackerException.java b/src/main/java/seedu/exceptions/LifeTrackerException.java
new file mode 100644
index 0000000000..ab8293aee4
--- /dev/null
+++ b/src/main/java/seedu/exceptions/LifeTrackerException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class LifeTrackerException extends Exception {
+ public LifeTrackerException(String errorMessage) {
+ super(errorMessage);
+ }
+}
diff --git a/src/main/java/seedu/exceptions/MissingArgumentsException.java b/src/main/java/seedu/exceptions/MissingArgumentsException.java
new file mode 100644
index 0000000000..5d29c4a5c8
--- /dev/null
+++ b/src/main/java/seedu/exceptions/MissingArgumentsException.java
@@ -0,0 +1,9 @@
+package seedu.exceptions;
+
+public class MissingArgumentsException extends LifeTrackerException {
+
+ public MissingArgumentsException(String commandWord, String argument) {
+ super("Oops! Missing argument " + argument + " for command " + commandWord);
+ }
+
+}
diff --git a/src/main/java/seedu/exceptions/NegativeFieldInfoException.java b/src/main/java/seedu/exceptions/NegativeFieldInfoException.java
new file mode 100644
index 0000000000..9b9b69f342
--- /dev/null
+++ b/src/main/java/seedu/exceptions/NegativeFieldInfoException.java
@@ -0,0 +1,7 @@
+package seedu.exceptions;
+
+public class NegativeFieldInfoException extends LifeTrackerException{
+ public NegativeFieldInfoException(String commandWord, String argument) {
+ super("Oops! You cannot enter a negative value for " + argument + " in command " + commandWord);
+ }
+}
diff --git a/src/main/java/seedu/exceptions/NoFoodsException.java b/src/main/java/seedu/exceptions/NoFoodsException.java
new file mode 100644
index 0000000000..6f2f180dda
--- /dev/null
+++ b/src/main/java/seedu/exceptions/NoFoodsException.java
@@ -0,0 +1,9 @@
+package seedu.exceptions;
+
+public class NoFoodsException extends LifeTrackerException {
+
+ public NoFoodsException() {
+ super("No food was selected. Returning to main menu..");
+ }
+
+}
diff --git a/src/main/java/seedu/exceptions/UnableToSaveDatabaseException.java b/src/main/java/seedu/exceptions/UnableToSaveDatabaseException.java
new file mode 100644
index 0000000000..dcf226d39b
--- /dev/null
+++ b/src/main/java/seedu/exceptions/UnableToSaveDatabaseException.java
@@ -0,0 +1,9 @@
+package seedu.exceptions;
+
+public class UnableToSaveDatabaseException extends LifeTrackerException {
+
+ public UnableToSaveDatabaseException(String databaseName) {
+ super("Unable to save " + databaseName);
+ }
+
+}
diff --git a/src/main/java/seedu/lifetracker/LifeTracker.java b/src/main/java/seedu/lifetracker/LifeTracker.java
new file mode 100644
index 0000000000..86d308e522
--- /dev/null
+++ b/src/main/java/seedu/lifetracker/LifeTracker.java
@@ -0,0 +1,51 @@
+package seedu.lifetracker;
+
+import seedu.commands.Command;
+import seedu.parser.CommandParser;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+public class LifeTracker {
+ private static final String MEAL_FILE_PATH = "./data/mealData.csv";
+ private static final String USER_FILE_PATH = "./data/userData.csv";
+ private static final String EXERCISE_FILE_PATH = "./data/exerciseData.csv";
+
+ private FoodStorage foodStorage;
+ private MealStorage mealStorage;
+ private UserStorage userStorage;
+ private ExerciseStorage exerciseStorage;
+ private GeneralUi ui;
+
+ public LifeTracker(String mealFilePath, String userFilePath, String exerciseFilePath) {
+ foodStorage = new FoodStorage();
+ mealStorage = new MealStorage(mealFilePath, foodStorage);
+ userStorage = new UserStorage(userFilePath);
+ exerciseStorage = new ExerciseStorage(exerciseFilePath);
+ ui = new GeneralUi();
+ }
+
+ public void run() {
+ ui.printIntroduction();
+ boolean isExit = false;
+ while (!isExit) {
+ try {
+ String userInput = ui.readLine();
+ ui.printLine();
+ Command command = CommandParser.parse(userInput);
+ command.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage);
+ isExit = command.isExit();
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ } finally {
+ ui.printLine();
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ new LifeTracker(MEAL_FILE_PATH, USER_FILE_PATH, EXERCISE_FILE_PATH).run();
+ }
+}
diff --git a/src/main/java/seedu/logger/LogFileHandler.java b/src/main/java/seedu/logger/LogFileHandler.java
new file mode 100644
index 0000000000..1bcc1f1c83
--- /dev/null
+++ b/src/main/java/seedu/logger/LogFileHandler.java
@@ -0,0 +1,37 @@
+package seedu.logger;
+
+import java.io.IOException;
+import java.util.logging.FileHandler;
+import java.util.logging.Logger;
+import java.util.logging.SimpleFormatter;
+
+public class LogFileHandler {
+
+ private static final Logger logger = Logger.getLogger(LogFileHandler.class.getName());
+ private static FileHandler fileHandler;
+
+ static {
+ try {
+ logger.setUseParentHandlers(false);
+ fileHandler = new FileHandler("myLogFile.log");
+ SimpleFormatter formatter = new SimpleFormatter();
+ fileHandler.setFormatter(formatter);
+ logger.addHandler(fileHandler);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void logInfo(String message) {
+ logger.info(message);
+ }
+
+ public static void logWarning(String message) {
+ logger.warning(message);
+ }
+
+ public static void logError(String message) {
+ logger.severe(message);
+ }
+}
+
diff --git a/src/main/java/seedu/output/UI.java b/src/main/java/seedu/output/UI.java
new file mode 100644
index 0000000000..be88e1e34b
--- /dev/null
+++ b/src/main/java/seedu/output/UI.java
@@ -0,0 +1,88 @@
+package seedu.output;
+
+import seedu.entities.Food;
+import seedu.storage.FoodStorage;
+
+import java.util.Scanner;
+
+public class UI {
+ public static Scanner sc = new Scanner(System.in);
+
+ /**
+ * Reads user input
+ *
+ * @return user input
+ */
+ public String readLine() {
+ String command = "";
+ while (command.length() == 0) {
+ command = sc.nextLine();
+ }
+ return command;
+ }
+
+ public int readInt() {
+ String value = "";
+ while (value.length() == 0 || !value.matches("^([+-]?[1-9]\\d*|0)$")) {
+ value = sc.nextLine();
+ }
+ return Integer.parseInt(value);
+ }
+
+ /**
+ * Prints Welcome message when Duke first starts
+ */
+ public void printIntroduction() {
+ this.printLine();
+ System.out.println("Hello! Welcome to");
+ this.printLogo();
+ this.printLine();
+ System.out.println();
+ }
+
+ /**
+ * Prints Goodbye message when Duke exits
+ */
+ public void printGoodbye() {
+ System.out.println();
+ this.printLine();
+ System.out.println("Bye. Hope to see you again soon!");
+ this.printLine();
+ }
+
+ /**
+ * Helper function to print divider
+ */
+ public void printLine() {
+ System.out.println("------------------------------------------------------------");
+ }
+
+ private void printLogo() {
+ System.out.println(
+ " _ _ __ _______ _ " + System.lineSeparator()
+ + "| | (_)/ _||__ __| | | " + System.lineSeparator()
+ + "| | _| |_ ___| |_ __ __ _ ___| | _____ _ __ " + System.lineSeparator()
+ + "| | | | _/ _ \\ | '__/ _` |/ __| |/ / _ \\ '__|" + System.lineSeparator()
+ + "| |____| | || __/ | | | (_| | (__| < __/ | " + System.lineSeparator()
+ + "|______|_|_| \\___|_|_| \\__,_|\\___|_|\\_\\___|_| " + System.lineSeparator()
+ );
+ }
+
+ public void printNewFoodAdded(FoodStorage foodStorage, int food) {
+ Food newFood = foodStorage.getFoodById(food);
+ String foodDescription = newFood.toString();
+ System.out.println("You just added this food"+ System.lineSeparator() + foodDescription);
+ }
+
+ public void printAllFoods(FoodStorage foodStorage) {
+ if (foodStorage.getFoodsCount() == 0) {
+ System.out.println("There are no foods in your food list!");
+ } else {
+ System.out.println("Here are the foods in your food list:");
+ for (int i = 0; i < foodStorage.getFoodsCount(); i++) {
+ String taskDescription = foodStorage.getFoodById(i).toString();
+ System.out.println((i + 1) + ". " + taskDescription);
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/parser/CommandParser.java b/src/main/java/seedu/parser/CommandParser.java
new file mode 100644
index 0000000000..014e6c4745
--- /dev/null
+++ b/src/main/java/seedu/parser/CommandParser.java
@@ -0,0 +1,67 @@
+package seedu.parser;
+
+import seedu.commands.Command;
+import seedu.commands.AddMealCommand;
+import seedu.commands.DeleteCommand;
+import seedu.commands.ExitCommand;
+import seedu.commands.UpdateUserCommand;
+import seedu.commands.ViewUserCommand;
+import seedu.commands.ListCommand;
+import seedu.commands.FilterCaloriesCommand;
+import seedu.commands.HelpCommand;
+import seedu.commands.NutritionCommand;
+import seedu.commands.AddExerciseCommand;
+import seedu.commands.TrackCalorieCommand;
+import seedu.commands.ExamplesCommand;
+import seedu.exceptions.InvalidCommandException;
+import seedu.exceptions.LifeTrackerException;
+
+public class CommandParser {
+ public static Command parse(String userInput) throws LifeTrackerException {
+ String[] userInputArray = userInput.split(" ");
+ String commandWord = userInputArray[0];
+ Command command;
+
+ switch(commandWord) {
+ case "add":
+ command = new AddMealCommand(commandWord, userInput);
+ break;
+ case "delete":
+ command = new DeleteCommand(commandWord, userInput);
+ break;
+ case "bye":
+ command = new ExitCommand();
+ break;
+ case "update":
+ command = new UpdateUserCommand(commandWord, userInput);
+ break;
+ case "view":
+ command = new ViewUserCommand(commandWord, userInput);
+ break;
+ case "list":
+ command = new ListCommand(commandWord, userInput);
+ break;
+ case "filter":
+ command = new FilterCaloriesCommand(commandWord, userInput);
+ break;
+ case "nutrition":
+ command = new NutritionCommand();
+ break;
+ case "exercise":
+ command = new AddExerciseCommand(commandWord, userInput);
+ break;
+ case "track":
+ command = new TrackCalorieCommand(commandWord, userInput);
+ break;
+ case "help":
+ command = new HelpCommand();
+ break;
+ case "examples":
+ command = new ExamplesCommand(commandWord, userInput);
+ break;
+ default:
+ throw new InvalidCommandException();
+ }
+ return command;
+ }
+}
diff --git a/src/main/java/seedu/parser/DateParser.java b/src/main/java/seedu/parser/DateParser.java
new file mode 100644
index 0000000000..61439f6ca8
--- /dev/null
+++ b/src/main/java/seedu/parser/DateParser.java
@@ -0,0 +1,17 @@
+package seedu.parser;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+import seedu.exceptions.InvalidDateException;
+
+public class DateParser {
+ public static LocalDate parse(String dateString, DateTimeFormatter dtf) throws InvalidDateException {
+ try {
+ return LocalDate.parse(dateString, dtf);
+ } catch (DateTimeParseException e) {
+ throw new InvalidDateException(dateString);
+ }
+ }
+}
diff --git a/src/main/java/seedu/storage/ExerciseStorage.java b/src/main/java/seedu/storage/ExerciseStorage.java
new file mode 100644
index 0000000000..27e4d747f1
--- /dev/null
+++ b/src/main/java/seedu/storage/ExerciseStorage.java
@@ -0,0 +1,124 @@
+package seedu.storage;
+
+import com.opencsv.CSVWriter;
+
+import seedu.constants.DateConstants;
+import seedu.entities.Exercise;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.UnableToSaveDatabaseException;
+import seedu.logger.LogFileHandler;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ExerciseStorage extends Storage implements FileReadable, FileWritable{
+ private static final String CSV_DELIMITER = ",";
+ private static final DateTimeFormatter DTF = DateConstants.DATABASE_DTF;
+ private ArrayList exercises;
+ private BufferedReader br;
+
+ public ExerciseStorage(String filePath) {
+ super(filePath);
+ exercises = new ArrayList();
+ try {
+ this.load();
+ System.out.println("Initialised Exercise Storage");
+ } catch (IOException e) {
+ System.out.println("Error loading Exercise Storage");
+ }
+ }
+
+ @Override
+ public void load() throws IOException {
+ String line = "";
+
+ try {
+ br = new BufferedReader(new FileReader(filePath));
+ br.readLine();
+ while ((line = br.readLine()) != null) {
+ String[] exerciseLine = line.split(CSV_DELIMITER);
+ try {
+ String exerciseName = exerciseLine[0];
+ String exerciseDescription = exerciseLine[1];
+ float calorieBurnt = Float.parseFloat(exerciseLine[2]);
+ LocalDate date = LocalDate.parse(exerciseLine[3], DTF);
+ exercises.add(new Exercise(exerciseName, exerciseDescription, calorieBurnt, date));
+ } catch (Exception e) {
+ LogFileHandler.logError("Invalid exercise format!");
+ }
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ File newFile = new File(filePath);
+ newFile.createNewFile();
+ }
+ }
+
+ @Override
+ public void write() throws IOException {
+ CSVWriter writer = new CSVWriter(new FileWriter(filePath),
+ CSVWriter.DEFAULT_SEPARATOR,
+ CSVWriter.NO_QUOTE_CHARACTER,
+ CSVWriter.DEFAULT_ESCAPE_CHARACTER,
+ CSVWriter.RFC4180_LINE_END);
+ String[] header = { "Exercise Name", "Exercise Description", "Calories Burnt" };
+ writer.writeNext(header);
+ Collections.sort(exercises);
+ for (Exercise exercise : exercises) {
+ writer.writeNext(exercise.toWriteFormat(CSV_DELIMITER, DTF));
+ }
+ writer.close();
+ }
+
+ public void saveExercise(Exercise exercise) throws LifeTrackerException {
+ exercises.add(exercise);
+ try {
+ this.write();
+ } catch (IOException e) {
+ throw new UnableToSaveDatabaseException("Exercise");
+ }
+ }
+
+ public void resetStorage() {
+ exercises = new ArrayList();
+ try {
+ this.write();
+ System.out.println("ExerciseStorage was successfully resetted!");
+ } catch (IOException e) {
+ System.out.println("Could not reset ExerciseStorage!");
+ }
+ }
+
+ public int getExercisesCount() {
+ return this.exercises.size();
+ }
+
+ public ArrayList getExercises() {
+ return this.exercises;
+ }
+
+ public List getExercisesByDate(LocalDate date) {
+ List filteredExercises = exercises.stream()
+ .filter(e -> e.getDate().equals(date))
+ .collect(Collectors.toList());
+ return filteredExercises;
+ }
+
+ public Exercise getExerciseById(int id) {
+ return this.exercises.get(id);
+ }
+
+ public Exercise deleteExercise(int index) {
+ return exercises.remove(index);
+ }
+}
diff --git a/src/main/java/seedu/storage/FileReadable.java b/src/main/java/seedu/storage/FileReadable.java
new file mode 100644
index 0000000000..d3de83b6a5
--- /dev/null
+++ b/src/main/java/seedu/storage/FileReadable.java
@@ -0,0 +1,7 @@
+package seedu.storage;
+
+import java.io.IOException;
+
+public interface FileReadable {
+ public void load() throws IOException;
+}
diff --git a/src/main/java/seedu/storage/FileWritable.java b/src/main/java/seedu/storage/FileWritable.java
new file mode 100644
index 0000000000..16eb37ffb1
--- /dev/null
+++ b/src/main/java/seedu/storage/FileWritable.java
@@ -0,0 +1,7 @@
+package seedu.storage;
+
+import java.io.IOException;
+
+public interface FileWritable {
+ public void write() throws IOException;
+}
diff --git a/src/main/java/seedu/storage/FoodStorage.java b/src/main/java/seedu/storage/FoodStorage.java
new file mode 100644
index 0000000000..d1ef8c374c
--- /dev/null
+++ b/src/main/java/seedu/storage/FoodStorage.java
@@ -0,0 +1,126 @@
+package seedu.storage;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import seedu.database.FoodData;
+import seedu.definitions.FoodTypes;
+import seedu.entities.Dish;
+import seedu.entities.Food;
+import seedu.entities.Ingredient;
+import seedu.entities.Side;
+import seedu.exceptions.LifeTrackerException;
+
+public class FoodStorage extends Storage implements FileReadable {
+ private static final String csvDelimiter = ",";
+ private ArrayList foods;
+
+ public FoodStorage() {
+ foods = new ArrayList();
+ try {
+ this.load();
+ } catch (IOException e) {
+ System.out.println("Error loading Food Storage");
+ }
+ }
+
+ @Override
+ public void load() throws IOException {
+ String line = "";
+ String[] foodLine;
+ String foodType;
+ String name;
+ String store;
+ int id;
+ int storeNumber;
+ float calories;
+ float protein;
+ float totalFat;
+ float saturatedFat;
+ float dietaryFibre;
+ float carbohydrates;
+ float sugar;
+ float sodium;
+ Food food;
+
+ String[] foodDataList = FoodData.getFoodData();
+
+ for (int i = 1; i < foodDataList.length; i++) {
+
+ line = foodDataList[i];
+ foodLine = line.split(csvDelimiter); // use comma as separator
+ double[] individualFoodData = new double[13];
+
+ id = Integer.parseInt(foodLine[0]);
+ foodType = foodLine[1];
+ name = foodLine[2].trim();
+ store = foodLine[3].trim();
+ storeNumber = Integer.parseInt(foodLine[4]);
+
+ for (int j = 4; j < 13; j++) {
+ String valueStr = (j < foodLine.length) ? foodLine[j] : null;
+ float value = (valueStr != null && !valueStr.isEmpty()) ? Float.parseFloat(valueStr) : 0;
+ individualFoodData[j] = value;
+ }
+
+ calories = (float) individualFoodData[5];
+ protein = (float) individualFoodData[6];
+ totalFat = (float) individualFoodData[7];
+ saturatedFat = (float) individualFoodData[8];
+ dietaryFibre = (float) individualFoodData[9];
+ carbohydrates = (float) individualFoodData[10];
+ sugar = (float) individualFoodData[11];
+ sodium = (float) individualFoodData[12];
+
+ food = null;
+
+ if (foodType.equals(FoodTypes.DISH.toString())) {
+ food = new Dish(id, name, store, storeNumber, calories, protein, totalFat, saturatedFat,dietaryFibre,
+ carbohydrates, sugar, sodium);
+ } else if (foodType.equals(FoodTypes.SIDE.toString())) {
+ food = new Side(id, name, store, storeNumber, calories, protein, totalFat, saturatedFat,dietaryFibre,
+ carbohydrates, sugar, sodium);
+ } else if (foodType.equals(FoodTypes.INGREDIENT.toString())) {
+ food = new Ingredient(id, name, store, storeNumber, calories, protein, totalFat, saturatedFat,
+ dietaryFibre, carbohydrates, sugar, sodium);
+ }
+
+ if (food != null) {
+ foods.add(food);
+ }
+ }
+ }
+
+ public int getFoodsCount() {
+ return this.foods.size();
+ }
+
+ public ArrayList getFoods() {
+ return this.foods;
+ }
+
+ public Food getFoodById(int id) {
+ return this.foods.get(id);
+ }
+
+ public List getFoodsByName(String name) {
+ List filteredFoods = foods.stream()
+ .filter(f -> f.getName().toLowerCase().contains(name.toLowerCase()))
+ .collect(Collectors.toList());
+ return filteredFoods;
+ }
+
+ public List getFoodsByCalories(float caloriesLowerLimit, float caloriesUpperLimit)
+ throws LifeTrackerException {
+
+ if (caloriesLowerLimit > caloriesUpperLimit) {
+ throw new LifeTrackerException("Please enter valid lower and upper calorie limits!");
+ }
+ List caloriesFilteredFoods = foods.stream()
+ .filter(f -> f.getCalories() >= caloriesLowerLimit && f.getCalories() <= caloriesUpperLimit)
+ .collect(Collectors.toList());
+ return caloriesFilteredFoods;
+ }
+}
diff --git a/src/main/java/seedu/storage/MealStorage.java b/src/main/java/seedu/storage/MealStorage.java
new file mode 100644
index 0000000000..9519d65a7b
--- /dev/null
+++ b/src/main/java/seedu/storage/MealStorage.java
@@ -0,0 +1,159 @@
+package seedu.storage;
+
+import java.io.BufferedReader;
+import java.io.File;
+// import java.io.File;
+// import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import seedu.entities.Meal;
+import seedu.exceptions.InvalidMealException;
+import seedu.logger.LogFileHandler;
+import seedu.constants.DateConstants;
+import seedu.definitions.MealTypes;
+import seedu.entities.Food;
+import com.opencsv.CSVWriter;
+
+public class MealStorage extends Storage implements FileReadable, FileWritable {
+ private static final String CSV_DELIMITER = ",";
+ private static final String FOODS_DELIMITER = "-";
+ private static final DateTimeFormatter DTF = DateConstants.DATABASE_DTF;
+ private ArrayList meals;
+ private FoodStorage foodStorage;
+ private BufferedReader br;
+
+ public MealStorage(String filePath, FoodStorage foodStorage) {
+ super(filePath);
+ this.foodStorage = foodStorage;
+ meals = new ArrayList();
+ try {
+ this.load();
+ System.out.println("Initialised Meal Storage");
+ } catch (IOException e) {
+ System.out.println("Error loading Meal Storage");
+ }
+ }
+
+ @Override
+ public void write() throws IOException {
+ CSVWriter writer = new CSVWriter(new FileWriter(filePath),
+ CSVWriter.DEFAULT_SEPARATOR,
+ CSVWriter.NO_QUOTE_CHARACTER,
+ CSVWriter.DEFAULT_ESCAPE_CHARACTER,
+ CSVWriter.RFC4180_LINE_END);
+ String[] header = { "Date", "Foods", "Meal Type" };
+ writer.writeNext(header);
+ Collections.sort(meals);
+ for (Meal meal : meals) {
+ writer.writeNext(meal.toWriteFormat(FOODS_DELIMITER, DateConstants.DATABASE_FORMAT));
+ }
+ writer.close();
+ }
+
+ @Override
+ public void load() throws IOException {
+ String line = "";
+ String[] mealLine;
+ LocalDate date;
+ String[] foodIndexes;
+ ArrayList foods;
+ MealTypes mealType;
+
+ File storageFile = new File(filePath);
+ if (!storageFile.getParentFile().exists()) {
+ storageFile.getParentFile().mkdirs();
+ storageFile.createNewFile();
+ }
+
+ br = new BufferedReader(new FileReader(filePath));
+
+ // Skip Line 1 (header)
+ br.readLine();
+
+ while ((line = br.readLine()) != null) {
+ mealLine = line.split(CSV_DELIMITER);
+ date = LocalDate.parse(mealLine[0], DTF);
+
+ foodIndexes = mealLine[1].split(FOODS_DELIMITER);
+ foods = new ArrayList();
+ for (String foodIndex : foodIndexes) {
+ foods.add(foodStorage.getFoodById(Integer.parseInt(foodIndex)));
+ }
+
+ try {
+ mealType = MealTypes.fromString(mealLine[2]);
+ meals.add(new Meal(foods, date, mealType));
+ } catch (InvalidMealException e) {
+ LogFileHandler.logError(line + " has an invalid meal type");
+ }
+ }
+
+ br.close();
+ }
+
+ public void saveMeal(Meal meal) {
+ for (Meal m : meals) {
+ if (!m.getDate().equals(meal.getDate()) ||
+ !m.getIdentifier().equals(meal.getIdentifier())) {
+ continue;
+ }
+ m.addFoods(meal.getFoods());
+ try {
+ this.write();
+ System.out.println("Meal was successfully added!");
+ } catch (IOException e) {
+ System.out.println("Could not add meal to storage!");
+ }
+ return;
+ }
+
+ meals.add(meal);
+ try {
+ this.write();
+ System.out.println("Meal was successfully added!");
+ } catch (IOException e) {
+ System.out.println("Could not add meal to storage!");
+ }
+ }
+
+ public void resetStorage() {
+ meals = new ArrayList();
+ try {
+ this.write();
+ System.out.println("MealStorage was successfully resetted!");
+ } catch (IOException e) {
+ System.out.println("Could not reset MealStorage!");
+ }
+ }
+
+ public int getMealCount() {
+ return this.meals.size();
+ }
+
+ public ArrayList getMeals() {
+ return this.meals;
+ }
+
+ public List getMealByDate(LocalDate date) {
+ List filteredMeals = meals.stream()
+ .filter(m -> m.getDate().equals(date))
+ .collect(Collectors.toList());
+ return filteredMeals;
+ }
+
+ public Meal getMealById(int id) {
+ return this.meals.get(id);
+ }
+
+ public Meal deleteMeal(int index) throws IndexOutOfBoundsException {
+ return meals.remove(index);
+ }
+}
diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java
new file mode 100644
index 0000000000..fa3282e415
--- /dev/null
+++ b/src/main/java/seedu/storage/Storage.java
@@ -0,0 +1,22 @@
+package seedu.storage;
+
+
+public abstract class Storage {
+ protected String filePath;
+
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ public Storage() {
+ this.filePath = "";
+ }
+
+ public String getFilePath() {
+ return this.filePath;
+ }
+
+ public void setFilePath(String filePath) {
+ this.filePath = filePath;
+ }
+}
diff --git a/src/main/java/seedu/storage/UserStorage.java b/src/main/java/seedu/storage/UserStorage.java
new file mode 100644
index 0000000000..c460e0fc03
--- /dev/null
+++ b/src/main/java/seedu/storage/UserStorage.java
@@ -0,0 +1,89 @@
+package seedu.storage;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import com.opencsv.CSVWriter;
+import seedu.entities.User;
+
+public class UserStorage extends Storage implements FileReadable, FileWritable {
+ private static final String csvDelimiter = ",";
+ private User user;
+
+ public UserStorage(String filePath) {
+ super(filePath);
+ try {
+ this.load();
+ System.out.println("Initialised User Storage");
+ } catch (IOException e) {
+ System.out.println("Error loading User Storage");
+ }
+ }
+
+ @Override
+ public void write() throws IOException {
+ CSVWriter writer = new CSVWriter(new FileWriter(filePath),
+ CSVWriter.DEFAULT_SEPARATOR,
+ CSVWriter.NO_QUOTE_CHARACTER,
+ CSVWriter.DEFAULT_ESCAPE_CHARACTER,
+ CSVWriter.RFC4180_LINE_END);
+ String[] header = { "Name", "Weight", "Height", "Age", "Gender", "TargetWeight" };
+ writer.writeNext(header);
+ writer.writeNext(user.toWriteFormat());
+ writer.close();
+ }
+
+ @Override
+ public void load() throws IOException {
+ String name;
+ float weight;
+ float height;
+ int age;
+ String gender;
+ float targetWeight;
+
+ try {
+ // parsing a CSV file into BufferedReader class constructor
+ BufferedReader br = new BufferedReader(new FileReader(filePath));
+
+ // Skip Line 1 (header)
+ br.readLine();
+
+ String[] userLine = br.readLine().split(csvDelimiter);
+ name = userLine[0];
+ weight = Float.parseFloat(userLine[1]);
+ height = Float.parseFloat(userLine[2]);
+ age = Integer.parseInt(userLine[3]);
+ gender = userLine[4];
+ targetWeight = Float.parseFloat(userLine[5]);
+ user = new User(name, weight, height, age, gender, targetWeight);
+ br.close();
+ } catch (FileNotFoundException e) {
+ File newFile = new File(filePath);
+ newFile.createNewFile();
+ user = new User();
+ } catch (NullPointerException e) {
+ user = new User();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ user = new User();
+ }
+ }
+
+ public void updateUser(User user) {
+ this.user = user;
+ try {
+ this.write();
+ System.out.println("Successfully updated user settings!");
+ } catch (IOException e) {
+ System.out.println("Error updating user settings!");
+ }
+ }
+
+ public User getUser() {
+ return this.user;
+ }
+}
diff --git a/src/main/java/seedu/ui/CalorieUi.java b/src/main/java/seedu/ui/CalorieUi.java
new file mode 100644
index 0000000000..f351d1e7d9
--- /dev/null
+++ b/src/main/java/seedu/ui/CalorieUi.java
@@ -0,0 +1,27 @@
+package seedu.ui;
+
+public class CalorieUi extends GeneralUi {
+
+ public void requestCalorieLimit() {
+ System.out.println("What do you wish to set as the limit of your daily calorie intake (kcal)?");
+ System.out.println("Please enter it in below: ");
+ }
+
+ public void showCurrentIntake() {
+ System.out.println("This is your current calorie intake for today: ");
+ }
+
+ @Override
+ public void showRemainingIntake(double caloriesLeft) {
+ System.out.println("This is the amount of calories that " +
+ "you can consume before exceeding your limit for today: ");
+ System.out.println(caloriesLeft + " Kcal");
+ }
+ public void showDailyCaloricLimit(double caloricLimit){
+ System.out.println("This is your daily caloric limit: ");
+ System.out.println(caloricLimit + " Kcal");
+ }
+ public void showWellDoneMessage() {
+ System.out.println("Congratulations! Your daily calorie intake for today is within the set limit.");
+ }
+}
diff --git a/src/main/java/seedu/ui/ExampleUi.java b/src/main/java/seedu/ui/ExampleUi.java
new file mode 100644
index 0000000000..9290b91d45
--- /dev/null
+++ b/src/main/java/seedu/ui/ExampleUi.java
@@ -0,0 +1,45 @@
+package seedu.ui;
+
+import seedu.database.ExampleData;
+
+public class ExampleUi extends GeneralUi{
+
+ public void showExerciseExamples() {
+ System.out.println("Here are some examples of exercises:");
+ }
+
+ public void showMealExamples() {
+ System.out.println("Here are some examples of meals that you can consider:");
+ }
+
+ public void afterExercisesMessage() {
+ printLine();
+ System.out.println("Hope this gives you some idea on the exercises that you can do!");
+ }
+
+ public void afterMealsMessage() {
+ printLine();
+ System.out.println("Remember to eat in moderation!");
+ }
+ public void displayExerciseExamples() {
+ String[] exerciseExampleData = ExampleData.getExampleExerciseData();
+ showExerciseExamples();
+ printLine();
+ for (String exercise: exerciseExampleData) {
+ String[] exerciseInfo = exercise.split(",");
+ System.out.println(exerciseInfo[0].substring(0) + ": " + exerciseInfo[1] + ", " + exerciseInfo[2]);
+ }
+ afterExercisesMessage();
+ }
+
+ public void displayMealExamples() {
+ String[] mealExampleData = ExampleData.getExampleMealData();
+ showMealExamples();
+ printLine();
+ for (String meal: mealExampleData) {
+ String[] mealInfo = meal.split(",");
+ System.out.println(mealInfo[0].substring(0));
+ }
+ afterMealsMessage();
+ }
+}
diff --git a/src/main/java/seedu/ui/ExerciseUi.java b/src/main/java/seedu/ui/ExerciseUi.java
new file mode 100644
index 0000000000..301ed6911f
--- /dev/null
+++ b/src/main/java/seedu/ui/ExerciseUi.java
@@ -0,0 +1,10 @@
+package seedu.ui;
+
+import seedu.entities.Exercise;
+
+public class ExerciseUi extends GeneralUi {
+ public static void addedExercise(Exercise exercise) {
+ System.out.println("Added this exercise");
+ System.out.println(exercise);
+ }
+}
diff --git a/src/main/java/seedu/ui/GeneralUi.java b/src/main/java/seedu/ui/GeneralUi.java
new file mode 100644
index 0000000000..a7645d7221
--- /dev/null
+++ b/src/main/java/seedu/ui/GeneralUi.java
@@ -0,0 +1,269 @@
+package seedu.ui;
+
+//import seedu.database.ExampleData;
+import seedu.entities.Exercise;
+import seedu.entities.Meal;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Scanner;
+import java.util.Random;
+
+import static java.lang.Math.abs;
+
+public class GeneralUi {
+ private static Scanner sc = new Scanner(System.in);
+ private static int minimumNumber = 1; //inclusive
+ private static int maximumNumber = 11; //exclusive
+ private static Random random = new Random();
+ private static int numberGenerated = random.nextInt(maximumNumber - minimumNumber) + minimumNumber;
+ private static String endingMessage = "Bye! Hope to see you again soon!";
+ private static String welcomeMessage = "Hello! I am LifeTracker, a program to aid you in keeping fit!"
+ + System.lineSeparator();
+
+ /**
+ * Reads user input
+ * @return user input
+ */
+ public String readLine() {
+ String command = "";
+ while (command.length() == 0) {
+ command = sc.nextLine();
+ if (command.length() == 0) {
+ System.out.println("Please enter a non-blank input!");
+ } else {
+ break;
+ }
+ }
+ return command;
+ }
+
+ public int readInt() {
+ String value = "";
+ while (true) {
+ value = sc.nextLine();
+ if (value.length() == 0 || !value.matches("^([+-]?[1-9]\\d*|0)$")) {
+ System.out.println("Please enter a valid integer!");
+ } else {
+ break;
+ }
+ }
+ return Integer.parseInt(value);
+ }
+
+ public float readFloat() {
+ String value = "";
+ while (true) {
+ value = sc.nextLine();
+ if (value.length() == 0 ||
+ !value.matches("^([0-9]+([.][0-9]*)?|[.][0-9]+)$")) {
+ System.out.println("Invalid input, input is not a positive float value");
+ } else {
+ break;
+ }
+ }
+ return Float.parseFloat(value);
+ }
+
+ /**
+ * Helper function to print divider
+ */
+ public void printLine() {
+ System.out.println("------------------------------------------------------------");
+ }
+
+ public void printMotivateMessage() {
+ if (numberGenerated == 1) {
+ System.out.println("You can do it!");
+ } else if (numberGenerated == 2) {
+ System.out.println("Keep it up!");
+ } else if (numberGenerated == 3) {
+ System.out.println("Good Progress!");
+ } else if (numberGenerated == 4) {
+ System.out.println("Well done!");
+ } else if (numberGenerated == 5) {
+ System.out.println("Good Work!");
+ } else if (numberGenerated == 6) {
+ System.out.println("Nice Effort!");
+ } else if (numberGenerated == 7) {
+ System.out.println("You are almost there!");
+ } else if (numberGenerated == 8) {
+ System.out.println("You can do it!");
+ } else if (numberGenerated == 9) {
+ System.out.println("Every step counts!");
+ } else {
+ System.out.println("Your goal is within reach!");
+ }
+ }
+
+
+ /**
+ * Prints Goodbye message when Duke exits
+ */
+ public void printGoodbye() {
+ System.out.println();
+ this.printLine();
+ System.out.println(endingMessage);
+ this.printLine();
+ }
+
+ private void printLogo() {
+ System.out.println(
+ " _ _ __ _______ _ " + System.lineSeparator()
+ + "| | (_)/ _||__ __| | | " + System.lineSeparator()
+ + "| | _| |_ ___| |_ __ __ _ ___| | _____ _ __ " + System.lineSeparator()
+ + "| | | | _/ _ \\ | '__/ _` |/ __| |/ / _ \\ '__|" + System.lineSeparator()
+ + "| |____| | || __/ | | | (_| | (__| < __/ | " + System.lineSeparator()
+ + "|______|_|_| \\___|_|_| \\__,_|\\___|_|\\_\\___|_| " + System.lineSeparator()
+ );
+ }
+ /**
+ * Prints Welcome message when Duke first starts
+ */
+ public void printIntroduction() {
+ this.printLine();
+ System.out.println("Hello! Welcome to");
+ this.printLogo();
+ this.printLine();
+ System.out.println(welcomeMessage);
+ System.out.println("Please enter command 'help' if you require assistance.");
+ }
+ public void requestWeight(){}
+ public void showLatestWeight(int weight){}
+
+ public void printAllFoods(FoodStorage foodStorage) {
+ if (foodStorage.getFoodsCount() == 0) {
+ System.out.println("There are no foods in your food list!");
+ } else {
+ System.out.println("Here are the foods in your food list:");
+ for (int i = 0; i < foodStorage.getFoodsCount(); i++) {
+ String taskDescription = foodStorage.getFoodById(i).toString();
+ System.out.println((i + 1) + ". " + taskDescription);
+ }
+ }
+ }
+
+ public void printAllMeals(MealStorage mealStorage) {
+ if (mealStorage.getMealCount() == 0) {
+ System.out.println("There are no meals in your meal list!");
+ } else {
+ System.out.println("Here are the meals in your meal list:");
+ for (int i = 0; i < mealStorage.getMealCount(); i++) {
+ String taskDescription = mealStorage.getMealById(i).toString();
+ System.out.println((i + 1) + ". " + taskDescription);
+ }
+ }
+ }
+
+ public void printAllExercises(ExerciseStorage exerciseStorage) {
+ if (exerciseStorage.getExercisesCount() == 0) {
+ System.out.println("There are no exercises in your exercise list!");
+ } else {
+ System.out.println("Here are the exercises in your exercise list:");
+ for (int i = 0; i < exerciseStorage.getExercisesCount(); i++) {
+ String taskDescription = exerciseStorage.getExerciseById(i).toString();
+ System.out.println((i + 1) + ". " + taskDescription);
+ }
+ }
+ }
+
+ public void printNewMealAdded(Meal meal) {
+ System.out.println(meal);
+ }
+
+ public void printMealDeleted(Meal meal) {
+ System.out.println("Successfully deleted this meal:");
+ System.out.println(meal);
+ }
+
+ public void printExerciseDeleted(Exercise exercise) {
+ System.out.println("Successfully deleted this exercise:");
+ System.out.println(exercise);
+ }
+
+ public void requestCalorieLimit() {
+ }
+
+ public void showCurrentIntake() {
+ }
+
+ public void showRemainingIntake(double caloriesLeft) {
+
+ }
+ public void showDailyCaloricLimit(double caloricLimit) {
+ }
+ public void showWellDoneMessage(){
+ }
+ public void displayDayCalories(ExerciseStorage exerciseStorage, LocalDate date, MealStorage mealStorage) {
+ List exercisesOnSpecificDate = exerciseStorage.getExercisesByDate(date);
+ float caloricDeficit = 0;
+ for (Exercise exercise: exercisesOnSpecificDate){
+ caloricDeficit += exercise.getCaloriesBurnt();
+ }
+ List mealsOnSpecificDate = mealStorage.getMealByDate(date);
+ float caloricGain = 0;
+ for (Meal meal: mealsOnSpecificDate){
+ caloricGain += meal.getTotalCalories();
+ }
+ float netCalories = caloricGain - caloricDeficit;
+ System.out.println("Calories Gained on " + date + " : " + caloricGain);
+ System.out.println("Calories Lost on " + date + " : " + caloricDeficit);
+ if (netCalories > 0) {
+ System.out.println("You have gained " + netCalories + " calories on " + date);
+ } else if (netCalories == 0) {
+ System.out.println("Your net calories on " + date + "is zero.");
+ } else {
+ System.out.println("You have lost " + abs(netCalories) + " calories on " + date);
+ }
+ }
+
+ public void printFieldNotStored() {
+ System.out.println("The field has not been stored yet please update it.");
+ }
+
+ public void printName(String name){
+ System.out.println("Name: " + name);
+ }
+
+ public void printWeight(float weight){
+ System.out.println("Weight: " + weight + " kg");
+ }
+
+ public void printHeight(float height){
+ System.out.println("Height: " + height + " cm");
+ }
+ public void printAge(int age){
+ System.out.println("Age: " + age + " years old");
+ }
+ public void printGender(String gender){
+ System.out.println("Gender: " + gender);
+ }
+
+ public void printHelpMenu(){
+ System.out.println( "Here are the list of available commands: \n" + "[view]: Here's the list of information"
+ + " you can choose to view followed by it's respective /[fieldName].\n"
+ + " 1. Name: /name \n" + " 2. Weight: /weight\n" + " 3. Height: /height\n" + " 4. Age: /age\n"
+ + " 5. Gender: /gender\n" + " 6. Daily caloric limit: /caloricLimit\n"
+ + " 7. Calories left today: /caloriesLeft\n" + " 8. Target weight: /targetWeight\n"
+ + "Usage: view /[fieldName]\n"+"[update]: Here's the list of information "
+ + "you can choose to update followed by it's respective /[fieldName].\n" + " 1. Name: /name\n"
+ + " 2. Weight: /weight\n" + " 3. Height: /height\n" + " 4. Age: /age\n"
+ + " 5. Gender: /gender\n"+" 6. Target Weight: /targetWeight\n"
+ + "Usage: update /[fieldName] [newInfo]\n"
+ + "[add]: Add a meal.\n" + "Usage: add /on [date] /type [MealType] /foods [foods]\n"
+ + "[list]: List either all the foods in the database, all previous added meals or exercises.\n"
+ + "Usage: list foods / list meals / list exercises \n" + "[delete]: Deletes a previously added meal.\n"
+ + "Usage: delete [index]\n" + "[filter]: Filters food by calorie content.\n"
+ +"[nutrition]: Find the nutrients of a specific kind of food.\n"+"[exercise]: Input a completed exercise.\n"
+ + "Usage: exercise /type [exercise name] /description [exercise description] "
+ + "/calories [calories burnt] /on [date]\n" + "[track]: Returns your caloric intake from previous days.\n"
+ + "Usage: track all OR track /start [DATE] /end [DATE] \n"
+ + "[examples]: Displays examples for inputs\n" + "[bye]: Exits the program.");
+ System.out.println("For any other questions please visit out User Guide.\n");
+ }
+}
+
+
diff --git a/src/main/java/seedu/ui/WeightUi.java b/src/main/java/seedu/ui/WeightUi.java
new file mode 100644
index 0000000000..ed931069fd
--- /dev/null
+++ b/src/main/java/seedu/ui/WeightUi.java
@@ -0,0 +1,24 @@
+package seedu.ui;
+import java.util.ArrayList;
+public class WeightUi extends GeneralUi {
+
+ @Override
+ public void requestWeight() {
+ System.out.println("Please enter your weight (in kg):");
+ }
+
+ @Override
+ public void showLatestWeight(int weight) {
+ System.out.println("This is the latest weight you have entered in: " + weight + "kg");
+ }
+
+ //@Override
+ public void showAllWeight(ArrayList weights) {
+ System.out.println("List of weights (in kg): ");
+ }
+
+ //@Override
+ public void showWeightAdded(int weight) {
+ System.out.println("This is your updated weight: " + weight + "kg");
+ }
+}
diff --git a/src/test/java/seedu/commands/AddExerciseCommandTest.java b/src/test/java/seedu/commands/AddExerciseCommandTest.java
new file mode 100644
index 0000000000..b65c22b524
--- /dev/null
+++ b/src/test/java/seedu/commands/AddExerciseCommandTest.java
@@ -0,0 +1,108 @@
+package seedu.commands;
+
+import seedu.constants.DateConstants;
+import seedu.exceptions.InvalidDateException;
+import seedu.exceptions.InvalidArgumentsException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.ExerciseStorage;
+
+import org.junit.jupiter.api.Test;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.ui.GeneralUi;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+
+public class AddExerciseCommandTest {
+ private final ExerciseStorage exerciseStorage = new ExerciseStorage("./data/exerciseData.csv");
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final GeneralUi ui = new GeneralUi();
+
+ @Test
+ void addExercise_invalidDateIncluded_expectInvalidDateException() {
+ String commandWord = "exercise";
+ String userInput = "exercise /type Running /description 5km /calories 400 /on 3/13/2023";
+ AddExerciseCommand command = new AddExerciseCommand(commandWord, userInput);
+ InvalidDateException thrown = assertThrows(InvalidDateException.class, () -> {
+ command.execute(ui, null, null, null, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! 3/13/2023 is not a valid date!" +
+ " Please format the date as: " + DateConstants.PARSE_FORMAT + "." +
+ "\n" + "Also check whether the date you've entered exists!";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void addExercise_invalidCalorieIncluded_expectInvalidArgumentsException() {
+ String commandWord = "exercise";
+ String userInput = "exercise /type Running /description 5km /calories wronginput /on 3/13/2023";
+ AddExerciseCommand command = new AddExerciseCommand(commandWord, userInput);
+ InvalidArgumentsException thrown = assertThrows(InvalidArgumentsException.class, () -> {
+ command.execute(null, null, null, null, exerciseStorage);
+ });
+ String expectedErrorMessage = "Error: Invalid arguments for /calories for command exercise";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void addExercise_validExerciseAdd_expectNoExceptions() {
+ String commandWord = "exercise";
+ String userInput = "exercise /type Running /description 5km /calories 400 /on 3/1/2023";
+ AddExerciseCommand command = new AddExerciseCommand(commandWord, userInput);
+ assertDoesNotThrow(() -> {
+ command.execute(ui, null, mealStorage, null, exerciseStorage);
+ });
+ }
+
+ @Test
+ void addExercise_missingType_expectMissingArgumentsException() {
+ String commandWord = "exercise";
+ String userInput = "exercise /description 5km /calories 400 /on 3/13/2023";
+ AddExerciseCommand command = new AddExerciseCommand(commandWord, userInput);
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ command.execute(null, null, null, null, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! Missing argument /type for command exercise";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void addExercise_missingDescription_expectMissingArgumentsException() {
+ String commandWord = "exercise";
+ String userInput = "exercise /type Running /calories 400 /on 3/1/2023";
+ AddExerciseCommand command = new AddExerciseCommand(commandWord, userInput);
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ command.execute(null, null, null, null, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! Missing argument /description for command exercise";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void addExercise_missingCalories_expectMissingArgumentsException() {
+ String commandWord = "exercise";
+ String userInput = "exercise /type Running /description 5km /on 3/1/2023";
+ AddExerciseCommand command = new AddExerciseCommand(commandWord, userInput);
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ command.execute(null, null, null, null, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! Missing argument /calories for command exercise";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void addExercise_missingDate_expectMissingArgumentsException() {
+ String commandWord = "exercise";
+ String userInput = "exercise /type Running /description 5km /calories 400";
+ AddExerciseCommand command = new AddExerciseCommand(commandWord, userInput);
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ command.execute(null, null, null, null, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! Missing argument /on for command exercise";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/commands/AddMealCommandTest.java b/src/test/java/seedu/commands/AddMealCommandTest.java
new file mode 100644
index 0000000000..6653d430df
--- /dev/null
+++ b/src/test/java/seedu/commands/AddMealCommandTest.java
@@ -0,0 +1,73 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.constants.DateConstants;
+import seedu.definitions.MealTypes;
+import seedu.entities.Food;
+import seedu.entities.Meal;
+import seedu.exceptions.InvalidArgumentsException;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+class AddMealCommandTest {
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final DateTimeFormatter dtf = DateConstants.DATABASE_DTF;
+ private ArrayList foodList = new ArrayList<>();
+
+ @Test
+ void addMeal_singleMealAdded_expectListSizeIncrease() throws InvalidArgumentsException {
+ mealStorage.resetStorage();
+ int oldSize = mealStorage.getMealCount();
+ foodList.add(foodStorage.getFoodById(2));
+ LocalDate date = LocalDate.parse("1/1/2023", dtf);
+ mealStorage.saveMeal(new Meal(foodList, date, MealTypes.BREAKFAST));
+ int newSize = mealStorage.getMealCount();
+ assertEquals(oldSize + 1, newSize);
+ }
+
+ @Test
+ void addTwoMeals_twoDifferentMealsAddedAtDifferentDates_expectSortedMeals() {
+ mealStorage.resetStorage();
+ LocalDate date;
+ foodList.add(foodStorage.getFoodById(2));
+ date = LocalDate.parse("31/12/2023", dtf);
+ mealStorage.saveMeal(new Meal(foodList, date, MealTypes.BREAKFAST));
+ date = LocalDate.parse("1/11/2023", dtf);
+ mealStorage.saveMeal(new Meal(foodList, date, MealTypes.BREAKFAST));
+ Meal meal0 = mealStorage.getMealById(0);
+ Meal meal1 = mealStorage.getMealById(1);
+ assertFalse(meal0.compareTo(meal1) > 0, "Array is not sorted!");
+ }
+
+ @Test
+ void addTwoMeals_twoDifferentMealsAddedAtDifferentMealTypes_expectSortedMeals() {
+ mealStorage.resetStorage();
+ LocalDate date;
+ foodList.add(foodStorage.getFoodById(2));
+ date = LocalDate.parse("31/12/2023", dtf);
+ mealStorage.saveMeal(new Meal(foodList, date, MealTypes.LUNCH));
+ date = LocalDate.parse("31/12/2023", dtf);
+ mealStorage.saveMeal(new Meal(foodList, date, MealTypes.BREAKFAST));
+ Meal meal0 = mealStorage.getMealById(0);
+ Meal meal1 = mealStorage.getMealById(1);
+ assertFalse(meal0.compareTo(meal1) > 0, "Array is not sorted!");
+ }
+
+ @Test
+ void parseInput_emptyInput_expectException() {
+
+ String commandDescriptor = "";
+ assertThrows(NumberFormatException.class,
+ () -> Integer.parseInt(commandDescriptor));
+ }
+}
diff --git a/src/test/java/seedu/commands/DeleteCommandTest.java b/src/test/java/seedu/commands/DeleteCommandTest.java
new file mode 100644
index 0000000000..52e9a88425
--- /dev/null
+++ b/src/test/java/seedu/commands/DeleteCommandTest.java
@@ -0,0 +1,88 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+import seedu.constants.DateConstants;
+import seedu.definitions.MealTypes;
+import seedu.entities.Exercise;
+import seedu.entities.Meal;
+import seedu.exceptions.InvalidIndexException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+import java.time.LocalDate;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+
+class DeleteCommandTest {
+ private DeleteCommand deleteCommand;
+ private final ExerciseStorage exerciseStorage = new ExerciseStorage("./data/exerciseData.csv");
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final UserStorage userStorage = new UserStorage("./data/userData.csv");
+
+ @Test
+ void deleteMeal_validMealToDelete_expectNoExceptions() throws LifeTrackerException {
+ GeneralUi ui = new GeneralUi();
+ String testDateInput = "01/01/2023";
+ LocalDate testDate = LocalDate.parse(testDateInput, DateConstants.PARSE_DTF);
+ Meal meal = new Meal(foodStorage.getFoods(), testDate, MealTypes.LUNCH);
+ mealStorage.saveMeal(meal);
+ deleteCommand = new DeleteCommand("delete", "delete /meal 1");
+ deleteCommand.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage);
+ assertDoesNotThrow(() -> {
+ deleteCommand.execute(ui, null, mealStorage, null, exerciseStorage);
+ });
+ assertFalse(mealStorage.getMeals().contains(meal));
+ }
+
+ @Test
+ void deleteExercise_validExerciseToDelete_expectNoExceptions() throws LifeTrackerException {
+ GeneralUi ui = new GeneralUi();
+ String testDateInput = "01/01/2023";
+ LocalDate testDate = LocalDate.parse(testDateInput, DateConstants.PARSE_DTF);
+ Exercise exercise = new Exercise("run", "3km", 800, testDate);
+ exerciseStorage.saveExercise(exercise);
+ deleteCommand = new DeleteCommand("delete", "delete /exercise 1");
+ deleteCommand.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage);
+ assertDoesNotThrow(() -> {
+ deleteCommand.execute(ui, null, mealStorage, null, exerciseStorage);
+ });
+ assertFalse(exerciseStorage.getExercises().contains(exercise));
+ }
+
+ @Test
+ void deleteExercise_missingIndex_expectMissingArgumentsException() throws LifeTrackerException {
+ GeneralUi ui = new GeneralUi();
+ String commandWord = "delete";
+ String userInput = "delete";
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ DeleteCommand command = new DeleteCommand(commandWord, userInput);
+ command.execute(ui, null, mealStorage, null, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! Missing argument [/meal, /exercise] for command delete";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void deleteMeal_missingType_expectInvalidIndexException() throws LifeTrackerException {
+ GeneralUi ui = new GeneralUi();
+ int currentMealsSize = mealStorage.getMealCount();
+ int testCase = currentMealsSize + 1;
+ String commandWord = "delete";
+ String userInput = "delete /meal " + testCase;
+ InvalidIndexException thrown = assertThrows(InvalidIndexException.class, () -> {
+ DeleteCommand command = new DeleteCommand(commandWord, userInput);
+ command.execute(ui, null, mealStorage, null, exerciseStorage);
+ });
+ String expectedErrorMessage = testCase + " is not a valid index!";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/commands/ExamplesCommandTest.java b/src/test/java/seedu/commands/ExamplesCommandTest.java
new file mode 100644
index 0000000000..55d08c33f2
--- /dev/null
+++ b/src/test/java/seedu/commands/ExamplesCommandTest.java
@@ -0,0 +1,34 @@
+package seedu.commands;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.LifeTrackerException;
+import seedu.ui.ExampleUi;
+
+
+class ExamplesCommandTest {
+
+ @Test
+ void printExamples_validInput_expectException() throws LifeTrackerException {
+ ExampleUi ui = new ExampleUi();
+ ExamplesCommand examplesCommand = new ExamplesCommand("examples", " exercise");
+ assertDoesNotThrow(() -> {
+ examplesCommand.printExamples("exercise", ui);
+ });
+ }
+
+ @Test
+ void printExamples_invalidInput_expectException() throws LifeTrackerException {
+ ExampleUi ui = new ExampleUi();
+ ExamplesCommand examplesCommand = new ExamplesCommand("examples", " food");
+ LifeTrackerException thrown = assertThrows(LifeTrackerException.class, () -> {
+ examplesCommand.printExamples("food", ui);
+ });
+
+ String expectedErrorMessage = "You can only input exercise/meal for this command!";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/commands/ExitCommandTest.java b/src/test/java/seedu/commands/ExitCommandTest.java
new file mode 100644
index 0000000000..43b15602e6
--- /dev/null
+++ b/src/test/java/seedu/commands/ExitCommandTest.java
@@ -0,0 +1,36 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.LifeTrackerException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class ExitCommandTest {
+ private ExitCommand exitCommand;
+ private final ExerciseStorage exerciseStorage = new ExerciseStorage("./data/exerciseData.csv");
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final UserStorage userStorage = new UserStorage("./data/userData.csv");
+
+ @BeforeEach
+ public void setUp() {
+ exitCommand = new ExitCommand();
+ }
+
+ @Test
+ public void testExecute() throws LifeTrackerException {
+ GeneralUi ui = new GeneralUi();
+ try {
+ exitCommand.execute(ui,foodStorage, mealStorage, userStorage, exerciseStorage);
+ assertTrue(exitCommand.isExit());
+ } catch (LifeTrackerException e) {
+ throw new LifeTrackerException("Unexpected exception thrown.");
+ }
+ }
+}
diff --git a/src/test/java/seedu/commands/FilterCaloriesCommandTest.java b/src/test/java/seedu/commands/FilterCaloriesCommandTest.java
new file mode 100644
index 0000000000..9deb844387
--- /dev/null
+++ b/src/test/java/seedu/commands/FilterCaloriesCommandTest.java
@@ -0,0 +1,51 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+import seedu.constants.DateConstants;
+import seedu.entities.Food;
+import seedu.exceptions.LifeTrackerException;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class FilterCaloriesCommandTest {
+
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final DateTimeFormatter dtf = DateConstants.DATABASE_DTF;
+ private ArrayList foodList = new ArrayList<>();
+
+ @Test
+ void filterCalories_validLowerAndUpperLimit_expectNoExceptions() throws LifeTrackerException {
+ mealStorage.resetStorage();
+ int foodsInRange = 0;
+ int caloriesLowerLimit = 500;
+ int caloriesUpperLimit = 1000;
+ for (Food food: foodStorage.getFoods()){
+ if (food.getCalories() > caloriesLowerLimit && food.getCalories() < caloriesUpperLimit){
+ foodsInRange += 1;
+ }
+ }
+ List caloriesFilteredFoods = foodStorage.getFoodsByCalories(caloriesLowerLimit, caloriesUpperLimit);
+ assertTrue(foodsInRange == caloriesFilteredFoods.size());
+ }
+
+ @Test
+ void filterCalories_invalidLowerAndUpperLimit_expectException() throws LifeTrackerException {
+ mealStorage.resetStorage();
+ int caloriesLowerLimit = 1000;
+ int caloriesUpperLimit = 500;
+ LifeTrackerException thrown = assertThrows(LifeTrackerException.class, () -> {
+ foodStorage.getFoodsByCalories(caloriesLowerLimit,caloriesUpperLimit);
+ });
+ String expectedErrorMessage = "Please enter valid lower and upper calorie limits!";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/commands/ListCommandTest.java b/src/test/java/seedu/commands/ListCommandTest.java
new file mode 100644
index 0000000000..f383e843bc
--- /dev/null
+++ b/src/test/java/seedu/commands/ListCommandTest.java
@@ -0,0 +1,44 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ListCommandTest {
+ private ListCommand listCommand;
+ private GeneralUi ui = new GeneralUi();
+ private final ExerciseStorage exerciseStorage = new ExerciseStorage("./data/exerciseData.csv");
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final UserStorage userStorage = new UserStorage("./data/userData.csv");
+
+ @Test
+ public void listCommand_missingOrExtraOrInvalidArguments_expectExceptionThrown() {
+ assertThrows(MissingArgumentsException.class, () -> new ListCommand("list", "list"));
+ assertThrows(MissingArgumentsException.class, () -> new ListCommand("list", "list "));
+ assertThrows(ExtraArgumentsException.class, () ->
+ new ListCommand("list", "list arg1 arg2"));
+ }
+
+ @Test
+ public void listCommand_invalidArgument_expectExceptionThrown() throws LifeTrackerException {
+ listCommand = new ListCommand("list", "list savings");
+ assertThrows(LifeTrackerException.class, () ->
+ listCommand.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage));
+ }
+
+ @Test
+ public void listMeals_validInput_expectNoExceptionsThrown() throws LifeTrackerException {
+ listCommand = new ListCommand("list", "list meals");
+ assertDoesNotThrow(() -> listCommand.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage));
+ }
+}
diff --git a/src/test/java/seedu/commands/TrackCalorieCommandTest.java b/src/test/java/seedu/commands/TrackCalorieCommandTest.java
new file mode 100644
index 0000000000..bf15152a48
--- /dev/null
+++ b/src/test/java/seedu/commands/TrackCalorieCommandTest.java
@@ -0,0 +1,69 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.InvalidDateException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.ExerciseStorage;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+class TrackCalorieCommandTest {
+ private TrackCalorieCommand trackCalorieCommand;
+ private final ExerciseStorage exerciseStorage = new ExerciseStorage("./data/exerciseData.csv");
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final UserStorage userStorage = new UserStorage("./data/userData.csv");
+
+ @Test
+ public void trackCalories_validOneLineInput_shouldNotThrowException() {
+ GeneralUi ui = new GeneralUi();
+ String commandWord = "track";
+ String userInput = "track /start 01/01/2022 /end 10/01/2022";
+ trackCalorieCommand = new TrackCalorieCommand(commandWord, userInput);
+ assertDoesNotThrow(() -> {
+ trackCalorieCommand.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage);
+ });
+ }
+
+ @Test
+ public void trackCalories_validDisplayAllInput_shouldNotThrowException() {
+ GeneralUi ui = new GeneralUi();
+ String commandWord = "track";
+ String userInput = "track all";
+ trackCalorieCommand = new TrackCalorieCommand(commandWord, userInput);
+ assertDoesNotThrow(() -> {
+ trackCalorieCommand.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage);
+ });
+ }
+
+ @Test
+ public void trackCalories_missingArguments_expectMissingArgumentsException() {
+ GeneralUi ui = new GeneralUi();
+ TrackCalorieCommand command = new TrackCalorieCommand("track", "track /start 10/01/2022");
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ command.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! Missing argument /end for command track";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ public void trackCalories_invalidDate_expectInvalidDateException() {
+ GeneralUi ui = new GeneralUi();
+ TrackCalorieCommand command = new TrackCalorieCommand("track",
+ "track /start 10/01/2022 /end 10/13/2022");
+ InvalidDateException thrown = assertThrows(InvalidDateException.class, () -> {
+ command.execute(ui, foodStorage, mealStorage, userStorage, exerciseStorage);
+ });
+ String expectedErrorMessage = "Oops! 10/13/2022 is not a valid date! Please format the date as: d/M/yyyy.\n" +
+ "Also check whether the date you've entered exists!";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+}
diff --git a/src/test/java/seedu/commands/UpdateUserCommandTest.java b/src/test/java/seedu/commands/UpdateUserCommandTest.java
new file mode 100644
index 0000000000..945eaf075b
--- /dev/null
+++ b/src/test/java/seedu/commands/UpdateUserCommandTest.java
@@ -0,0 +1,325 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+import seedu.entities.CaloricIntake;
+import seedu.exceptions.ExtraArgumentsException;
+import seedu.exceptions.InvalidFieldNameException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.exceptions.InvalidFieldInfoFormatException;
+import seedu.exceptions.NegativeFieldInfoException;
+import seedu.exceptions.ImpossibleValueException;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.time.LocalDate;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+
+public class UpdateUserCommandTest {
+ private final UserStorage userStorage = new UserStorage("./data/userData.csv");
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final GeneralUi ui = new GeneralUi();
+ private final CaloricIntake meals = new CaloricIntake(mealStorage.getMealByDate(LocalDate.now()));
+
+ @Test
+ void updateUser_missingFieldToUpdate_expectMissingArgumentsException() throws LifeTrackerException {
+ String commandWord = "update";
+ String userInput = "update";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedErrorMessage = "Oops! Missing argument [user information field]/ [new information] " +
+ "for command update";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void updateUser_invalidFieldName_expectInvalidFieldNameException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /nil test";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldNameException thrown = assertThrows(InvalidFieldNameException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "Oops! Invalid field name /nil for command update";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_extraArguments_expectExtraArgumentsException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /nil test test";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ ExtraArgumentsException thrown = assertThrows(ExtraArgumentsException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "Oops! Too many arguments in your input!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+
+ @Test
+ void updateUser_updateNameAsNumbers_expectInvalidFieldInfoFormatException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /name 123";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldInfoFormatException thrown = assertThrows(InvalidFieldInfoFormatException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "123 is not of valid format for /name please try again!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateNameAsSpecialCharacters_expectInvalidFieldInfoFormatException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /name @#!%&$^3";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldInfoFormatException thrown = assertThrows(InvalidFieldInfoFormatException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "@#!%&$^3 is not of valid format for /name please try again!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateName_expectSuccessfullyUpdatedMessage() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /name test";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Successfully updated user settings!";
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void updateUser_updateWeightAsAlphabets_expectInvalidFieldInfoFormatException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /weight abc";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldInfoFormatException thrown = assertThrows(InvalidFieldInfoFormatException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "abc is not of valid format for /weight please try again!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateWeightAsNegativeValue_expectNegativeFieldInfoException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /weight -10";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ NegativeFieldInfoException thrown = assertThrows(NegativeFieldInfoException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "Oops! You cannot enter a negative value for /weight in command update";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+
+ @Test
+ void updateUser_updateWeightAsAbsurdValue_expectImpossibleValueException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /weight 800";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ ImpossibleValueException thrown = assertThrows(ImpossibleValueException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "800 kg is an impossible value for /weight please enter a valid one!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateWeight_expectSuccessfullyUpdatedMessage() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /weight 78";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Successfully updated user settings!";
+ assertTrue(output.contains(expectedMessage));
+ }
+ @Test
+ void updateUser_updateHeightAsAlphabets_expectInvalidFieldInfoFormatException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /height abc";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldInfoFormatException thrown = assertThrows(InvalidFieldInfoFormatException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "abc is not of valid format for /height please try again!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateHeightAsNegativeValue_expectNegativeFieldInfoException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /height -10";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ NegativeFieldInfoException thrown = assertThrows(NegativeFieldInfoException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "Oops! You cannot enter a negative value for /height in command update";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+
+ @Test
+ void updateUser_updateHeightAsAbsurdValue_expectImpossibleValueException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /height 800";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ ImpossibleValueException thrown = assertThrows(ImpossibleValueException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "800 cm is an impossible value for /height please enter a valid one!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+
+ @Test
+ void updateUser_updateHeight_expectSuccessfullyUpdatedMessage() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /height 178";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Successfully updated user settings!";
+ assertTrue(output.contains(expectedMessage));
+ }
+ @Test
+ void updateUser_updateAgeAsAlphabets_expectInvalidFieldInfoFormatException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /age abc";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldInfoFormatException thrown = assertThrows(InvalidFieldInfoFormatException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "abc is not of valid format for /age please try again!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateAgeAsNegativeValue_expectNegativeFieldInfoException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /age -10";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ NegativeFieldInfoException thrown = assertThrows(NegativeFieldInfoException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "Oops! You cannot enter a negative value for /age in command update";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+
+ @Test
+ void updateUser_updateAgeAsAbsurdValue_expectImpossibleValueException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /age 800";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ ImpossibleValueException thrown = assertThrows(ImpossibleValueException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "800 years old is an impossible value for /age please enter a valid one!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateAge_expectSuccessfullyUpdatedMessage() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /age 23";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Successfully updated user settings!";
+ assertTrue(output.contains(expectedMessage));
+ }
+ @Test
+ void updateUser_updateGenderAsNumbers_expectInvalidFieldInfoFormatException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /gender 123";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldInfoFormatException thrown = assertThrows(InvalidFieldInfoFormatException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "123 is not of valid format for /gender please try again!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateGender_expectSuccessfullyUpdatedMessage() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /gender male";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Successfully updated user settings!";
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void updateUser_updateTargetWeightAsAlphabets_expectInvalidFieldInfoFormatException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /targetWeight abc";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ InvalidFieldInfoFormatException thrown = assertThrows(InvalidFieldInfoFormatException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "abc is not of valid format for /targetWeight please try again!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateTargetWeightAsNegativeValue_expectNegativeFieldInfoException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /targetWeight -10";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ NegativeFieldInfoException thrown = assertThrows(NegativeFieldInfoException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "Oops! You cannot enter a negative value for /targetWeight in command update";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void updateUser_updateTargetWeight_expectSuccessfullyUpdatedMessage() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /targetWeight 60";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Successfully updated user settings!";
+ assertTrue(output.contains(expectedMessage));
+ }
+ @Test
+ void updateUser_updateTargetWeightAsAbsurdValue_expectImpossibleValueException() throws LifeTrackerException{
+ String commandWord = "update";
+ String userInput = "update /targetWeight 800";
+ UpdateUserCommand command = new UpdateUserCommand(commandWord, userInput);
+ ImpossibleValueException thrown = assertThrows(ImpossibleValueException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "800 kg is an impossible value for /targetWeight please enter a valid one!";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/commands/ViewUserCommandTest.java b/src/test/java/seedu/commands/ViewUserCommandTest.java
new file mode 100644
index 0000000000..6fcbf6187a
--- /dev/null
+++ b/src/test/java/seedu/commands/ViewUserCommandTest.java
@@ -0,0 +1,172 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+import seedu.entities.CaloricIntake;
+import seedu.exceptions.InvalidFieldNameException;
+import seedu.exceptions.LifeTrackerException;
+import seedu.exceptions.MissingArgumentsException;
+import seedu.storage.FoodStorage;
+import seedu.storage.MealStorage;
+import seedu.storage.UserStorage;
+import seedu.ui.GeneralUi;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.time.LocalDate;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ViewUserCommandTest {
+ private final UserStorage userStorage = new UserStorage("./data/userData.csv");
+ private final FoodStorage foodStorage = new FoodStorage();
+ private final MealStorage mealStorage = new MealStorage("./data/mealData.csv", foodStorage);
+ private final GeneralUi ui = new GeneralUi();
+ private final CaloricIntake meals = new CaloricIntake(mealStorage.getMealByDate(LocalDate.now()));
+ @Test
+ void viewUser_missingFieldName_expectMissingArgumentsException() throws LifeTrackerException {
+ String commandWord = "view";
+ String userInput = "view";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ MissingArgumentsException thrown = assertThrows(MissingArgumentsException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedErrorMessage = "Oops! Missing argument [fieldName] for command view";
+ assertEquals(expectedErrorMessage, thrown.getMessage());
+ }
+
+ @Test
+ void viewUser_invalidFieldName_expectInvalidFieldNameException() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /nil";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ InvalidFieldNameException thrown = assertThrows(InvalidFieldNameException.class, () -> {
+ command.execute(ui,null,mealStorage,userStorage,null);
+ });
+ String expectedMessage = "Oops! Invalid field name /nil for command view";
+ assertEquals(expectedMessage,thrown.getMessage());
+ }
+ @Test
+ void viewUser_viewName_expectName() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /name";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = userStorage.getUser().getName();
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void viewUser_viewWeight_expectWeight() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /weight";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Weight: " + userStorage.getUser().getWeight() + " kg";
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void viewUser_viewHeight_expectHeight() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /height";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Height: " + userStorage.getUser().getHeight() + " cm";
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void viewUser_viewAge_expectAge() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /age";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Age: " + userStorage.getUser().getAge() + " years old";
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void viewUser_viewGender_expectGender() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /gender";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Gender: " + userStorage.getUser().getGender();
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void viewUser_viewCaloricLimit_expectCaloricLimit() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /caloricLimit";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "This is your daily caloric limit: " + System.lineSeparator() +
+ + userStorage.getUser().getCaloricLimit() + " Kcal";
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void viewUser_viewCaloriesLeft_expectCaloriesLeft() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /caloriesLeft";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "This is the amount of calories that " +
+ "you can consume before exceeding your limit for today: " + System.lineSeparator() +
+ + userStorage.getUser().getCaloriesLeft(meals.getTotalDailyCalories()) + " Kcal";
+ assertTrue(output.contains(expectedMessage));
+ }
+
+ @Test
+ void viewUser_viewTargetWeight_expectTargetWeight() throws LifeTrackerException{
+ String commandWord = "view";
+ String userInput = "view /targetWeight";
+ ViewUserCommand command = new ViewUserCommand(commandWord, userInput);
+ PrintStream oldOut = System.out;
+ System.setOut(oldOut);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stream));
+ command.execute(ui,null,mealStorage,userStorage,null);
+ String output = new String(stream.toByteArray());
+ String expectedMessage = "Target Weight: " + userStorage.getUser().getTargetWeight()+ " kg";
+ assertTrue(output.contains(expectedMessage));
+ }
+}
diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java
deleted file mode 100644
index 2dda5fd651..0000000000
--- a/src/test/java/seedu/duke/DukeTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package seedu.duke;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import org.junit.jupiter.api.Test;
-
-class DukeTest {
- @Test
- public void sampleTest() {
- assertTrue(true);
- }
-}
diff --git a/src/test/java/seedu/entities/UserTest.java b/src/test/java/seedu/entities/UserTest.java
new file mode 100644
index 0000000000..0a1b26eccc
--- /dev/null
+++ b/src/test/java/seedu/entities/UserTest.java
@@ -0,0 +1,54 @@
+package seedu.entities;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class UserTest {
+ private final User newUser = new User("user", 80, 180, 21, "male", 75);
+
+ @Test
+ void calculateCaloricNeeds_male_expect1466() {
+ assertEquals(1466, 1466);
+ }
+
+ @Test
+ void calculateCaloricNeeds_female_expect1325() {
+ assertEquals(1325, 1325);
+ }
+
+ @Test
+ void calculateCaloricNeeds_male_expect66() {
+ assertEquals(66, 66);
+ }
+
+ @Test
+ void calculateCaloricNeeds_female_expect651p86() {
+ assertEquals(651.86, 651.86);
+ }
+
+ @Test
+ void getWeight_input80_expect80() {
+ assertEquals(80.0, newUser.getWeight());
+ }
+
+ @Test
+ void getHeight_input180_expect180() {
+ assertEquals(180.0, newUser.getHeight());
+ }
+
+ @Test
+ void getAge_input21_expect21() {
+ assertEquals(21, newUser.getAge());
+ }
+
+ @Test
+ void getGender_male_expectMale() {
+ assertEquals("male", newUser.getGender());
+ }
+
+ @Test
+ void getTargetWeight_input75_expect75() {
+ assertEquals(75.0, newUser.getTargetWeight());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/InvalidArgumentsExceptionTest.java b/src/test/java/seedu/exceptions/InvalidArgumentsExceptionTest.java
new file mode 100644
index 0000000000..37c76cc78a
--- /dev/null
+++ b/src/test/java/seedu/exceptions/InvalidArgumentsExceptionTest.java
@@ -0,0 +1,15 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class InvalidArgumentsExceptionTest {
+ @Test
+ void createInvalidArgumentsException_emptyInput_expectCorrectErrorMessage() {
+ InvalidArgumentsException error = new InvalidArgumentsException(
+ "testCommand", "/testArgument");
+ String expectedErrorMessage = "Error: Invalid arguments for /testArgument for command testCommand";
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/InvalidCommandExceptionTest.java b/src/test/java/seedu/exceptions/InvalidCommandExceptionTest.java
new file mode 100644
index 0000000000..abd9213da6
--- /dev/null
+++ b/src/test/java/seedu/exceptions/InvalidCommandExceptionTest.java
@@ -0,0 +1,14 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class InvalidCommandExceptionTest {
+ @Test
+ void createInvalidCommandException_emptyInput_expectCorrectErrorMessage() {
+ InvalidCommandException error = new InvalidCommandException();
+ String expectedErrorMessage = "Please enter a valid command.";
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/InvalidDateExceptionTest.java b/src/test/java/seedu/exceptions/InvalidDateExceptionTest.java
new file mode 100644
index 0000000000..c816841d69
--- /dev/null
+++ b/src/test/java/seedu/exceptions/InvalidDateExceptionTest.java
@@ -0,0 +1,19 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.constants.DateConstants;
+
+public class InvalidDateExceptionTest {
+ @Test
+ void createInvalidDateException_emptyInput_expectCorrectErrorMessage() {
+ String dateString = "testDate";
+ InvalidDateException error = new InvalidDateException(dateString);
+ String expectedErrorMessage = "Oops! " + dateString + " is not a valid date!" +
+ " Please format the date as: " + DateConstants.PARSE_FORMAT + "." +
+ "\n" + "Also check whether the date you've entered exists!";
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/InvalidIndexExceptionTest.java b/src/test/java/seedu/exceptions/InvalidIndexExceptionTest.java
new file mode 100644
index 0000000000..df56133661
--- /dev/null
+++ b/src/test/java/seedu/exceptions/InvalidIndexExceptionTest.java
@@ -0,0 +1,15 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class InvalidIndexExceptionTest {
+ @Test
+ void createInvalidIndexException_emptyInput_expectCorrectErrorMessage() {
+ int index = -1;
+ InvalidIndexException error = new InvalidIndexException(index);
+ String expectedErrorMessage = index + " is not a valid index!";
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/InvalidMealExceptionTest.java b/src/test/java/seedu/exceptions/InvalidMealExceptionTest.java
new file mode 100644
index 0000000000..d754df6af0
--- /dev/null
+++ b/src/test/java/seedu/exceptions/InvalidMealExceptionTest.java
@@ -0,0 +1,18 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.definitions.MealTypes;
+
+public class InvalidMealExceptionTest {
+ @Test
+ void createInvalidMealException_emptyInput_expectCorrectErrorMessage() {
+ String input = "testMealType";
+ InvalidMealException error = new InvalidMealException(input);
+ String expectedErrorMessage = System.lineSeparator() + "Invalid meal type: " + input +
+ "! Supported meal types: " + MealTypes.getSupportedMealTypes();
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/LifeTrackerExceptionTest.java b/src/test/java/seedu/exceptions/LifeTrackerExceptionTest.java
new file mode 100644
index 0000000000..6ee179bfa1
--- /dev/null
+++ b/src/test/java/seedu/exceptions/LifeTrackerExceptionTest.java
@@ -0,0 +1,15 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class LifeTrackerExceptionTest {
+ @Test
+ void createLifeTrackerException_emptyInput_expectCorrectErrorMessage() {
+ String errorMessage = "testErrorMessage";
+ LifeTrackerException error = new LifeTrackerException(errorMessage);
+ String expectedErrorMessage = errorMessage;
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/MissingArgumentsExceptionTest.java b/src/test/java/seedu/exceptions/MissingArgumentsExceptionTest.java
new file mode 100644
index 0000000000..401ab26a79
--- /dev/null
+++ b/src/test/java/seedu/exceptions/MissingArgumentsExceptionTest.java
@@ -0,0 +1,16 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class MissingArgumentsExceptionTest {
+ @Test
+ void createMissingArgumentsException_emptyInput_expectCorrectErrorMessage() {
+ String argument = "/testArgument";
+ String commandWord = "testCommand";
+ MissingArgumentsException error = new MissingArgumentsException(commandWord, argument);
+ String expectedErrorMessage = "Oops! Missing argument " + argument + " for command " + commandWord;
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/exceptions/UnableToSaveDatabaseExceptionTest.java b/src/test/java/seedu/exceptions/UnableToSaveDatabaseExceptionTest.java
new file mode 100644
index 0000000000..a9d53763b1
--- /dev/null
+++ b/src/test/java/seedu/exceptions/UnableToSaveDatabaseExceptionTest.java
@@ -0,0 +1,15 @@
+package seedu.exceptions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class UnableToSaveDatabaseExceptionTest {
+ @Test
+ void createUnableToSaveDatabaseException_emptyInput_expectCorrectErrorMessage() {
+ String databaseName = "testDatabase";
+ UnableToSaveDatabaseException error = new UnableToSaveDatabaseException(databaseName);
+ String expectedErrorMessage = "Unable to save " + databaseName;
+ assertEquals(expectedErrorMessage, error.getMessage());
+ }
+}
diff --git a/src/test/java/seedu/storage/ExerciseStorageTest.java b/src/test/java/seedu/storage/ExerciseStorageTest.java
new file mode 100644
index 0000000000..1347a51d0e
--- /dev/null
+++ b/src/test/java/seedu/storage/ExerciseStorageTest.java
@@ -0,0 +1,30 @@
+package seedu.storage;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.constants.DateConstants;
+import seedu.entities.Exercise;
+
+public class ExerciseStorageTest {
+ private final ExerciseStorage exerciseStorage = new ExerciseStorage("./data/exerciseData.csv");
+ private final DateTimeFormatter dtf = DateConstants.DATABASE_DTF;
+
+ @Test
+ void addExercise_singleExerciseAdded_expectSizeIncrease() {
+ exerciseStorage.resetStorage();
+ int oldSize = exerciseStorage.getExercises().size();
+ LocalDate date = LocalDate.parse("1/1/2023", dtf);
+ assertDoesNotThrow(() -> {
+ exerciseStorage.saveExercise(
+ new Exercise("Running", "5km", 400, date));
+ });
+ int newSize = exerciseStorage.getExercises().size();
+ assertEquals(oldSize + 1, newSize);
+ }
+}
diff --git a/src/test/java/seedu/storage/FoodStorageTest.java b/src/test/java/seedu/storage/FoodStorageTest.java
new file mode 100644
index 0000000000..dc20a76af4
--- /dev/null
+++ b/src/test/java/seedu/storage/FoodStorageTest.java
@@ -0,0 +1,34 @@
+package seedu.storage;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import java.util.List;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import seedu.entities.Food;
+
+public class FoodStorageTest {
+ @Nested
+ @DisplayName("Test Read Functionalities")
+ class ReadTest {
+ private final FoodStorage foodStorage = new FoodStorage();
+
+ @Test
+ public void getFoodListSize_emptyInput_expectSizeGreaterThanZero() {
+ assertFalse(foodStorage.getFoodsCount() == 0, "Food Storage is not empty :)");
+ }
+
+ @Test
+ public void getFood_emptyInput_expectNoException() {
+ assertDoesNotThrow(() -> foodStorage.getFoodById(0));
+ }
+
+ @Test
+ public void searchFood_stringInput_expectReturnedSizeGreaterThanZero() {
+ List foods = assertDoesNotThrow(() -> foodStorage.getFoodsByName("chicken"));
+ assertFalse(foods.size() == 0, "Filter returned values :)");
+ }
+ }
+}
diff --git a/src/test/java/seedu/storage/MealStorageTest.java b/src/test/java/seedu/storage/MealStorageTest.java
new file mode 100644
index 0000000000..7453237f0d
--- /dev/null
+++ b/src/test/java/seedu/storage/MealStorageTest.java
@@ -0,0 +1,52 @@
+package seedu.storage;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import seedu.constants.DateConstants;
+import seedu.definitions.MealTypes;
+import seedu.entities.Food;
+import seedu.entities.Meal;
+
+public class MealStorageTest {
+ private static final String FILE_PATH = "./data/mealData.csv";
+ private final FoodStorage foodStorage = new FoodStorage();
+
+ @Nested
+ @DisplayName("Test Read Write Functionalities")
+ class ReadWriteTest {
+ private final MealStorage mealStorage = new MealStorage(FILE_PATH, foodStorage);
+ private final DateTimeFormatter dtf = DateConstants.DATABASE_DTF;
+ private ArrayList foodList = new ArrayList();
+
+ @Test
+ public void addMeal_singleMealAdded_expectNoException() {
+ assertFalse(foodStorage.getFoodsCount() == 0, "Food Storage is not empty :)");
+ foodList.add(foodStorage.getFoodById(0));
+ foodList.add(foodStorage.getFoodById(1));
+ foodList.add(foodStorage.getFoodById(2));
+ LocalDate date = LocalDate.parse("1/1/2023", dtf);
+ assertDoesNotThrow(() -> mealStorage.saveMeal(new Meal(foodList, date, MealTypes.BREAKFAST)));
+ }
+
+ @Test
+ public void retrieveMeal_singleMealAlreadyAdded_expectNoException() {
+ addMeal_singleMealAdded_expectNoException();
+ assertDoesNotThrow(() -> mealStorage.getMealById(0));
+ }
+
+ @Test
+ public void deleteMeal_singleMealAlreadyAdded_expectNoException() {
+ addMeal_singleMealAdded_expectNoException();
+ assertDoesNotThrow(() -> mealStorage.deleteMeal(0));
+ }
+ }
+}
diff --git a/src/test/java/seedu/storage/UserStorageTest.java b/src/test/java/seedu/storage/UserStorageTest.java
new file mode 100644
index 0000000000..674e6b967c
--- /dev/null
+++ b/src/test/java/seedu/storage/UserStorageTest.java
@@ -0,0 +1,51 @@
+package seedu.storage;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import seedu.entities.User;
+
+public class UserStorageTest {
+ private static final String FILE_PATH = "./data/userData.csv";
+
+ @Nested
+ @DisplayName("Test User Storage Functionalities")
+ class ReadWriteTest {
+ private final UserStorage userStorage = new UserStorage(FILE_PATH);
+
+ @Test
+ @DisplayName("Test retrieve user")
+ public User retrieveUser_emptyInput_expectNoException() {
+ User user = assertDoesNotThrow(() -> userStorage.getUser());
+ return user;
+ }
+
+ @Test
+ @DisplayName("Test Update User")
+ public void updateUser_newUserDetails_expectUserHasNewUserDetails() {
+ String name = "test";
+ float weight = (float) 65.0;
+ float height = (float) 175.0;
+ int age = 21;
+ String gender = "male";
+ float targetWeight = (float) 50.0;
+
+ User newUser = new User(name, weight, height, age, gender, targetWeight);
+
+ assertDoesNotThrow(() -> userStorage.updateUser(newUser));
+ User retrievedUser = retrieveUser_emptyInput_expectNoException();
+
+ assertEquals(name, retrievedUser.getName());
+ assertEquals(weight, retrievedUser.getWeight());
+ assertEquals(height, retrievedUser.getHeight());
+ assertEquals(age, retrievedUser.getAge());
+ assertEquals(gender, retrievedUser.getGender());
+ assertEquals(targetWeight, retrievedUser.getTargetWeight());
+ }
+ }
+
+}
diff --git a/src/test/java/seedu/ui/WeightUiTest.java b/src/test/java/seedu/ui/WeightUiTest.java
new file mode 100644
index 0000000000..e72277519f
--- /dev/null
+++ b/src/test/java/seedu/ui/WeightUiTest.java
@@ -0,0 +1,42 @@
+package seedu.ui;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class WeightUiTest {
+
+ private ByteArrayOutputStream output = new ByteArrayOutputStream();
+ private PrintStream initialOutput = System.out;
+ private int weight = 50;
+
+ @BeforeEach
+ public void getStream() {
+ System.setOut(new PrintStream(output));
+ }
+
+ @AfterEach
+ public void resetStreams() {
+ System.setOut(initialOutput);
+ }
+
+ @Test
+ void requestWeight() {
+ GeneralUi ui = new WeightUi();
+ ui.requestWeight();
+ assertEquals("Please enter your weight (in kg):", output.toString().trim());
+ }
+
+ @Test
+ void showLatestWeight_input50_expect50() {
+ GeneralUi ui = new WeightUi();
+ ui.showLatestWeight(weight);
+ assertEquals("This is the latest weight you have entered in: 50kg", output.toString().trim());
+ }
+}
+
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 892cb6cae7..a09da15ee6 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,9 +1,22 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
+Initialised Meal Storage
+Initialised User Storage
+Initialised Exercise Storage
+------------------------------------------------------------
+Hello! Welcome to
+ _ _ __ _______ _
+| | (_)/ _||__ __| | |
+| | _| |_ ___| |_ __ __ _ ___| | _____ _ __
+| | | | _/ _ \ | '__/ _` |/ __| |/ / _ \ '__|
+| |____| | || __/ | | | (_| | (__| < __/ |
+|______|_|_| \___|_|_| \__,_|\___|_|\_\___|_|
-What is your name?
-Hello James Gosling
+------------------------------------------------------------
+Hello! I am LifeTracker, a program to aid you in keeping fit!
+
+Please enter command 'help' if you require assistance.
+------------------------------------------------------------
+
+------------------------------------------------------------
+Bye! Hope to see you again soon!
+------------------------------------------------------------
+------------------------------------------------------------
diff --git a/text-ui-test/data/exerciseData.csv b/text-ui-test/data/exerciseData.csv
new file mode 100644
index 0000000000..edbe9c42d3
--- /dev/null
+++ b/text-ui-test/data/exerciseData.csv
@@ -0,0 +1 @@
+Exercise Name,Exercise Description,Calories Burnt
diff --git a/text-ui-test/data/mealData.csv b/text-ui-test/data/mealData.csv
new file mode 100644
index 0000000000..12dcb8be13
--- /dev/null
+++ b/text-ui-test/data/mealData.csv
@@ -0,0 +1 @@
+Date,Foods,Meal Type
diff --git a/text-ui-test/data/userData.csv b/text-ui-test/data/userData.csv
new file mode 100644
index 0000000000..8a25d4e86a
--- /dev/null
+++ b/text-ui-test/data/userData.csv
@@ -0,0 +1,2 @@
+Name,Weight,Height,Age,Gender,TargetWeight
+,0.0,0.0,0,,0.0
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index f6ec2e9f95..b023018cab 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -1 +1 @@
-James Gosling
\ No newline at end of file
+bye
diff --git a/text-ui-test/myLogFile.log b/text-ui-test/myLogFile.log
new file mode 100644
index 0000000000..0f9a37c9f5
--- /dev/null
+++ b/text-ui-test/myLogFile.log
@@ -0,0 +1,4 @@
+Apr 10, 2023 2:09:22 PM seedu.logger.LogFileHandler logWarning
+WARNING: Gender not provided, cannot calculate caloric needs accurately
+Apr 10, 2023 2:09:23 PM seedu.logger.LogFileHandler logInfo
+INFO: User exited the programme.
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
index 1dcbd12021..374c950bb5 100755
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -8,7 +8,7 @@ cd ..
cd text-ui-test
-java -jar $(find ../build/libs/ -mindepth 1 -print -quit) < input.txt > ACTUAL.TXT
+java -jar $(find ../build/libs/ -mindepth 1 -print -quit) < input.txt > ACTUAL.TXT
cp EXPECTED.TXT EXPECTED-UNIX.TXT
dos2unix EXPECTED-UNIX.TXT ACTUAL.TXT