From f8b87925e7077dbc4b3a34547ece38d86b5113ed Mon Sep 17 00:00:00 2001 From: edwardhumi <110726439+edwardhumi@users.noreply.github.com> Date: Wed, 6 Mar 2024 14:35:21 +0800 Subject: [PATCH 001/274] Update README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index bbcc99c1e7..2244f8b22c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Duke +# FitNUS {Give product intro here} From ec961da67021dc93ab95544c6537d85278c1c89c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 6 Mar 2024 15:04:57 +0800 Subject: [PATCH 002/274] Add details to docs/AboutUs.md --- docs/AboutUs.md | 10 +++------- docs/team/claribelho.md | 0 2 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 docs/team/claribelho.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..1aa65e8e34 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,5 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:----:|:----------------------------------------:|:---------: +-- | Claribel Ho | [Github] (https://github.com/claribelho) | [Portfolio] (docs/team/claribelho.md) \ No newline at end of file diff --git a/docs/team/claribelho.md b/docs/team/claribelho.md new file mode 100644 index 0000000000..e69de29bb2 From 58dced88bae408cf5918009053e5cd44e9432466 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 6 Mar 2024 15:05:19 +0800 Subject: [PATCH 003/274] Update AboutUs.md --- docs/AboutUs.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..bc5157b213 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,5 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:---------------:|:---------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](docs/team/edwardhumi.md) \ No newline at end of file From 7385b50c5ab7dfbb92cf00da66be62e736fa0591 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Wed, 6 Mar 2024 15:05:58 +0800 Subject: [PATCH 004/274] Update AboutUs.md --- docs/AboutUs.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..1180158374 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,5 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:--------------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](docs/team/johndoe.md) From d8a221fbb43a7102f269742f340164c86f7c8a31 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 6 Mar 2024 20:16:09 +0800 Subject: [PATCH 005/274] Update AboutUs.md --- docs/AboutUs.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 4dca18e234..0c721bbd34 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,7 +1,8 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:---------------:|:---------------------------------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](docs/team/edwardhumi.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](docs/team/johndoe.md) --- | Claribel Ho | [Github] (https://github.com/claribelho) | [Portfolio] (docs/team/claribelho.md) \ No newline at end of file +Display | Name | Github Profile | Portfolio +--------|:---------------------:|:-------------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](docs/team/edwardhumi.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](docs/team/johndoe.md) +-- | Claribel Ho | [Github] (https://github.com/claribelho) | [Portfolio] (docs/team/claribelho.md) +![](https://via.placeholder.com/100.png?text=Photo) | Bryan Castorius Halim | [Github](https://github.com/BryanCastorius) | [Portfolio](docs/team/bryancastorius.md) \ No newline at end of file From 8205c086634df19ebd86485b6c193120fdca3bc7 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 13 Mar 2024 14:12:21 +0800 Subject: [PATCH 006/274] Update Checkstyle --- config/checkstyle/checkstyle.xml | 153 ++++++++++++++++++++++++++++- config/checkstyle/suppressions.xml | 6 +- 2 files changed, 153 insertions(+), 6 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index c35db7c7e6..acac1a8e28 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -5,7 +5,7 @@ @@ -48,6 +48,21 @@ IMPORT CHECKS --> + + + + + + + + + + + + + + @@ -200,6 +221,13 @@ + + + + + + + @@ -237,13 +265,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -271,7 +408,7 @@ - + @@ -283,5 +420,15 @@ + + + + + + + + + + - + \ No newline at end of file diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 39efb6e4ac..39102a4119 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -1,10 +1,10 @@ + "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" + "https://checkstyle.org/dtds/suppressions_1_2.dtd"> - + \ No newline at end of file From f3552abec1adfb622d3df93996c6913b6b62f51d Mon Sep 17 00:00:00 2001 From: tinaliu27 <27tinaliu@gmail.com> Date: Sat, 16 Mar 2024 12:58:09 +0800 Subject: [PATCH 007/274] added database for us to use --- FitNus_db - Meal.csv | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 FitNus_db - Meal.csv diff --git a/FitNus_db - Meal.csv b/FitNus_db - Meal.csv new file mode 100644 index 0000000000..2bed965bdf --- /dev/null +++ b/FitNus_db - Meal.csv @@ -0,0 +1,22 @@ +Meal Name,Calories,Carbs,Proteins,Fats,Fiber +Chicken Rice (382g),607,75,25,23,2 +Char Kway Teow (384g),744,76,23,29.2,7.3 +Laksa,377,71,18,2,4 +Hokkien Prawn Mee,522,69,18,19,4.4 +Kaya Toast ,459,44.4,8,27.2,1.3 +Mee Goreng (309g),500,61,18,20,4.4 +Char Siew Rice (327g),605,91,24,16,5.9 +Nasi lemak (210g),494,80,13,14,6.5 +roti prata ,209,32,5,7,1.7 +Pork Satay with Satay Sauce ,36,0.36,4.99,1.52,0 +Nasi Goreng (1 cup),346,44.95,12.93,12.25,1.4 +Wanton Mee (400g),555,96.79,15.1,14.13,13.8 +Mala ,583,72.35,12.22,30.85,7 +Oyster Omlette ,467,40.07,19.03,24.33,0.6 +Pepper lunch ,500,50,40,11,4.6 +Ban Mian (528g),475,48,22,22,3.2 +Soup Kambeng,203.8,5.6,28.8,6.8,1.1 +Durian (100g),147,27.09,1.47,5.33,3.8 +Ice KaChang (504g),257,58,6,1,2 +Tau Huay (282g),153,32.2,14.1,1.5,1 +Chendol (368g),386,59,6,15,2 \ No newline at end of file From be6471098127e4e76c17002f0e8253f58116f473 Mon Sep 17 00:00:00 2001 From: tinaliu27 <27tinaliu@gmail.com> Date: Sun, 17 Mar 2024 15:30:29 +0800 Subject: [PATCH 008/274] added csvreader methods --- db/Drink_db.csv | 20 +++++++++++++++ FitNus_db - Meal.csv => db/Meal_db.csv | 0 src/main/java/seedu/duke/CSVReader.java | 33 +++++++++++++++++++++++++ src/main/java/seedu/duke/FitNus.java | 7 ++++++ src/main/java/seedu/duke/Meal.java | 7 ++++++ src/main/java/seedu/duke/Water.java | 7 ++++++ 6 files changed, 74 insertions(+) create mode 100644 db/Drink_db.csv rename FitNus_db - Meal.csv => db/Meal_db.csv (100%) create mode 100644 src/main/java/seedu/duke/CSVReader.java create mode 100644 src/main/java/seedu/duke/FitNus.java create mode 100644 src/main/java/seedu/duke/Meal.java create mode 100644 src/main/java/seedu/duke/Water.java diff --git a/db/Drink_db.csv b/db/Drink_db.csv new file mode 100644 index 0000000000..ffc5d5e231 --- /dev/null +++ b/db/Drink_db.csv @@ -0,0 +1,20 @@ +Drink Name,Calories,Carbs,Protein,Fat +Teh C Bing,231,24,15,1 +Teh,151,29,4,0.8 +Kopi,141,26.7,2.3,2.8 +Milo,124,20,3.4,3.4 +Milo Dinosaur,270,42,7,8 +Sugarcane juice ,192,52.2,0,0 +Bandung,153,32,1.1,2 +Teh Tarik,124,21.22,2.98,3.28 +100 plus,72,18,0,0 +Tiger Beer (100ml),42,3.4,0.4,0 +Kopi O,67,14.9,0.5,0 +Kopi C,117,20,1,3.6 +Iced Lemon Tea,95,20.9,1,0.1 +Honey Lemon Tea,134,36,0.2,0 +Soursop Juice ,117,25,2.8,1.4 +Kalamansi Juice,168,42,0,0 +Chrysanthemun Juice ,12.2,1.54,1.71,0.3 +Guava Juice ,143,38,0,0 +Plum Juice ,57,13.3,0.5,0 \ No newline at end of file diff --git a/FitNus_db - Meal.csv b/db/Meal_db.csv similarity index 100% rename from FitNus_db - Meal.csv rename to db/Meal_db.csv diff --git a/src/main/java/seedu/duke/CSVReader.java b/src/main/java/seedu/duke/CSVReader.java new file mode 100644 index 0000000000..a7227ea1d7 --- /dev/null +++ b/src/main/java/seedu/duke/CSVReader.java @@ -0,0 +1,33 @@ +package seedu.duke; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +public class CSVReader { + public static final String delimiter = ","; + public static void main(String[] args){ + String csvFile = "./db/Meal_db.csv"; + CSVReader.read(csvFile); + } + public static void read(String filename) { + try{ + File file = new File(filename); + FileReader fr = new FileReader(file); + BufferedReader br = new BufferedReader(fr); + + String line = ""; + String[] tempArr; + while ((line = br.readLine()) != null) { + tempArr = line.split(delimiter); + for (String tempStr : tempArr) { + System.out.print(tempStr + " "); + } + System.out.println(); + } + br.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } +} diff --git a/src/main/java/seedu/duke/FitNus.java b/src/main/java/seedu/duke/FitNus.java new file mode 100644 index 0000000000..1288bc382a --- /dev/null +++ b/src/main/java/seedu/duke/FitNus.java @@ -0,0 +1,7 @@ +package seedu.duke; + +import java.io.File; +import java.util.Scanner; + +public class FitNus { +} \ No newline at end of file diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java new file mode 100644 index 0000000000..9927f99520 --- /dev/null +++ b/src/main/java/seedu/duke/Meal.java @@ -0,0 +1,7 @@ +package seedu.duke; + +import java.util.Scanner; + +public class Meal { + +} \ No newline at end of file diff --git a/src/main/java/seedu/duke/Water.java b/src/main/java/seedu/duke/Water.java new file mode 100644 index 0000000000..08dd41d0c2 --- /dev/null +++ b/src/main/java/seedu/duke/Water.java @@ -0,0 +1,7 @@ +package seedu.duke; + +import java.util.Scanner; + +public class Water { + +} \ No newline at end of file From d74b8d030c98dd6928f0be2ce97b4f45bb34abf9 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 17 Mar 2024 16:13:50 +0800 Subject: [PATCH 009/274] Add Parser class Created parser for meal, drink, and water --- src/main/java/seedu/duke/Parser.java | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/seedu/duke/Parser.java diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java new file mode 100644 index 0000000000..837ad24d6c --- /dev/null +++ b/src/main/java/seedu/duke/Parser.java @@ -0,0 +1,28 @@ +package seedu.duke; + +public class Parser { + public static String mealDescription; + public static int mealSize; + public static String drinkDescription; + public static int drinkSize; + public static int waterSize; + + public void parseMeal(String command) { + int descriptionIndex = command.indexOf("m/") + 2; + int sizeIndex = command.indexOf("s/") + 2; + mealDescription = command.substring(descriptionIndex, sizeIndex - 2); + mealSize = Integer.parseInt(command.substring(sizeIndex)); + } + + public void parseDrink(String command) { + int descriptionIndex = command.indexOf("d/") + 2; + int sizeIndex = command.indexOf("s/") + 2; + drinkDescription = command.substring(descriptionIndex, sizeIndex - 2).trim(); + drinkSize = Integer.parseInt(command.substring(sizeIndex).trim()); + } + + public void parseWater(String command) { + int sizeIndex = command.indexOf("s/") + 2; + waterSize = Integer.parseInt(command.substring(sizeIndex).trim()); + } +} From 936174e5653bd6a923bdc1372965efd7e7e16e7e Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 17 Mar 2024 16:31:32 +0800 Subject: [PATCH 010/274] Add Parser for Info and Edit --- src/main/java/seedu/duke/Parser.java | 36 +++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 837ad24d6c..a0d780a988 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -6,12 +6,17 @@ public class Parser { public static String drinkDescription; public static int drinkSize; public static int waterSize; + public static int editMealIndex; + public static int editMealSize; + public static int editDrinkIndex; + public static int editDrinkSize; + public static int editWaterSize; public void parseMeal(String command) { int descriptionIndex = command.indexOf("m/") + 2; int sizeIndex = command.indexOf("s/") + 2; mealDescription = command.substring(descriptionIndex, sizeIndex - 2); - mealSize = Integer.parseInt(command.substring(sizeIndex)); + mealSize = Integer.parseInt(command.substring(sizeIndex).trim()); } public void parseDrink(String command) { @@ -25,4 +30,33 @@ public void parseWater(String command) { int sizeIndex = command.indexOf("s/") + 2; waterSize = Integer.parseInt(command.substring(sizeIndex).trim()); } + + public String parseInfoMeal(String command) { + int mealIndex = 9; + return command.substring(mealIndex).trim(); + } + + public String parseInfoDrink(String command) { + int drinkIndex = 10; + return command.substring(drinkIndex).trim(); + } + + public void parseEditMeal(String command) { + int mealSizePosition = command.indexOf("s/"); + int mealIndexPosition = 20; + editMealIndex = Integer.parseInt(command.substring(mealIndexPosition, mealSizePosition).trim()); + editMealSize = Integer.parseInt(command.substring(mealSizePosition + 2).trim()); + } + + public void parseEditDrink(String command) { + int drinkSizePosition = command.indexOf("s/"); + int drinkIndexPosition = 21; + editDrinkIndex = Integer.parseInt(command.substring(drinkSizePosition, drinkIndexPosition).trim()); + editDrinkSize = Integer.parseInt(command.substring(drinkIndexPosition + 2).trim()); + } + + public void parseEditWater(String command) { + int waterSizePosition = command.indexOf("s/") + 2; + editWaterSize = Integer.parseInt(command.substring(waterSizePosition).trim()); + } } From 2e5dcd9765982d4b9446ea16e4814254b9aab90b Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 17 Mar 2024 16:55:35 +0800 Subject: [PATCH 011/274] Revert Checkstyle --- config/checkstyle/checkstyle.xml | 151 +-------------------------- src/main/java/seedu/duke/Parser.java | 22 ++-- 2 files changed, 13 insertions(+), 160 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index acac1a8e28..8cc92d43b5 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -5,7 +5,7 @@ @@ -48,21 +48,6 @@ IMPORT CHECKS --> - - - - - - - - - - - - - - @@ -221,13 +200,6 @@ - - - - - - - @@ -265,122 +237,13 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -408,7 +271,7 @@ - + @@ -420,15 +283,5 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index a0d780a988..2d1c210fd5 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -12,50 +12,50 @@ public class Parser { public static int editDrinkSize; public static int editWaterSize; - public void parseMeal(String command) { + public static void parseMeal(String command) { int descriptionIndex = command.indexOf("m/") + 2; int sizeIndex = command.indexOf("s/") + 2; - mealDescription = command.substring(descriptionIndex, sizeIndex - 2); + mealDescription = command.substring(descriptionIndex, sizeIndex - 2).trim(); mealSize = Integer.parseInt(command.substring(sizeIndex).trim()); } - public void parseDrink(String command) { + public static void parseDrink(String command) { int descriptionIndex = command.indexOf("d/") + 2; int sizeIndex = command.indexOf("s/") + 2; drinkDescription = command.substring(descriptionIndex, sizeIndex - 2).trim(); drinkSize = Integer.parseInt(command.substring(sizeIndex).trim()); } - public void parseWater(String command) { + public static void parseWater(String command) { int sizeIndex = command.indexOf("s/") + 2; waterSize = Integer.parseInt(command.substring(sizeIndex).trim()); } - public String parseInfoMeal(String command) { + public static String parseInfoMeal(String command) { int mealIndex = 9; return command.substring(mealIndex).trim(); } - public String parseInfoDrink(String command) { + public static String parseInfoDrink(String command) { int drinkIndex = 10; return command.substring(drinkIndex).trim(); } - public void parseEditMeal(String command) { + public static void parseEditMeal(String command) { int mealSizePosition = command.indexOf("s/"); int mealIndexPosition = 20; editMealIndex = Integer.parseInt(command.substring(mealIndexPosition, mealSizePosition).trim()); editMealSize = Integer.parseInt(command.substring(mealSizePosition + 2).trim()); } - public void parseEditDrink(String command) { + public static void parseEditDrink(String command) { int drinkSizePosition = command.indexOf("s/"); int drinkIndexPosition = 21; - editDrinkIndex = Integer.parseInt(command.substring(drinkSizePosition, drinkIndexPosition).trim()); - editDrinkSize = Integer.parseInt(command.substring(drinkIndexPosition + 2).trim()); + editDrinkIndex = Integer.parseInt(command.substring(drinkIndexPosition, drinkSizePosition).trim()); + editDrinkSize = Integer.parseInt(command.substring(drinkSizePosition + 2).trim()); } - public void parseEditWater(String command) { + public static void parseEditWater(String command) { int waterSizePosition = command.indexOf("s/") + 2; editWaterSize = Integer.parseInt(command.substring(waterSizePosition).trim()); } From 4fa31d289ae9ea4ea59ae4854143956c6ea58dce Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 17 Mar 2024 17:04:28 +0800 Subject: [PATCH 012/274] Fix build errors Add new lines to each file and remove unused imports --- src/main/java/seedu/duke/FitNus.java | 5 +---- src/main/java/seedu/duke/Meal.java | 4 +--- src/main/java/seedu/duke/Water.java | 4 +--- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/duke/FitNus.java b/src/main/java/seedu/duke/FitNus.java index 1288bc382a..6182fffa62 100644 --- a/src/main/java/seedu/duke/FitNus.java +++ b/src/main/java/seedu/duke/FitNus.java @@ -1,7 +1,4 @@ package seedu.duke; -import java.io.File; -import java.util.Scanner; - public class FitNus { -} \ No newline at end of file +} diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index 9927f99520..2cfa9236ae 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -1,7 +1,5 @@ package seedu.duke; -import java.util.Scanner; - public class Meal { -} \ No newline at end of file +} diff --git a/src/main/java/seedu/duke/Water.java b/src/main/java/seedu/duke/Water.java index 08dd41d0c2..cd24cc795e 100644 --- a/src/main/java/seedu/duke/Water.java +++ b/src/main/java/seedu/duke/Water.java @@ -1,7 +1,5 @@ package seedu.duke; -import java.util.Scanner; - public class Water { -} \ No newline at end of file +} From f37a8bab0d4fbfe8c8eae630de63d073f86409bc Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Sun, 17 Mar 2024 22:23:12 +0800 Subject: [PATCH 013/274] Add Meal Class --- src/main/java/seedu/duke/Meal.java | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index 2cfa9236ae..78b64054aa 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -1,5 +1,57 @@ package seedu.duke; public class Meal { + private String name; + private int caloriesPerServing; + private int carbsPerServing; + private int proteinPerServing; + private int fatPerServing; + private int fiberPerServing; + private int sugarPerServing; + private int servingSize; + + // Constructor + public Meal(String name, int servingSize, int caloriesPerServing, int carbs, int protein, int fat, int fiber, int sugar) { + this.name = name; + this.caloriesPerServing = caloriesPerServing; + this.carbsPerServing = carbs; + this.proteinPerServing = protein; + this.fatPerServing = fat; + this.fiberPerServing = fiber; + this.sugarPerServing = sugar; + } + + // Getter methods + public String getName() { + return name; + } + + public int getServingSize() { + return servingSize; + } + + public int getCalories() { + return caloriesPerServing * servingSize; + } + + public int getCarbs() { + return carbsPerServing * servingSize; + } + + public int getProtein() { + return proteinPerServing * servingSize; + } + + public int getFat() { + return fatPerServing * servingSize; + } + + public int getFiber() { + return fiberPerServing * servingSize; + } + + public int getSugar() { + return sugarPerServing * servingSize; + } } From 2a41ac5cab6e60d477a9884db0991c183ed32656 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Sun, 17 Mar 2024 22:35:03 +0800 Subject: [PATCH 014/274] Update Meal Class --- src/main/java/seedu/duke/Meal.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index 78b64054aa..3b1397388e 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -13,6 +13,7 @@ public class Meal { // Constructor public Meal(String name, int servingSize, int caloriesPerServing, int carbs, int protein, int fat, int fiber, int sugar) { this.name = name; + this.servingSize = servingSize; this.caloriesPerServing = caloriesPerServing; this.carbsPerServing = carbs; this.proteinPerServing = protein; @@ -22,6 +23,17 @@ public Meal(String name, int servingSize, int caloriesPerServing, int carbs, int } // Getter methods + public void infoMeal() { + System.out.println("Meal: " + name); + System.out.println("Serving Size: " + servingSize); + System.out.println("Calories: " + getCalories()); + System.out.println("Carbs: " + getCarbs()); + System.out.println("Protein: " + getProtein()); + System.out.println("Fat: " + getFat()); + System.out.println("Fiber: " + getFiber()); + System.out.println("Sugar: " + getSugar()); + } + public String getName() { return name; } From 03c13a354ad2f9b3926cbb29502cf204957e3a3e Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 18 Mar 2024 00:23:09 +0800 Subject: [PATCH 015/274] Add Drink and Water Class --- src/main/java/seedu/duke/Drink.java | 67 +++++++++++++++++++++++++++++ src/main/java/seedu/duke/Water.java | 13 ++++++ 2 files changed, 80 insertions(+) create mode 100644 src/main/java/seedu/duke/Drink.java diff --git a/src/main/java/seedu/duke/Drink.java b/src/main/java/seedu/duke/Drink.java new file mode 100644 index 0000000000..50422a9369 --- /dev/null +++ b/src/main/java/seedu/duke/Drink.java @@ -0,0 +1,67 @@ +package seedu.duke; + +public class Drink { + private String name; + private int drinkVolume; + private int caloriesPerMilliliter; + private int carbsPerMilliliter; + private int sugarPerMilliliter; + private int proteinPerMilliliter; + private int fatPerMilliliter; + private int sodiumPerMilliliter; + + public Drink(String name, int volume, int calories, int carbs, int protein, int fat, int sugar, int sodium) { + this.name = name; + this.drinkVolume = volume; + this.caloriesPerMilliliter = calories; + this.carbsPerMilliliter = carbs; + this.proteinPerMilliliter = protein; + this.fatPerMilliliter = fat; + this.sugarPerMilliliter = sugar; + this.sodiumPerMilliliter = sodium; + } + + public void infoDrink() { + System.out.println("Drink: " + name); + System.out.println("Volume: " + drinkVolume); + System.out.println("Calories: " + getCalories()); + System.out.println("Carbs: " + getCarbs()); + // Sugar is part of Carbohydrates + System.out.println(" Sugar: " + getSugar()); + System.out.println("Protein: " + getProtein()); + System.out.println("Fat: " + getFat()); + System.out.println("Sodium: " + getSodium()); + } + + public String getName() { + return name; + } + + public int getDrinkVolumeSize() { + return drinkVolume; + } + + public int getCalories() { + return caloriesPerMilliliter * drinkVolume; + } + + public int getCarbs() { + return carbsPerMilliliter * drinkVolume; + } + + public int getSugar() { + return sugarPerMilliliter * drinkVolume; + } + + public int getProtein() { + return proteinPerMilliliter * drinkVolume; + } + + public int getFat() { + return fatPerMilliliter* drinkVolume; + } + + public int getSodium() { + return sodiumPerMilliliter * drinkVolume; + } +} diff --git a/src/main/java/seedu/duke/Water.java b/src/main/java/seedu/duke/Water.java index cd24cc795e..e4ccfc3e52 100644 --- a/src/main/java/seedu/duke/Water.java +++ b/src/main/java/seedu/duke/Water.java @@ -1,5 +1,18 @@ package seedu.duke; public class Water { + private int waterIntake = 0; + + public Water(int waterIntake) { + this.waterIntake += waterIntake; + } + + public void viewWater() { + System.out.println("Total water intake: " + waterIntake + " ml"); + } + + public int getWater() { + return waterIntake; + } } From 031e13895ce947e299171d51c05a26b55b96df05 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 18 Mar 2024 00:36:37 +0800 Subject: [PATCH 016/274] Add Hashmap for meals --- src/main/java/seedu/duke/Meal.java | 81 +++++++++++++++++------------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index 3b1397388e..ce2e505427 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -1,69 +1,82 @@ package seedu.duke; +import java.util.HashMap; + public class Meal { private String name; - private int caloriesPerServing; - private int carbsPerServing; - private int proteinPerServing; - private int fatPerServing; - private int fiberPerServing; - private int sugarPerServing; private int servingSize; + private int calories; + private int carbs; + private int protein; + private int fat; + private int fiber; + private int sugar; + private static HashMap nutrientDetails = new HashMap<>(); - // Constructor - public Meal(String name, int servingSize, int caloriesPerServing, int carbs, int protein, int fat, int fiber, int sugar) { + // Constructor with only serving size and meal name + public Meal(String name, int servingSize) { this.name = name; this.servingSize = servingSize; - this.caloriesPerServing = caloriesPerServing; - this.carbsPerServing = carbs; - this.proteinPerServing = protein; - this.fatPerServing = fat; - this.fiberPerServing = fiber; - this.sugarPerServing = sugar; + setNutrientValues(name); // Assign nutrient values based on the name } - // Getter methods - public void infoMeal() { - System.out.println("Meal: " + name); - System.out.println("Serving Size: " + servingSize); - System.out.println("Calories: " + getCalories()); - System.out.println("Carbs: " + getCarbs()); - System.out.println("Protein: " + getProtein()); - System.out.println("Fat: " + getFat()); - System.out.println("Fiber: " + getFiber()); - System.out.println("Sugar: " + getSugar()); + // Add nutrient details to the static HashMap + static { + nutrientDetails.put("chicken rice", new int[]{400, 50, 30, 20, 10, 5}); + nutrientDetails.put("fried rice", new int[]{500, 60, 25, 15, 20, 3}); + nutrientDetails.put("pizza", new int[]{600, 70, 20, 25, 30, 2}); } - public String getName() { - return name; + // Method to set nutrient values based on meal name + private void setNutrientValues(String name) { + int[] nutrients = nutrientDetails.get(name); + calories = nutrients[0]; + carbs = nutrients[1]; + protein = nutrients[2]; + fat = nutrients[3]; + fiber = nutrients[4]; + sugar = nutrients[5]; } - public int getServingSize() { - return servingSize; + // Getter methods + public String getName() { + return name; } public int getCalories() { - return caloriesPerServing * servingSize; + return calories * servingSize; } public int getCarbs() { - return carbsPerServing * servingSize; + return carbs * servingSize; } public int getProtein() { - return proteinPerServing * servingSize; + return protein * servingSize; } public int getFat() { - return fatPerServing * servingSize; + return fat * servingSize; } public int getFiber() { - return fiberPerServing * servingSize; + return fiber * servingSize; } public int getSugar() { - return sugarPerServing * servingSize; + return sugar * servingSize; + } + + // Method to print all meal info + public void infoMeal() { + System.out.println("Meal: " + name); + System.out.println("Serving Size: " + servingSize); + System.out.println("Calories: " + getCalories()); + System.out.println("Carbs: " + getCarbs()); + System.out.println("Protein: " + getProtein()); + System.out.println("Fat: " + getFat()); + System.out.println("Fiber: " + getFiber()); + System.out.println("Sugar: " + getSugar()); } } From 6fcbc6cff118ee2a4a798c5195d148d3e14f28b2 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 18 Mar 2024 12:48:48 +0800 Subject: [PATCH 017/274] Add Command Handler --- src/main/java/seedu/duke/CSVReader.java | 4 +- src/main/java/seedu/duke/Parser.java | 71 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/CSVReader.java b/src/main/java/seedu/duke/CSVReader.java index a7227ea1d7..c507dae88f 100644 --- a/src/main/java/seedu/duke/CSVReader.java +++ b/src/main/java/seedu/duke/CSVReader.java @@ -5,7 +5,7 @@ import java.io.IOException; public class CSVReader { - public static final String delimiter = ","; + public static final String DELIMITER = ","; public static void main(String[] args){ String csvFile = "./db/Meal_db.csv"; CSVReader.read(csvFile); @@ -19,7 +19,7 @@ public static void read(String filename) { String line = ""; String[] tempArr; while ((line = br.readLine()) != null) { - tempArr = line.split(delimiter); + tempArr = line.split(DELIMITER); for (String tempStr : tempArr) { System.out.print(tempStr + " "); } diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 2d1c210fd5..0ce0e6ebcb 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -12,6 +12,77 @@ public class Parser { public static int editDrinkSize; public static int editWaterSize; + public static void handleCommand(String command) { + if (command.equals("help")) { + handleHelp(); + } else if (command.startsWith("ate")) { + //handleMeal(command); + } else if (command.startsWith("drink")) { + //handleDrink(command); + } else if (command.startsWith("infoMeal")) { + //handleInfoMeal(command); + } else if (command.startsWith("infoDrink")) { + //handleInfoDrink(command); + } else if (command.equals("viewCalories")) { + //handleViewCalories(); + } else if (command.equals("viewCarbohydrates")) { + //handleViewCarbohydrates(); + } else if (command.equals("viewProteins")) { + //handleViewProteins(); + } else if (command.equals("viewWater")) { + //handleViewWater(); + } else if (command.equals("viewFiber")) { + //handleViewFiber(); + } else if (command.equals("listMeals")) { + //handleListMeals(); + } else if (command.equals("listDrinks")) { + //handleListDrinks(); + } else if (command.equals("listEverything")) { + //handleListEverything(); + } else if (command.startsWith("editMealServingSize")) { + //handleEditMealServingSize(command); + } else if (command.startsWith("editDrinkServingSize")) { + //handleEditDrinkServingSize(command); + } else if (command.startsWith("editWaterIntake")) { + //handleEditWaterIntake(command); + } else if (command.startsWith("deleteMeal")) { + //handleDeleteMeal(command); + } else if (command.startsWith("deleteDrink")) { + //handleDeleteDrink(command); + } else if (command.equals("clear")) { + //handleClear(); + } else if (command.equals("exit")) { + //handleExit(); + } else { + System.out.println("Invalid command"); + } + } + + public static void handleHelp() { + System.out.println("Add a meal eaten: ate m/MEAL s/SERVING_SIZE"); + System.out.println("Add a drink: d/DRINK s/SERVING_SIZE"); + System.out.println("Add water: water s/SERVING_SIZE"); + System.out.println("Find the information about a certain meal: infoMeal MEAL"); + System.out.println("Find the information about a certain drink: infoDrink DRINK"); + System.out.println("View daily calories consumed: viewCalories"); + System.out.println("View daily carbohydrates consumed: viewCarbohydrates"); + System.out.println("View daily proteins consumed: viewProteins"); + System.out.println("View daily fat consumed: viewFat"); + System.out.println("View daily sugar consumed: viewSugar"); + System.out.println("View daily water consumption: viewWater"); + System.out.println("View daily fiber consumed: viewFiber"); + System.out.println("List meal intake: listMeals"); + System.out.println("List drink intake: listDrinks"); + System.out.println("List entire food intake for the day: listEverything"); + System.out.println("Edit an existing meal after inserted: editMealServingSize INDEX s/NEW_SERVING_SIZE"); + System.out.println("Edit an existing drink after inserted: editDrinkServingSize INDEX s/NEW_SERVING_SIZE"); + System.out.println("Edit water intake after inserted: editWaterIntake s/TOTAL_WATER_INTAKE"); + System.out.println("Delete certain meal entry: deleteMeal INDEX"); + System.out.println("Delete certain drink entry: deleteDrink INDEX"); + System.out.println("Clear all entries: clear"); + System.out.println("Exit the app: exit "); + } + public static void parseMeal(String command) { int descriptionIndex = command.indexOf("m/") + 2; int sizeIndex = command.indexOf("s/") + 2; From 228f2d71f85de0f84f2285d8e7e4bf68183ce42b Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 18 Mar 2024 19:34:57 +0800 Subject: [PATCH 018/274] Add all handle commands from user --- src/main/java/seedu/duke/Meal.java | 4 +- src/main/java/seedu/duke/Parser.java | 30 ++--- src/main/java/seedu/duke/Water.java | 2 +- src/main/java/seedu/duke/user/User.java | 148 ++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 src/main/java/seedu/duke/user/User.java diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index ce2e505427..cd3b46ad3e 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -3,7 +3,7 @@ import java.util.HashMap; public class Meal { - private String name; + private static String name; private int servingSize; private int calories; private int carbs; @@ -39,7 +39,7 @@ private void setNutrientValues(String name) { } // Getter methods - public String getName() { + public static String getName() { return name; } diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 0ce0e6ebcb..612e0895f8 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -1,5 +1,7 @@ package seedu.duke; +import seedu.duke.user.User; + public class Parser { public static String mealDescription; public static int mealSize; @@ -16,29 +18,29 @@ public static void handleCommand(String command) { if (command.equals("help")) { handleHelp(); } else if (command.startsWith("ate")) { - //handleMeal(command); + User.handleMeal(command); } else if (command.startsWith("drink")) { - //handleDrink(command); + User.handleDrink(command); } else if (command.startsWith("infoMeal")) { //handleInfoMeal(command); } else if (command.startsWith("infoDrink")) { //handleInfoDrink(command); } else if (command.equals("viewCalories")) { - //handleViewCalories(); + User.handleViewCalories(); } else if (command.equals("viewCarbohydrates")) { - //handleViewCarbohydrates(); + User.handleViewCarbohydrates(); } else if (command.equals("viewProteins")) { - //handleViewProteins(); + User.handleViewProteins(); } else if (command.equals("viewWater")) { - //handleViewWater(); + User.handleViewWater(); } else if (command.equals("viewFiber")) { - //handleViewFiber(); + User.handleViewFiber(); } else if (command.equals("listMeals")) { - //handleListMeals(); + User.handleListMeals(); } else if (command.equals("listDrinks")) { - //handleListDrinks(); + User.handleListDrinks(); } else if (command.equals("listEverything")) { - //handleListEverything(); + User.handleListEverything(); } else if (command.startsWith("editMealServingSize")) { //handleEditMealServingSize(command); } else if (command.startsWith("editDrinkServingSize")) { @@ -46,13 +48,13 @@ public static void handleCommand(String command) { } else if (command.startsWith("editWaterIntake")) { //handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { - //handleDeleteMeal(command); + User.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { - //handleDeleteDrink(command); + User.handleDeleteDrink(command); } else if (command.equals("clear")) { - //handleClear(); + User.handleClear(); } else if (command.equals("exit")) { - //handleExit(); + //User.handleExit(); } else { System.out.println("Invalid command"); } diff --git a/src/main/java/seedu/duke/Water.java b/src/main/java/seedu/duke/Water.java index e4ccfc3e52..cd6e925190 100644 --- a/src/main/java/seedu/duke/Water.java +++ b/src/main/java/seedu/duke/Water.java @@ -7,7 +7,7 @@ public Water(int waterIntake) { this.waterIntake += waterIntake; } - public void viewWater() { + public static void viewWater() { System.out.println("Total water intake: " + waterIntake + " ml"); } diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java new file mode 100644 index 0000000000..f047f34102 --- /dev/null +++ b/src/main/java/seedu/duke/user/User.java @@ -0,0 +1,148 @@ +package seedu.duke.user; + +import seedu.duke.Drink; +import seedu.duke.Meal; +import seedu.duke.Parser; +import seedu.duke.Water; + +import java.util.ArrayList; + +public class User { + protected static ArrayList mealList; + protected static ArrayList drinkList; + private static int waterIntake; + + public User() { + mealList = new ArrayList<>(); + drinkList = new ArrayList<>(); + waterIntake = 0; + } + + public static void handleMeal(String command) { + Parser.parseMeal(command); + String mealName = Parser.mealDescription; + int servingSize = Parser.mealSize; + + mealList.add(new Meal(mealName, servingSize)); + System.out.println("Added " + servingSize + " serving of " + mealName); + } + + public static void handleDrink(String command) { + Parser.parseDrink(command); + String drinkName = Parser.drinkDescription; + int servingSize = Parser.drinkSize; + + drinkList.add(new Drink(drinkName, servingSize)); //TODO: Drink constructor needs 8 arguments + System.out.println("Added " + servingSize + " serving of " + drinkName); + } + + public static void handleViewCalories() { + int caloriesCount = 0; + for (Meal meal: mealList) { + caloriesCount += meal.getCalories(); + } + for (Drink drink: drinkList) { + caloriesCount += drink.getCalories(); + } + System.out.println("Total Calories: " + caloriesCount); + } + + public static void handleViewCarbohydrates() { + int carbohydratesCount = 0; + for (Meal meal: mealList) { + carbohydratesCount += meal.getCarbs(); + } + for (Drink drink: drinkList) { + carbohydratesCount += drink.getCarbs(); + } + System.out.println("Total Carbohydrates: " + carbohydratesCount); + } + + public static void handleViewProteins() { + int proteinCount = 0; + for (Meal meal: mealList) { + proteinCount += meal.getProtein(); + } + for (Drink drink: drinkList) { + proteinCount += drink.getProtein(); + } + System.out.println("Total Proteins: " + proteinCount); + } + + public static void handleViewWater() { + System.out.println("Total Water: " + waterIntake); + } + + public static void handleViewFiber() { + int fibreCount = 0; + for (Meal meal: mealList) { + fibreCount += meal.getFiber(); + } + System.out.println("Total Proteins: " + fibreCount); + } + + public static void printMealList(int startingIndex) { + for (int i = startingIndex; i <= mealList.size(); i++) { + Meal currentMeal = mealList.get(i); + System.out.print(i + ". " + currentMeal.getName()); + } + } + public static void handleListMeals() { + System.out.println("here's what you have eaten today"); + if (mealList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printMealList(1); + } + } + + public static void printDrinkList(int startingIndex) { + for (int i = startingIndex; i <= drinkList.size(); i++) { + Drink currentDrink = drinkList.get(i); + System.out.print(i + ". " + currentDrink.getName()); + } + } + + public static void handleListDrinks() { + System.out.println("here's what you have drank today"); + if (drinkList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + Water.viewWater(); + printDrinkList(1); + } + } + + public static void handleListEverything() { + System.out.println("here's what you have drank today"); + if (drinkList.isEmpty() && mealList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printMealList(1); + printDrinkList(mealList.size() + 1); + Water.viewWater(); + } + } + + public static void handleDeleteMeal(String command) { + int mealIndex = Integer.parseInt(command.substring(11)); + String mealName = mealList.get(mealIndex).getName(); + mealList.remove(mealIndex); + + System.out.println("Removed " + mealName + " from Meals"); + } + + public static void handleDeleteDrink(String command) { + int drinkIndex = Integer.parseInt(command.substring(12)); + String drinkName = drinkList.get(drinkIndex).getName(); + drinkList.remove(drinkIndex); + System.out.println("Removed " + drinkName + " from Meals"); + } + + public static void handleClear() { + mealList.clear(); + drinkList.clear(); + System.out.println("All entries have been deleted"); + } + +} From 3d4cfcacc7fcb91ec7f27c47e2fd96577aaefa2d Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 18 Mar 2024 19:50:39 +0800 Subject: [PATCH 019/274] Add Commands to edit serving size --- src/main/java/seedu/duke/Parser.java | 4 ++-- src/main/java/seedu/duke/user/User.java | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 612e0895f8..d8c53e144b 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -42,9 +42,9 @@ public static void handleCommand(String command) { } else if (command.equals("listEverything")) { User.handleListEverything(); } else if (command.startsWith("editMealServingSize")) { - //handleEditMealServingSize(command); + User.handleEditMealServingSize(command); } else if (command.startsWith("editDrinkServingSize")) { - //handleEditDrinkServingSize(command); + User.handleEditDrinkServingSize(command); } else if (command.startsWith("editWaterIntake")) { //handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index f047f34102..c3fb11f62a 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -124,6 +124,28 @@ public static void handleListEverything() { } } + public static void handleEditMealServingSize(String command) { + int slashIndex = command.indexOf("/"); + int mealIndex = Integer.parseInt(command.substring(20, slashIndex - 3)); + String mealName = mealList.get(mealIndex).getName(); + int servingSize = Integer.parseInt(command.substring(slashIndex)); + + Meal updatedMeal = new Meal(mealName, servingSize); + mealList.set(mealIndex, updatedMeal); + System.out.println(mealName + "has been edited to " + servingSize + " serving(s)"); + } + + public static void handleEditDrinkServingSize(String command) { + int slashIndex = command.indexOf("/"); + int drinkIndex = Integer.parseInt(command.substring(21, slashIndex - 3)); + String drinkName = mealList.get(drinkIndex).getName(); + int servingSize = Integer.parseInt(command.substring(slashIndex)); + + Meal updatedDrink = new Drink(drinkName, servingSize); + mealList.set(drinkIndex, updatedDrink); + System.out.println(drinkName + "has been edited to " + servingSize " ml"); + } + public static void handleDeleteMeal(String command) { int mealIndex = Integer.parseInt(command.substring(11)); String mealName = mealList.get(mealIndex).getName(); From d0b7a214761c183f097014dc17ec678988601b9c Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 18 Mar 2024 20:43:48 +0800 Subject: [PATCH 020/274] Fix water class --- src/main/java/seedu/duke/Meal.java | 6 +++--- src/main/java/seedu/duke/Water.java | 9 ++------- src/main/java/seedu/duke/user/User.java | 16 ++++++++++------ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index cd3b46ad3e..c594de6118 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -3,7 +3,8 @@ import java.util.HashMap; public class Meal { - private static String name; + private static HashMap nutrientDetails = new HashMap<>(); + private String name; private int servingSize; private int calories; private int carbs; @@ -11,7 +12,6 @@ public class Meal { private int fat; private int fiber; private int sugar; - private static HashMap nutrientDetails = new HashMap<>(); // Constructor with only serving size and meal name public Meal(String name, int servingSize) { @@ -39,7 +39,7 @@ private void setNutrientValues(String name) { } // Getter methods - public static String getName() { + public String getName() { return name; } diff --git a/src/main/java/seedu/duke/Water.java b/src/main/java/seedu/duke/Water.java index cd6e925190..b8bcb73964 100644 --- a/src/main/java/seedu/duke/Water.java +++ b/src/main/java/seedu/duke/Water.java @@ -1,18 +1,13 @@ package seedu.duke; public class Water { - private int waterIntake = 0; + private int waterIntake; public Water(int waterIntake) { - this.waterIntake += waterIntake; - } - - public static void viewWater() { - System.out.println("Total water intake: " + waterIntake + " ml"); + this.waterIntake = waterIntake; } public int getWater() { return waterIntake; } - } diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index f047f34102..3b386b639f 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -10,12 +10,12 @@ public class User { protected static ArrayList mealList; protected static ArrayList drinkList; - private static int waterIntake; + private static ArrayList totalWaterIntake; public User() { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); - waterIntake = 0; + totalWaterIntake = new ArrayList<>(); } public static void handleMeal(String command) { @@ -69,8 +69,12 @@ public static void handleViewProteins() { System.out.println("Total Proteins: " + proteinCount); } - public static void handleViewWater() { - System.out.println("Total Water: " + waterIntake); + public static void viewTotalWaterIntake() { + int waterIntake = 0; + for (Water water: totalWaterIntake) { + waterIntake += water.getWater(); + } + System.out.println("Total water intake: " + waterIntake); } public static void handleViewFiber() { @@ -108,8 +112,8 @@ public static void handleListDrinks() { if (drinkList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { - Water.viewWater(); printDrinkList(1); + viewTotalWaterIntake(); } } @@ -120,7 +124,7 @@ public static void handleListEverything() { } else { printMealList(1); printDrinkList(mealList.size() + 1); - Water.viewWater(); + viewTotalWaterIntake(); } } From 9bfb7b5d6ba4a3871f93df4429afb93500f03bfd Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 18 Mar 2024 21:09:56 +0800 Subject: [PATCH 021/274] Edit drink and meal class Convert the calculation from per milliliter to per 100 milliliter in drink class. --- src/main/java/seedu/duke/Drink.java | 53 ++++++++++++++++--------- src/main/java/seedu/duke/Meal.java | 24 +++++------ src/main/java/seedu/duke/Parser.java | 2 +- src/main/java/seedu/duke/user/User.java | 6 +-- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/main/java/seedu/duke/Drink.java b/src/main/java/seedu/duke/Drink.java index 50422a9369..ba42982185 100644 --- a/src/main/java/seedu/duke/Drink.java +++ b/src/main/java/seedu/duke/Drink.java @@ -1,24 +1,39 @@ package seedu.duke; +import java.util.HashMap; + public class Drink { + private static HashMap nutrientDetails = new HashMap<>(); private String name; private int drinkVolume; - private int caloriesPerMilliliter; - private int carbsPerMilliliter; - private int sugarPerMilliliter; - private int proteinPerMilliliter; - private int fatPerMilliliter; - private int sodiumPerMilliliter; + private int calories; + private int carbs; + private int sugar; + private int protein; + private int fat; + private int sodium; - public Drink(String name, int volume, int calories, int carbs, int protein, int fat, int sugar, int sodium) { + public Drink(String name, int volume) { this.name = name; this.drinkVolume = volume; - this.caloriesPerMilliliter = calories; - this.carbsPerMilliliter = carbs; - this.proteinPerMilliliter = protein; - this.fatPerMilliliter = fat; - this.sugarPerMilliliter = sugar; - this.sodiumPerMilliliter = sodium; + setNutrientValues(name); + } + + // Add nutrient details per 100 milliliter to the static HashMap + static { + nutrientDetails.put("sprite", new int[]{40, 50, 30, 20, 2, 5}); + nutrientDetails.put("lemon tea", new int[]{150, 30, 25, 1, 20, 3}); + nutrientDetails.put("milk coffee", new int[]{20, 27, 25, 4, 3, 2}); + } + + private void setNutrientValues(String name) { + int[] nutrients = nutrientDetails.get(name); + calories = nutrients[0] * drinkVolume / 100; + carbs = nutrients[1] * drinkVolume / 100; + sugar = nutrients[2] * drinkVolume / 100; + protein = nutrients[3] * drinkVolume / 100; + fat = nutrients[4] * drinkVolume / 100; + sodium = nutrients[5] * drinkVolume / 100; } public void infoDrink() { @@ -42,26 +57,26 @@ public int getDrinkVolumeSize() { } public int getCalories() { - return caloriesPerMilliliter * drinkVolume; + return calories; } public int getCarbs() { - return carbsPerMilliliter * drinkVolume; + return carbs; } public int getSugar() { - return sugarPerMilliliter * drinkVolume; + return sugar; } public int getProtein() { - return proteinPerMilliliter * drinkVolume; + return protein; } public int getFat() { - return fatPerMilliliter* drinkVolume; + return fat; } public int getSodium() { - return sodiumPerMilliliter * drinkVolume; + return sodium; } } diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index c594de6118..db4e0f53d6 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -30,12 +30,12 @@ public Meal(String name, int servingSize) { // Method to set nutrient values based on meal name private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); - calories = nutrients[0]; - carbs = nutrients[1]; - protein = nutrients[2]; - fat = nutrients[3]; - fiber = nutrients[4]; - sugar = nutrients[5]; + calories = nutrients[0] * servingSize; + carbs = nutrients[1] * servingSize; + protein = nutrients[2] * servingSize; + fat = nutrients[3] * servingSize; + fiber = nutrients[4] * servingSize; + sugar = nutrients[5] * servingSize; } // Getter methods @@ -44,27 +44,27 @@ public String getName() { } public int getCalories() { - return calories * servingSize; + return calories; } public int getCarbs() { - return carbs * servingSize; + return carbs; } public int getProtein() { - return protein * servingSize; + return protein; } public int getFat() { - return fat * servingSize; + return fat; } public int getFiber() { - return fiber * servingSize; + return fiber; } public int getSugar() { - return sugar * servingSize; + return sugar; } // Method to print all meal info diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 612e0895f8..992f146a90 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -32,7 +32,7 @@ public static void handleCommand(String command) { } else if (command.equals("viewProteins")) { User.handleViewProteins(); } else if (command.equals("viewWater")) { - User.handleViewWater(); + User.handleViewWaterIntake(); } else if (command.equals("viewFiber")) { User.handleViewFiber(); } else if (command.equals("listMeals")) { diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index 3b386b639f..42f6bda798 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -69,7 +69,7 @@ public static void handleViewProteins() { System.out.println("Total Proteins: " + proteinCount); } - public static void viewTotalWaterIntake() { + public static void handleViewWaterIntake() { int waterIntake = 0; for (Water water: totalWaterIntake) { waterIntake += water.getWater(); @@ -113,7 +113,7 @@ public static void handleListDrinks() { System.out.println(" >> nothing so far :o"); } else { printDrinkList(1); - viewTotalWaterIntake(); + handleViewWaterIntake(); } } @@ -124,7 +124,7 @@ public static void handleListEverything() { } else { printMealList(1); printDrinkList(mealList.size() + 1); - viewTotalWaterIntake(); + handleViewWaterIntake(); } } From fbb8d12ece53ff6408923531c0b431217f72471b Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 18 Mar 2024 23:15:08 +0800 Subject: [PATCH 022/274] Add FitNus class Added FitNus class and made the necessary modifications to other classes --- src/main/java/seedu/duke/Drink.java | 28 ++++----- src/main/java/seedu/duke/FitNus.java | 24 +++++++- src/main/java/seedu/duke/Meal.java | 17 +++--- src/main/java/seedu/duke/Parser.java | 50 +++++++++------- src/main/java/seedu/duke/Ui.java | 41 +++++++++++++ src/main/java/seedu/duke/user/User.java | 80 +++++++++++++++++-------- 6 files changed, 169 insertions(+), 71 deletions(-) create mode 100644 src/main/java/seedu/duke/Ui.java diff --git a/src/main/java/seedu/duke/Drink.java b/src/main/java/seedu/duke/Drink.java index ba42982185..27026c03a1 100644 --- a/src/main/java/seedu/duke/Drink.java +++ b/src/main/java/seedu/duke/Drink.java @@ -11,7 +11,6 @@ public class Drink { private int sugar; private int protein; private int fat; - private int sodium; public Drink(String name, int volume) { this.name = name; @@ -21,9 +20,9 @@ public Drink(String name, int volume) { // Add nutrient details per 100 milliliter to the static HashMap static { - nutrientDetails.put("sprite", new int[]{40, 50, 30, 20, 2, 5}); - nutrientDetails.put("lemon tea", new int[]{150, 30, 25, 1, 20, 3}); - nutrientDetails.put("milk coffee", new int[]{20, 27, 25, 4, 3, 2}); + nutrientDetails.put("sprite", new int[]{40, 50, 30, 20, 2}); + nutrientDetails.put("lemon tea", new int[]{150, 30, 25, 1, 20}); + nutrientDetails.put("milk coffee", new int[]{20, 27, 25, 4, 3}); } private void setNutrientValues(String name) { @@ -33,19 +32,18 @@ private void setNutrientValues(String name) { sugar = nutrients[2] * drinkVolume / 100; protein = nutrients[3] * drinkVolume / 100; fat = nutrients[4] * drinkVolume / 100; - sodium = nutrients[5] * drinkVolume / 100; } - public void infoDrink() { + public static void handleInfoDrink(String command) { + String name = Parser.parseInfoDrink(command); + int[] nutrients = nutrientDetails.get(name); System.out.println("Drink: " + name); - System.out.println("Volume: " + drinkVolume); - System.out.println("Calories: " + getCalories()); - System.out.println("Carbs: " + getCarbs()); + System.out.println("Calories: " + nutrients[0]); + System.out.println("Carbs: " + nutrients[1]); // Sugar is part of Carbohydrates - System.out.println(" Sugar: " + getSugar()); - System.out.println("Protein: " + getProtein()); - System.out.println("Fat: " + getFat()); - System.out.println("Sodium: " + getSodium()); + System.out.println("Sugar: " + nutrients[2]); + System.out.println("Protein: " + nutrients[3]); + System.out.println("Fat: " + nutrients[4]); } public String getName() { @@ -75,8 +73,4 @@ public int getProtein() { public int getFat() { return fat; } - - public int getSodium() { - return sodium; - } } diff --git a/src/main/java/seedu/duke/FitNus.java b/src/main/java/seedu/duke/FitNus.java index 6182fffa62..a74b976dae 100644 --- a/src/main/java/seedu/duke/FitNus.java +++ b/src/main/java/seedu/duke/FitNus.java @@ -1,4 +1,26 @@ package seedu.duke; +import seedu.duke.user.User; + public class FitNus { -} + + private static Ui ui; + + public FitNus() { + ui = new Ui(); + } + + /** Runs the program until termination. */ + public void run() { + ui.printWelcomeMessage(); + while (!ui.isExit) { + ui.readCommand(); + } + } + + public static void main(String[] args) { + new FitNus().run(); + } + + +} \ No newline at end of file diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index db4e0f53d6..b6a31f8c87 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -68,15 +68,16 @@ public int getSugar() { } // Method to print all meal info - public void infoMeal() { + public static void handleInfoMeal(String command) { + String name = Parser.parseInfoMeal(command); + int[] nutrients = nutrientDetails.get(name); System.out.println("Meal: " + name); - System.out.println("Serving Size: " + servingSize); - System.out.println("Calories: " + getCalories()); - System.out.println("Carbs: " + getCarbs()); - System.out.println("Protein: " + getProtein()); - System.out.println("Fat: " + getFat()); - System.out.println("Fiber: " + getFiber()); - System.out.println("Sugar: " + getSugar()); + System.out.println("Calories: " + nutrients[0]); + System.out.println("Carbs: " + nutrients[1]); + System.out.println("Protein: " + nutrients[2]); + System.out.println("Fat: " + nutrients[3]); + System.out.println("Fiber: " + nutrients[4]); + System.out.println("Sugar: " + nutrients[5]); } } diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 992f146a90..0c400eae9e 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -13,34 +13,44 @@ public class Parser { public static int editDrinkIndex; public static int editDrinkSize; public static int editWaterSize; + private User user; - public static void handleCommand(String command) { + public Parser() { + this.user = new User(); + } + public void handleCommand(String command) { if (command.equals("help")) { handleHelp(); } else if (command.startsWith("ate")) { - User.handleMeal(command); + user.handleMeal(command); } else if (command.startsWith("drink")) { - User.handleDrink(command); - } else if (command.startsWith("infoMeal")) { - //handleInfoMeal(command); + user.handleDrink(command); + } else if (command.startsWith("water")) { + user.handleWater(command); + }else if (command.startsWith("infoMeal")) { + Meal.handleInfoMeal(command); } else if (command.startsWith("infoDrink")) { - //handleInfoDrink(command); + Drink.handleInfoDrink(command); } else if (command.equals("viewCalories")) { - User.handleViewCalories(); + user.handleViewCalories(); } else if (command.equals("viewCarbohydrates")) { - User.handleViewCarbohydrates(); - } else if (command.equals("viewProteins")) { - User.handleViewProteins(); + user.handleViewCarbohydrates(); + } else if (command.equals("viewProtein")) { + user.handleViewProteins(); + } else if (command.equals("viewSugar")) { + user.handleViewSugar(); + }else if (command.equals("viewFat")) { + user.handleViewFat(); } else if (command.equals("viewWater")) { - User.handleViewWaterIntake(); + user.handleViewWaterIntake(); } else if (command.equals("viewFiber")) { - User.handleViewFiber(); + user.handleViewFiber(); } else if (command.equals("listMeals")) { - User.handleListMeals(); + user.handleListMeals(); } else if (command.equals("listDrinks")) { - User.handleListDrinks(); + user.handleListDrinks(); } else if (command.equals("listEverything")) { - User.handleListEverything(); + user.handleListEverything(); } else if (command.startsWith("editMealServingSize")) { //handleEditMealServingSize(command); } else if (command.startsWith("editDrinkServingSize")) { @@ -48,13 +58,11 @@ public static void handleCommand(String command) { } else if (command.startsWith("editWaterIntake")) { //handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { - User.handleDeleteMeal(command); + user.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { - User.handleDeleteDrink(command); + user.handleDeleteDrink(command); } else if (command.equals("clear")) { - User.handleClear(); - } else if (command.equals("exit")) { - //User.handleExit(); + user.handleClear(); } else { System.out.println("Invalid command"); } @@ -68,7 +76,7 @@ public static void handleHelp() { System.out.println("Find the information about a certain drink: infoDrink DRINK"); System.out.println("View daily calories consumed: viewCalories"); System.out.println("View daily carbohydrates consumed: viewCarbohydrates"); - System.out.println("View daily proteins consumed: viewProteins"); + System.out.println("View daily proteins consumed: viewProtein"); System.out.println("View daily fat consumed: viewFat"); System.out.println("View daily sugar consumed: viewSugar"); System.out.println("View daily water consumption: viewWater"); diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java new file mode 100644 index 0000000000..973dda84cf --- /dev/null +++ b/src/main/java/seedu/duke/Ui.java @@ -0,0 +1,41 @@ +package seedu.duke; + +import java.util.Scanner; + +public class Ui { + public static final String LINE = "_________________________________________________________________"; + static Scanner input = new Scanner(System.in); + /** Specifies whether user has input the exit command */ + public boolean isExit = false; + + private Parser parser = new Parser(); + + /** Prints the welcome message upon the start of the application */ + public void printWelcomeMessage() { + System.out.println(LINE); + System.out.println("Hello! Welcome to FitNUS"); + System.out.println("What would you like to track today?"); + System.out.println(LINE); + } + + public void handleExit() { + System.out.println("Bye. Hope to see you again soon!"); + input.close(); + isExit = true; + } + + public static void showLine() { + System.out.println(LINE); + } + + public void readCommand() { + String command = input.nextLine(); + showLine(); + if (command.equals("exit")) { + handleExit(); + } else { + parser.handleCommand(command); + } + showLine(); + } +} diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index 42f6bda798..a6f91f1e6d 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -18,7 +18,7 @@ public User() { totalWaterIntake = new ArrayList<>(); } - public static void handleMeal(String command) { + public void handleMeal(String command) { Parser.parseMeal(command); String mealName = Parser.mealDescription; int servingSize = Parser.mealSize; @@ -27,16 +27,23 @@ public static void handleMeal(String command) { System.out.println("Added " + servingSize + " serving of " + mealName); } - public static void handleDrink(String command) { + public void handleDrink(String command) { Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; - drinkList.add(new Drink(drinkName, servingSize)); //TODO: Drink constructor needs 8 arguments - System.out.println("Added " + servingSize + " serving of " + drinkName); + drinkList.add(new Drink(drinkName, servingSize)); + System.out.println("Added " + servingSize + " ml of " + drinkName); } - public static void handleViewCalories() { + public void handleWater(String command) { + Parser.parseWater(command); + int volume = Parser.waterSize; + + totalWaterIntake.add(new Water(volume)); + System.out.println("Added " + volume + " ml of water"); + } + public void handleViewCalories() { int caloriesCount = 0; for (Meal meal: mealList) { caloriesCount += meal.getCalories(); @@ -47,7 +54,7 @@ public static void handleViewCalories() { System.out.println("Total Calories: " + caloriesCount); } - public static void handleViewCarbohydrates() { + public void handleViewCarbohydrates() { int carbohydratesCount = 0; for (Meal meal: mealList) { carbohydratesCount += meal.getCarbs(); @@ -58,7 +65,7 @@ public static void handleViewCarbohydrates() { System.out.println("Total Carbohydrates: " + carbohydratesCount); } - public static void handleViewProteins() { + public void handleViewProteins() { int proteinCount = 0; for (Meal meal: mealList) { proteinCount += meal.getProtein(); @@ -69,29 +76,52 @@ public static void handleViewProteins() { System.out.println("Total Proteins: " + proteinCount); } - public static void handleViewWaterIntake() { + public void handleViewWaterIntake() { int waterIntake = 0; for (Water water: totalWaterIntake) { waterIntake += water.getWater(); } - System.out.println("Total water intake: " + waterIntake); + System.out.println("Total water intake: " + waterIntake + " ml"); } - public static void handleViewFiber() { + public void handleViewFiber() { int fibreCount = 0; for (Meal meal: mealList) { fibreCount += meal.getFiber(); } - System.out.println("Total Proteins: " + fibreCount); + System.out.println("Total Fiber: " + fibreCount); + } + + public void handleViewFat() { + int fatCount = 0; + for (Meal meal: mealList) { + fatCount += meal.getFat(); + } + for (Drink drink: drinkList) { + fatCount += drink.getFat(); + } + System.out.println("Total Fat: " + fatCount); + } + + public void handleViewSugar() { + int sugarCount = 0; + for (Meal meal: mealList) { + sugarCount += meal.getSugar(); + } + for (Drink drink: drinkList) { + sugarCount += drink.getSugar(); + } + System.out.println("Total Sugar: " + sugarCount); } - public static void printMealList(int startingIndex) { - for (int i = startingIndex; i <= mealList.size(); i++) { + public void printMealList(int startIndex) { + for (int i = 0; i < mealList.size(); i++) { Meal currentMeal = mealList.get(i); - System.out.print(i + ". " + currentMeal.getName()); + System.out.print((startIndex+i) + ". " + currentMeal.getName()); } + System.out.println(); } - public static void handleListMeals() { + public void handleListMeals() { System.out.println("here's what you have eaten today"); if (mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); @@ -100,35 +130,37 @@ public static void handleListMeals() { } } - public static void printDrinkList(int startingIndex) { - for (int i = startingIndex; i <= drinkList.size(); i++) { + public void printDrinkList(int startIndex) { + for (int i = 0; i < drinkList.size(); i++) { Drink currentDrink = drinkList.get(i); - System.out.print(i + ". " + currentDrink.getName()); + System.out.print((startIndex+i) + ". " + currentDrink.getName()); } } - public static void handleListDrinks() { + public void handleListDrinks() { System.out.println("here's what you have drank today"); if (drinkList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { printDrinkList(1); + System.out.println(); handleViewWaterIntake(); } } - public static void handleListEverything() { + public void handleListEverything() { System.out.println("here's what you have drank today"); if (drinkList.isEmpty() && mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { printMealList(1); - printDrinkList(mealList.size() + 1); + printDrinkList(mealList.size()+1); + System.out.println(); handleViewWaterIntake(); } } - public static void handleDeleteMeal(String command) { + public void handleDeleteMeal(String command) { int mealIndex = Integer.parseInt(command.substring(11)); String mealName = mealList.get(mealIndex).getName(); mealList.remove(mealIndex); @@ -136,14 +168,14 @@ public static void handleDeleteMeal(String command) { System.out.println("Removed " + mealName + " from Meals"); } - public static void handleDeleteDrink(String command) { + public void handleDeleteDrink(String command) { int drinkIndex = Integer.parseInt(command.substring(12)); String drinkName = drinkList.get(drinkIndex).getName(); drinkList.remove(drinkIndex); System.out.println("Removed " + drinkName + " from Meals"); } - public static void handleClear() { + public void handleClear() { mealList.clear(); drinkList.clear(); System.out.println("All entries have been deleted"); From 5861079454007db92dea7663d51c535285d7b2a8 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 18 Mar 2024 23:19:34 +0800 Subject: [PATCH 023/274] Add new line to end of file --- src/main/java/seedu/duke/FitNus.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/seedu/duke/FitNus.java b/src/main/java/seedu/duke/FitNus.java index a74b976dae..2b678164eb 100644 --- a/src/main/java/seedu/duke/FitNus.java +++ b/src/main/java/seedu/duke/FitNus.java @@ -1,7 +1,5 @@ package seedu.duke; -import seedu.duke.user.User; - public class FitNus { private static Ui ui; @@ -23,4 +21,4 @@ public static void main(String[] args) { } -} \ No newline at end of file +} From 96ed909485cee7db12f83c9f85550b9fd23bade6 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 19 Mar 2024 14:04:53 +0800 Subject: [PATCH 024/274] Add exception package and classes --- src/main/java/seedu/duke/Drink.java | 17 +- src/main/java/seedu/duke/Meal.java | 15 ++ src/main/java/seedu/duke/Parser.java | 150 ++++++++++++------ src/main/java/seedu/duke/Ui.java | 2 + .../exception/IncompleteDrinkException.java | 4 + .../exception/IncompleteMealException.java | 4 + .../exception/IncompleteWaterException.java | 4 + .../exception/InvalidCommandException.java | 4 + .../exception/UnregisteredDrinkException.java | 4 + .../exception/UnregisteredMealException.java | 4 + src/main/java/seedu/duke/user/User.java | 12 +- 11 files changed, 166 insertions(+), 54 deletions(-) create mode 100644 src/main/java/seedu/duke/exception/IncompleteDrinkException.java create mode 100644 src/main/java/seedu/duke/exception/IncompleteMealException.java create mode 100644 src/main/java/seedu/duke/exception/IncompleteWaterException.java create mode 100644 src/main/java/seedu/duke/exception/InvalidCommandException.java create mode 100644 src/main/java/seedu/duke/exception/UnregisteredDrinkException.java create mode 100644 src/main/java/seedu/duke/exception/UnregisteredMealException.java diff --git a/src/main/java/seedu/duke/Drink.java b/src/main/java/seedu/duke/Drink.java index 27026c03a1..d4b395d6f1 100644 --- a/src/main/java/seedu/duke/Drink.java +++ b/src/main/java/seedu/duke/Drink.java @@ -37,7 +37,7 @@ private void setNutrientValues(String name) { public static void handleInfoDrink(String command) { String name = Parser.parseInfoDrink(command); int[] nutrients = nutrientDetails.get(name); - System.out.println("Drink: " + name); + System.out.println("Drink: " + name + " (100 ml)"); System.out.println("Calories: " + nutrients[0]); System.out.println("Carbs: " + nutrients[1]); // Sugar is part of Carbohydrates @@ -46,6 +46,16 @@ public static void handleInfoDrink(String command) { System.out.println("Fat: " + nutrients[4]); } + public static void printAvailableDrinks() { + System.out.print("Available drinks: "); + for (String drink : nutrientDetails.keySet()) { + System.out.print(drink); + System.out.print(", "); + } + System.out.print("etc."); + System.out.println(); + } + public String getName() { return name; } @@ -73,4 +83,9 @@ public int getProtein() { public int getFat() { return fat; } + + public static HashMap getNutrientDetails() { + return nutrientDetails; + } + } diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index b6a31f8c87..3fcd94ae38 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -80,4 +80,19 @@ public static void handleInfoMeal(String command) { System.out.println("Sugar: " + nutrients[5]); } + // Print all the available meals registered in the database + public static void printAvailableMeals() { + System.out.print("Available meals: "); + for (String meal : nutrientDetails.keySet()) { + System.out.print(meal); + System.out.print(", "); + } + System.out.print("etc."); + System.out.println(); + } + + public static HashMap getNutrientDetails() { + return nutrientDetails; + } + } diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 0c400eae9e..deea938692 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -1,5 +1,11 @@ package seedu.duke; +import seedu.duke.exception.IncompleteDrinkException; +import seedu.duke.exception.IncompleteMealException; +import seedu.duke.exception.IncompleteWaterException; +import seedu.duke.exception.InvalidCommandException; +import seedu.duke.exception.UnregisteredDrinkException; +import seedu.duke.exception.UnregisteredMealException; import seedu.duke.user.User; public class Parser { @@ -19,58 +25,72 @@ public Parser() { this.user = new User(); } public void handleCommand(String command) { - if (command.equals("help")) { - handleHelp(); - } else if (command.startsWith("ate")) { - user.handleMeal(command); - } else if (command.startsWith("drink")) { - user.handleDrink(command); - } else if (command.startsWith("water")) { - user.handleWater(command); - }else if (command.startsWith("infoMeal")) { - Meal.handleInfoMeal(command); - } else if (command.startsWith("infoDrink")) { - Drink.handleInfoDrink(command); - } else if (command.equals("viewCalories")) { - user.handleViewCalories(); - } else if (command.equals("viewCarbohydrates")) { - user.handleViewCarbohydrates(); - } else if (command.equals("viewProtein")) { - user.handleViewProteins(); - } else if (command.equals("viewSugar")) { - user.handleViewSugar(); - }else if (command.equals("viewFat")) { - user.handleViewFat(); - } else if (command.equals("viewWater")) { - user.handleViewWaterIntake(); - } else if (command.equals("viewFiber")) { - user.handleViewFiber(); - } else if (command.equals("listMeals")) { - user.handleListMeals(); - } else if (command.equals("listDrinks")) { - user.handleListDrinks(); - } else if (command.equals("listEverything")) { - user.handleListEverything(); - } else if (command.startsWith("editMealServingSize")) { - //handleEditMealServingSize(command); - } else if (command.startsWith("editDrinkServingSize")) { - //handleEditDrinkServingSize(command); - } else if (command.startsWith("editWaterIntake")) { - //handleEditWaterIntake(command); - } else if (command.startsWith("deleteMeal")) { - user.handleDeleteMeal(command); - } else if (command.startsWith("deleteDrink")) { - user.handleDeleteDrink(command); - } else if (command.equals("clear")) { - user.handleClear(); - } else { - System.out.println("Invalid command"); + try { + if (command.equals("help")) { + handleHelp(); + } else if (command.startsWith("ate")) { + user.handleMeal(command); + } else if (command.startsWith("drink")) { + user.handleDrink(command); + } else if (command.startsWith("water")) { + user.handleWater(command); + } else if (command.startsWith("infoMeal")) { + Meal.handleInfoMeal(command); + } else if (command.startsWith("infoDrink")) { + Drink.handleInfoDrink(command); + } else if (command.equals("viewCalories")) { + user.handleViewCalories(); + } else if (command.equals("viewCarbohydrates")) { + user.handleViewCarbohydrates(); + } else if (command.equals("viewProtein")) { + user.handleViewProteins(); + } else if (command.equals("viewSugar")) { + user.handleViewSugar(); + } else if (command.equals("viewFat")) { + user.handleViewFat(); + } else if (command.equals("viewWater")) { + user.handleViewWaterIntake(); + } else if (command.equals("viewFiber")) { + user.handleViewFiber(); + } else if (command.equals("listMeals")) { + user.handleListMeals(); + } else if (command.equals("listDrinks")) { + user.handleListDrinks(); + } else if (command.equals("listEverything")) { + user.handleListEverything(); + } else if (command.startsWith("editMealServingSize")) { + //handleEditMealServingSize(command); + } else if (command.startsWith("editDrinkServingSize")) { + //handleEditDrinkServingSize(command); + } else if (command.startsWith("editWaterIntake")) { + //handleEditWaterIntake(command); + } else if (command.startsWith("deleteMeal")) { + user.handleDeleteMeal(command); + } else if (command.startsWith("deleteDrink")) { + user.handleDeleteDrink(command); + } else if (command.equals("clear")) { + user.handleClear(); + } else { + throw new InvalidCommandException(); + } + } catch (InvalidCommandException e) { + System.out.println("Invalid command, type [help] to view all commands."); + } catch (IncompleteWaterException e) { + System.out.println("Incomplete command, the format must be [water s/SERVING_SIZE]."); + } catch (IncompleteDrinkException e) { + System.out.println("Incomplete command, the format must be [drink d/DRINK s/SERVING_SIZE]."); + } catch (IncompleteMealException e) { + System.out.println("Incomplete command, the format must be [ate m/MEAL s/SERVING_SIZE]."); + } catch (UnregisteredDrinkException e) { + System.out.println("Sorry that drink is not registered in the database."); + } catch (UnregisteredMealException e) { + throw new RuntimeException("Sorry that meal is not registered in the database."); } } public static void handleHelp() { System.out.println("Add a meal eaten: ate m/MEAL s/SERVING_SIZE"); - System.out.println("Add a drink: d/DRINK s/SERVING_SIZE"); + System.out.println("Add a drink: drink d/DRINK s/SERVING_SIZE"); System.out.println("Add water: water s/SERVING_SIZE"); System.out.println("Find the information about a certain meal: infoMeal MEAL"); System.out.println("Find the information about a certain drink: infoDrink DRINK"); @@ -93,22 +113,52 @@ public static void handleHelp() { System.out.println("Exit the app: exit "); } - public static void parseMeal(String command) { + public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException { + if (!command.contains("m/") || !command.contains("s/")) { + throw new IncompleteMealException(); + } int descriptionIndex = command.indexOf("m/") + 2; int sizeIndex = command.indexOf("s/") + 2; + if (sizeIndex >= command.length()) { + throw new IncompleteMealException(); + } mealDescription = command.substring(descriptionIndex, sizeIndex - 2).trim(); + if (mealDescription.isEmpty()) { + throw new IncompleteMealException(); + } + if (!Meal.getNutrientDetails().containsKey(mealDescription)) { + throw new UnregisteredMealException(); + } mealSize = Integer.parseInt(command.substring(sizeIndex).trim()); } - public static void parseDrink(String command) { + public static void parseDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException { + if (!command.contains("d/") || !command.contains("s/")) { + throw new IncompleteDrinkException(); + } int descriptionIndex = command.indexOf("d/") + 2; int sizeIndex = command.indexOf("s/") + 2; + if (sizeIndex >= command.length()) { + throw new IncompleteDrinkException(); + } drinkDescription = command.substring(descriptionIndex, sizeIndex - 2).trim(); + if (drinkDescription.isEmpty()) { + throw new IncompleteDrinkException(); + } + if (!Drink.getNutrientDetails().containsKey(drinkDescription)) { + throw new UnregisteredDrinkException(); + } drinkSize = Integer.parseInt(command.substring(sizeIndex).trim()); } - public static void parseWater(String command) { + public static void parseWater(String command) throws IncompleteWaterException { + if (!command.contains("s/")) { + throw new IncompleteWaterException(); + } int sizeIndex = command.indexOf("s/") + 2; + if (sizeIndex >= command.length()) { + throw new IncompleteWaterException(); + } waterSize = Integer.parseInt(command.substring(sizeIndex).trim()); } diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 973dda84cf..537cab35ed 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -15,6 +15,8 @@ public void printWelcomeMessage() { System.out.println(LINE); System.out.println("Hello! Welcome to FitNUS"); System.out.println("What would you like to track today?"); + Meal.printAvailableMeals(); + Drink.printAvailableDrinks(); System.out.println(LINE); } diff --git a/src/main/java/seedu/duke/exception/IncompleteDrinkException.java b/src/main/java/seedu/duke/exception/IncompleteDrinkException.java new file mode 100644 index 0000000000..f65e9eb7b0 --- /dev/null +++ b/src/main/java/seedu/duke/exception/IncompleteDrinkException.java @@ -0,0 +1,4 @@ +package seedu.duke.exception; + +public class IncompleteDrinkException extends Exception{ +} diff --git a/src/main/java/seedu/duke/exception/IncompleteMealException.java b/src/main/java/seedu/duke/exception/IncompleteMealException.java new file mode 100644 index 0000000000..15965cc126 --- /dev/null +++ b/src/main/java/seedu/duke/exception/IncompleteMealException.java @@ -0,0 +1,4 @@ +package seedu.duke.exception; + +public class IncompleteMealException extends Exception{ +} diff --git a/src/main/java/seedu/duke/exception/IncompleteWaterException.java b/src/main/java/seedu/duke/exception/IncompleteWaterException.java new file mode 100644 index 0000000000..29804d6ff9 --- /dev/null +++ b/src/main/java/seedu/duke/exception/IncompleteWaterException.java @@ -0,0 +1,4 @@ +package seedu.duke.exception; + +public class IncompleteWaterException extends Exception{ +} diff --git a/src/main/java/seedu/duke/exception/InvalidCommandException.java b/src/main/java/seedu/duke/exception/InvalidCommandException.java new file mode 100644 index 0000000000..8f9584c8f5 --- /dev/null +++ b/src/main/java/seedu/duke/exception/InvalidCommandException.java @@ -0,0 +1,4 @@ +package seedu.duke.exception; + +public class InvalidCommandException extends Exception{ +} diff --git a/src/main/java/seedu/duke/exception/UnregisteredDrinkException.java b/src/main/java/seedu/duke/exception/UnregisteredDrinkException.java new file mode 100644 index 0000000000..0b2850d9f3 --- /dev/null +++ b/src/main/java/seedu/duke/exception/UnregisteredDrinkException.java @@ -0,0 +1,4 @@ +package seedu.duke.exception; + +public class UnregisteredDrinkException extends Exception{ +} diff --git a/src/main/java/seedu/duke/exception/UnregisteredMealException.java b/src/main/java/seedu/duke/exception/UnregisteredMealException.java new file mode 100644 index 0000000000..627cb7dacb --- /dev/null +++ b/src/main/java/seedu/duke/exception/UnregisteredMealException.java @@ -0,0 +1,4 @@ +package seedu.duke.exception; + +public class UnregisteredMealException extends Exception{ +} diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index a6f91f1e6d..0d501f25de 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -5,6 +5,12 @@ import seedu.duke.Parser; import seedu.duke.Water; +import seedu.duke.exception.IncompleteDrinkException; +import seedu.duke.exception.IncompleteMealException; +import seedu.duke.exception.IncompleteWaterException; +import seedu.duke.exception.UnregisteredDrinkException; +import seedu.duke.exception.UnregisteredMealException; + import java.util.ArrayList; public class User { @@ -18,7 +24,7 @@ public User() { totalWaterIntake = new ArrayList<>(); } - public void handleMeal(String command) { + public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException { Parser.parseMeal(command); String mealName = Parser.mealDescription; int servingSize = Parser.mealSize; @@ -27,7 +33,7 @@ public void handleMeal(String command) { System.out.println("Added " + servingSize + " serving of " + mealName); } - public void handleDrink(String command) { + public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException { Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; @@ -36,7 +42,7 @@ public void handleDrink(String command) { System.out.println("Added " + servingSize + " ml of " + drinkName); } - public void handleWater(String command) { + public void handleWater(String command) throws IncompleteWaterException { Parser.parseWater(command); int volume = Parser.waterSize; From a2e9b128cff371175768117c8b2e25ab4ab098d5 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 19 Mar 2024 14:08:43 +0800 Subject: [PATCH 025/274] Fix exception bug --- src/main/java/seedu/duke/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index deea938692..c598e21a08 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -84,7 +84,7 @@ public void handleCommand(String command) { } catch (UnregisteredDrinkException e) { System.out.println("Sorry that drink is not registered in the database."); } catch (UnregisteredMealException e) { - throw new RuntimeException("Sorry that meal is not registered in the database."); + System.out.println("Sorry that meal is not registered in the database."); } } From 7ec557f499250482d2d8e349d794d0b7ceadcba7 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 19 Mar 2024 14:27:23 +0800 Subject: [PATCH 026/274] Add more exception checks --- src/main/java/seedu/duke/Drink.java | 4 +++- src/main/java/seedu/duke/Meal.java | 6 ++++-- src/main/java/seedu/duke/Parser.java | 14 +++++++++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/duke/Drink.java b/src/main/java/seedu/duke/Drink.java index d4b395d6f1..6e8d58a43d 100644 --- a/src/main/java/seedu/duke/Drink.java +++ b/src/main/java/seedu/duke/Drink.java @@ -1,5 +1,7 @@ package seedu.duke; +import seedu.duke.exception.UnregisteredDrinkException; + import java.util.HashMap; public class Drink { @@ -34,7 +36,7 @@ private void setNutrientValues(String name) { fat = nutrients[4] * drinkVolume / 100; } - public static void handleInfoDrink(String command) { + public static void handleInfoDrink(String command) throws UnregisteredDrinkException { String name = Parser.parseInfoDrink(command); int[] nutrients = nutrientDetails.get(name); System.out.println("Drink: " + name + " (100 ml)"); diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index 3fcd94ae38..0030cdeca1 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -1,5 +1,7 @@ package seedu.duke; +import seedu.duke.exception.UnregisteredMealException; + import java.util.HashMap; public class Meal { @@ -68,10 +70,10 @@ public int getSugar() { } // Method to print all meal info - public static void handleInfoMeal(String command) { + public static void handleInfoMeal(String command) throws UnregisteredMealException { String name = Parser.parseInfoMeal(command); int[] nutrients = nutrientDetails.get(name); - System.out.println("Meal: " + name); + System.out.println("Meal: " + name + " (per serving)"); System.out.println("Calories: " + nutrients[0]); System.out.println("Carbs: " + nutrients[1]); System.out.println("Protein: " + nutrients[2]); diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index c598e21a08..a69c74eba4 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -162,13 +162,21 @@ public static void parseWater(String command) throws IncompleteWaterException { waterSize = Integer.parseInt(command.substring(sizeIndex).trim()); } - public static String parseInfoMeal(String command) { + public static String parseInfoMeal(String command) throws UnregisteredMealException { int mealIndex = 9; - return command.substring(mealIndex).trim(); + String infoMealDescription = command.substring(mealIndex).trim(); + if (!Meal.getNutrientDetails().containsKey(infoMealDescription)) { + throw new UnregisteredMealException(); + } + return infoMealDescription; } - public static String parseInfoDrink(String command) { + public static String parseInfoDrink(String command) throws UnregisteredDrinkException { int drinkIndex = 10; + String infoDrinkDescription = command.substring(drinkIndex).trim(); + if (!Meal.getNutrientDetails().containsKey(infoDrinkDescription)) { + throw new UnregisteredDrinkException(); + } return command.substring(drinkIndex).trim(); } From 4c57e087c9f91f315f10292991c7d4bc69cbd303 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 14:58:12 +0800 Subject: [PATCH 027/274] Fix bugs in commands --- src/main/java/seedu/duke/Drink.java | 2 -- src/main/java/seedu/duke/Parser.java | 4 ++-- src/main/java/seedu/duke/user/User.java | 27 ++++++++++++------------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/main/java/seedu/duke/Drink.java b/src/main/java/seedu/duke/Drink.java index 6e8d58a43d..3c3bffb7ce 100644 --- a/src/main/java/seedu/duke/Drink.java +++ b/src/main/java/seedu/duke/Drink.java @@ -1,7 +1,6 @@ package seedu.duke; import seedu.duke.exception.UnregisteredDrinkException; - import java.util.HashMap; public class Drink { @@ -35,7 +34,6 @@ private void setNutrientValues(String name) { protein = nutrients[3] * drinkVolume / 100; fat = nutrients[4] * drinkVolume / 100; } - public static void handleInfoDrink(String command) throws UnregisteredDrinkException { String name = Parser.parseInfoDrink(command); int[] nutrients = nutrientDetails.get(name); diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index a69c74eba4..5878756b7a 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -59,9 +59,9 @@ public void handleCommand(String command) { } else if (command.equals("listEverything")) { user.handleListEverything(); } else if (command.startsWith("editMealServingSize")) { - //handleEditMealServingSize(command); + User.handleEditMealServingSize(command); } else if (command.startsWith("editDrinkServingSize")) { - //handleEditDrinkServingSize(command); + User.handleEditDrinkServingSize(command); } else if (command.startsWith("editWaterIntake")) { //handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index 320cdb412b..af801da727 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -23,7 +23,6 @@ public User() { drinkList = new ArrayList<>(); totalWaterIntake = new ArrayList<>(); } - public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException { Parser.parseMeal(command); String mealName = Parser.mealDescription; @@ -123,7 +122,7 @@ public void handleViewSugar() { public void printMealList(int startIndex) { for (int i = 0; i < mealList.size(); i++) { Meal currentMeal = mealList.get(i); - System.out.print((startIndex+i) + ". " + currentMeal.getName()); + System.out.println((startIndex+i) + ". " + currentMeal.getName()); } System.out.println(); } @@ -168,39 +167,39 @@ public void handleListEverything() { public static void handleEditMealServingSize(String command) { int slashIndex = command.indexOf("/"); - int mealIndex = Integer.parseInt(command.substring(20, slashIndex - 3)); + int mealIndex = Integer.parseInt(command.substring(20, slashIndex - 2)) - 1; String mealName = mealList.get(mealIndex).getName(); - int servingSize = Integer.parseInt(command.substring(slashIndex)); + int servingSize = Integer.parseInt(command.substring(slashIndex + 1)); Meal updatedMeal = new Meal(mealName, servingSize); mealList.set(mealIndex, updatedMeal); - System.out.println(mealName + "has been edited to " + servingSize + " serving(s)"); + System.out.println(mealName + " has been edited to " + servingSize + " serving(s)"); } public static void handleEditDrinkServingSize(String command) { int slashIndex = command.indexOf("/"); - int drinkIndex = Integer.parseInt(command.substring(21, slashIndex - 3)); + int drinkIndex = Integer.parseInt(command.substring(21, slashIndex - 2)) - 1; String drinkName = mealList.get(drinkIndex).getName(); - int servingSize = Integer.parseInt(command.substring(slashIndex)); + int servingSize = Integer.parseInt(command.substring(slashIndex + 1)); - Meal updatedDrink = new Drink(drinkName, servingSize); - mealList.set(drinkIndex, updatedDrink); - System.out.println(drinkName + "has been edited to " + servingSize " ml"); + Drink updatedDrink = new Drink(drinkName, servingSize); + drinkList.set(drinkIndex, updatedDrink); + System.out.println(drinkName + "has been edited to " + servingSize + " ml"); } public void handleDeleteMeal(String command) { - int mealIndex = Integer.parseInt(command.substring(11)); + int mealIndex = Integer.parseInt(command.substring(11)) - 1; String mealName = mealList.get(mealIndex).getName(); mealList.remove(mealIndex); - System.out.println("Removed " + mealName + " from Meals"); + System.out.println("Removed " + mealName + " from meals"); } public void handleDeleteDrink(String command) { - int drinkIndex = Integer.parseInt(command.substring(12)); + int drinkIndex = Integer.parseInt(command.substring(12)) - 1; String drinkName = drinkList.get(drinkIndex).getName(); drinkList.remove(drinkIndex); - System.out.println("Removed " + drinkName + " from Meals"); + System.out.println("Removed " + drinkName + " from drinks"); } public void handleClear() { From 3f69a495752bcbed151aa8d63edb67e3f8653bf3 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 15:29:15 +0800 Subject: [PATCH 028/274] Simplify input commands format --- src/main/java/seedu/duke/Parser.java | 79 ++++++++++++------------- src/main/java/seedu/duke/user/User.java | 29 ++++----- 2 files changed, 51 insertions(+), 57 deletions(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 5878756b7a..716da028ab 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -38,19 +38,19 @@ public void handleCommand(String command) { Meal.handleInfoMeal(command); } else if (command.startsWith("infoDrink")) { Drink.handleInfoDrink(command); - } else if (command.equals("viewCalories")) { + } else if (command.equals("calories")) { user.handleViewCalories(); - } else if (command.equals("viewCarbohydrates")) { + } else if (command.equals("carbs")) { user.handleViewCarbohydrates(); - } else if (command.equals("viewProtein")) { + } else if (command.equals("protein")) { user.handleViewProteins(); - } else if (command.equals("viewSugar")) { + } else if (command.equals("sugar")) { user.handleViewSugar(); - } else if (command.equals("viewFat")) { + } else if (command.equals("fat")) { user.handleViewFat(); } else if (command.equals("viewWater")) { user.handleViewWaterIntake(); - } else if (command.equals("viewFiber")) { + } else if (command.equals("fiber")) { user.handleViewFiber(); } else if (command.equals("listMeals")) { user.handleListMeals(); @@ -58,12 +58,12 @@ public void handleCommand(String command) { user.handleListDrinks(); } else if (command.equals("listEverything")) { user.handleListEverything(); - } else if (command.startsWith("editMealServingSize")) { + } else if (command.startsWith("editMeal")) { User.handleEditMealServingSize(command); - } else if (command.startsWith("editDrinkServingSize")) { + } else if (command.startsWith("editDrink")) { User.handleEditDrinkServingSize(command); - } else if (command.startsWith("editWaterIntake")) { - //handleEditWaterIntake(command); + } else if (command.startsWith("editWater")) { + //User.handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { user.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { @@ -89,28 +89,29 @@ public void handleCommand(String command) { } public static void handleHelp() { - System.out.println("Add a meal eaten: ate m/MEAL s/SERVING_SIZE"); - System.out.println("Add a drink: drink d/DRINK s/SERVING_SIZE"); - System.out.println("Add water: water s/SERVING_SIZE"); - System.out.println("Find the information about a certain meal: infoMeal MEAL"); - System.out.println("Find the information about a certain drink: infoDrink DRINK"); - System.out.println("View daily calories consumed: viewCalories"); - System.out.println("View daily carbohydrates consumed: viewCarbohydrates"); - System.out.println("View daily proteins consumed: viewProtein"); - System.out.println("View daily fat consumed: viewFat"); - System.out.println("View daily sugar consumed: viewSugar"); - System.out.println("View daily water consumption: viewWater"); - System.out.println("View daily fiber consumed: viewFiber"); - System.out.println("List meal intake: listMeals"); - System.out.println("List drink intake: listDrinks"); - System.out.println("List entire food intake for the day: listEverything"); - System.out.println("Edit an existing meal after inserted: editMealServingSize INDEX s/NEW_SERVING_SIZE"); - System.out.println("Edit an existing drink after inserted: editDrinkServingSize INDEX s/NEW_SERVING_SIZE"); - System.out.println("Edit water intake after inserted: editWaterIntake s/TOTAL_WATER_INTAKE"); - System.out.println("Delete certain meal entry: deleteMeal INDEX"); - System.out.println("Delete certain drink entry: deleteDrink INDEX"); - System.out.println("Clear all entries: clear"); - System.out.println("Exit the app: exit "); + System.out.println("here's all the valid commands i recognise: "); + System.out.println("- Add a meal eaten: ate m/MEAL s/SERVING_SIZE"); + System.out.println("- Add a drink: drink d/DRINK s/SERVING_SIZE"); + System.out.println("- Add water: water s/SERVING_SIZE"); + System.out.println("- Find the information about a certain meal: infoMeal MEAL"); + System.out.println("- Find the information about a certain drink: infoDrink DRINK"); + System.out.println("- View daily calories consumed: calories"); + System.out.println("- View daily carbohydrates consumed: carbs"); + System.out.println("- View daily proteins consumed: protein"); + System.out.println("- View daily fat consumed: fat"); + System.out.println("- View daily sugar consumed: sugar"); + System.out.println("- View daily fiber consumed: fiber"); + System.out.println("- View daily water consumption: viewWater"); + System.out.println("- List meal intake: listMeals"); + System.out.println("- List drink intake: listDrinks"); + System.out.println("- List entire food intake for the day: listEverything"); + System.out.println("- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE"); + System.out.println("- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE"); + //System.out.println("- Edit water intake after inserted: editWater s/TOTAL_WATER_INTAKE"); + System.out.println("- Delete certain meal entry: deleteMeal INDEX"); + System.out.println("- Delete certain drink entry: deleteDrink INDEX"); + System.out.println("- Clear all entries: clear"); + System.out.println("- Exit the app: exit "); } public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException { @@ -181,17 +182,15 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce } public static void parseEditMeal(String command) { - int mealSizePosition = command.indexOf("s/"); - int mealIndexPosition = 20; - editMealIndex = Integer.parseInt(command.substring(mealIndexPosition, mealSizePosition).trim()); - editMealSize = Integer.parseInt(command.substring(mealSizePosition + 2).trim()); + int mealSizePosition = command.indexOf("/"); + editMealIndex = Integer.parseInt(command.substring(9, mealSizePosition - 2).trim()) - 1; + editMealSize = Integer.parseInt(command.substring(mealSizePosition + 1).trim()); } public static void parseEditDrink(String command) { - int drinkSizePosition = command.indexOf("s/"); - int drinkIndexPosition = 21; - editDrinkIndex = Integer.parseInt(command.substring(drinkIndexPosition, drinkSizePosition).trim()); - editDrinkSize = Integer.parseInt(command.substring(drinkSizePosition + 2).trim()); + int drinkSizePosition = command.indexOf("/"); + editDrinkIndex = Integer.parseInt(command.substring(10, drinkSizePosition - 2).trim()) - 1; + editDrinkSize = Integer.parseInt(command.substring(drinkSizePosition + 1).trim()); } public static void parseEditWater(String command) { diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index af801da727..e82198191c 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -23,6 +23,7 @@ public User() { drinkList = new ArrayList<>(); totalWaterIntake = new ArrayList<>(); } + public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException { Parser.parseMeal(command); String mealName = Parser.mealDescription; @@ -48,6 +49,7 @@ public void handleWater(String command) throws IncompleteWaterException { totalWaterIntake.add(new Water(volume)); System.out.println("Added " + volume + " ml of water"); } + public void handleViewCalories() { int caloriesCount = 0; for (Meal meal: mealList) { @@ -124,7 +126,6 @@ public void printMealList(int startIndex) { Meal currentMeal = mealList.get(i); System.out.println((startIndex+i) + ". " + currentMeal.getName()); } - System.out.println(); } public void handleListMeals() { System.out.println("here's what you have eaten today"); @@ -166,25 +167,19 @@ public void handleListEverything() { } public static void handleEditMealServingSize(String command) { - int slashIndex = command.indexOf("/"); - int mealIndex = Integer.parseInt(command.substring(20, slashIndex - 2)) - 1; - String mealName = mealList.get(mealIndex).getName(); - int servingSize = Integer.parseInt(command.substring(slashIndex + 1)); - - Meal updatedMeal = new Meal(mealName, servingSize); - mealList.set(mealIndex, updatedMeal); - System.out.println(mealName + " has been edited to " + servingSize + " serving(s)"); + Parser.parseEditMeal(command); + String mealName = mealList.get(Parser.editMealIndex).getName(); + Meal updatedMeal = new Meal(mealName, Parser.editMealSize); + mealList.set(Parser.editMealIndex, updatedMeal); + System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } public static void handleEditDrinkServingSize(String command) { - int slashIndex = command.indexOf("/"); - int drinkIndex = Integer.parseInt(command.substring(21, slashIndex - 2)) - 1; - String drinkName = mealList.get(drinkIndex).getName(); - int servingSize = Integer.parseInt(command.substring(slashIndex + 1)); - - Drink updatedDrink = new Drink(drinkName, servingSize); - drinkList.set(drinkIndex, updatedDrink); - System.out.println(drinkName + "has been edited to " + servingSize + " ml"); + Parser.parseEditDrink(command); + String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); + Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize); + drinkList.set(Parser.editDrinkIndex, updatedDrink); + System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } public void handleDeleteMeal(String command) { From 77156705913e275a6d0ba46211d7f2645c349441 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:05:26 +0800 Subject: [PATCH 029/274] Add invalidIndexException --- src/main/java/seedu/duke/Meal.java | 4 ++++ src/main/java/seedu/duke/Parser.java | 3 +++ .../java/seedu/duke/exception/invalidIndexException.java | 4 ++++ src/main/java/seedu/duke/user/User.java | 8 ++++++-- 4 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/main/java/seedu/duke/exception/invalidIndexException.java diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/duke/Meal.java index 0030cdeca1..c3e35761e7 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/duke/Meal.java @@ -69,6 +69,10 @@ public int getSugar() { return sugar; } + public int getServingSize() { + return servingSize; + } + // Method to print all meal info public static void handleInfoMeal(String command) throws UnregisteredMealException { String name = Parser.parseInfoMeal(command); diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 716da028ab..f6f6daeaf3 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -85,6 +85,9 @@ public void handleCommand(String command) { System.out.println("Sorry that drink is not registered in the database."); } catch (UnregisteredMealException e) { System.out.println("Sorry that meal is not registered in the database."); + } catch (invalidIndexException e) { + System.out.println("Sorry the index you provided is invalid, check listMeals/listDrinks to view valid " + + "indexes."); } } diff --git a/src/main/java/seedu/duke/exception/invalidIndexException.java b/src/main/java/seedu/duke/exception/invalidIndexException.java new file mode 100644 index 0000000000..7356bc2443 --- /dev/null +++ b/src/main/java/seedu/duke/exception/invalidIndexException.java @@ -0,0 +1,4 @@ +package seedu.duke.exception; + +public class invalidIndexException extends Exception { +} diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index e82198191c..b991f42b2c 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -10,6 +10,7 @@ import seedu.duke.exception.IncompleteWaterException; import seedu.duke.exception.UnregisteredDrinkException; import seedu.duke.exception.UnregisteredMealException; +import seedu.duke.exception.invalidIndexException; import java.util.ArrayList; @@ -91,7 +92,7 @@ public void handleViewWaterIntake() { System.out.println("Total water intake: " + waterIntake + " ml"); } - public void handleViewFiber() { + public static void handleViewFiber() { int fibreCount = 0; for (Meal meal: mealList) { fibreCount += meal.getFiber(); @@ -174,8 +175,11 @@ public static void handleEditMealServingSize(String command) { System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } - public static void handleEditDrinkServingSize(String command) { + public static void handleEditDrinkServingSize(String command) throws invalidIndexException { Parser.parseEditDrink(command); + if (Parser.editDrinkIndex >= drinkList.size()) { + throw new invalidIndexException(); + } String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize); drinkList.set(Parser.editDrinkIndex, updatedDrink); From ff86106ebeedb143be1d50115e78d4da5c087baa Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:05:51 +0800 Subject: [PATCH 030/274] Add JUnit test for some user class methods --- src/test/java/seedu/duke/user/UserTest.java | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/test/java/seedu/duke/user/UserTest.java diff --git a/src/test/java/seedu/duke/user/UserTest.java b/src/test/java/seedu/duke/user/UserTest.java new file mode 100644 index 0000000000..791044e8a7 --- /dev/null +++ b/src/test/java/seedu/duke/user/UserTest.java @@ -0,0 +1,48 @@ +package seedu.duke.user; + +import org.junit.jupiter.api.Test; +import seedu.duke.Drink; +import seedu.duke.Meal; +import seedu.duke.Parser; +import seedu.duke.Water; +import seedu.duke.exception.IncompleteMealException; +import seedu.duke.exception.IncompleteWaterException; +import seedu.duke.exception.UnregisteredMealException; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class UserTest { + ArrayList testMealList = new ArrayList<>(); + ArrayList testDrinkList = new ArrayList<>(); + + @Test + public void sampleUser() { + assertTrue(true); + } + + @Test + public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException { + Meal newMeal = new Meal("pizza", 3); + testMealList.add(newMeal); + + assertEquals("pizza", testMealList.get(0).getName()); + assertEquals(3, testMealList.get(0).getServingSize()); + } + + @Test + public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWaterException { + try { + Parser.parseWater("water 1"); + new Water(Parser.waterSize); + } catch (IncompleteWaterException e) { + return; + } + + String error = "Incomplete command, the format must be [water s/SERVING_SIZE]."; + fail(error); + } +} From dbab4717581b5afa377a2771108f2af2fa3fb64a Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:16:33 +0800 Subject: [PATCH 031/274] Add assertions to User class --- src/main/java/seedu/duke/Parser.java | 1 + src/main/java/seedu/duke/user/User.java | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index f6f6daeaf3..184303015b 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -6,6 +6,7 @@ import seedu.duke.exception.InvalidCommandException; import seedu.duke.exception.UnregisteredDrinkException; import seedu.duke.exception.UnregisteredMealException; +import seedu.duke.exception.invalidIndexException; import seedu.duke.user.User; public class Parser { diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/duke/user/User.java index b991f42b2c..dec51c1d09 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/duke/user/User.java @@ -31,6 +31,8 @@ public void handleMeal(String command) throws IncompleteMealException, Unregiste int servingSize = Parser.mealSize; mealList.add(new Meal(mealName, servingSize)); + assert !mealList.isEmpty(): "failed to add meal"; + System.out.println("Added " + servingSize + " serving of " + mealName); } @@ -46,6 +48,7 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis public void handleWater(String command) throws IncompleteWaterException { Parser.parseWater(command); int volume = Parser.waterSize; + assert volume > 0: "invalid volume"; totalWaterIntake.add(new Water(volume)); System.out.println("Added " + volume + " ml of water"); @@ -167,8 +170,13 @@ public void handleListEverything() { } } - public static void handleEditMealServingSize(String command) { + public static void handleEditMealServingSize(String command) throws invalidIndexException{ Parser.parseEditMeal(command); + assert Parser.editMealIndex != 0: "meal index out of bounds"; + if (Parser.editMealIndex >= mealList.size()) { + throw new invalidIndexException(); + } + String mealName = mealList.get(Parser.editMealIndex).getName(); Meal updatedMeal = new Meal(mealName, Parser.editMealSize); mealList.set(Parser.editMealIndex, updatedMeal); @@ -177,6 +185,8 @@ public static void handleEditMealServingSize(String command) { public static void handleEditDrinkServingSize(String command) throws invalidIndexException { Parser.parseEditDrink(command); + assert Parser.editDrinkIndex != 0: "drink index out of bounds"; + if (Parser.editDrinkIndex >= drinkList.size()) { throw new invalidIndexException(); } @@ -188,14 +198,15 @@ public static void handleEditDrinkServingSize(String command) throws invalidInde public void handleDeleteMeal(String command) { int mealIndex = Integer.parseInt(command.substring(11)) - 1; + assert mealIndex >= 0: "meal index out of bounds"; String mealName = mealList.get(mealIndex).getName(); mealList.remove(mealIndex); - System.out.println("Removed " + mealName + " from meals"); } public void handleDeleteDrink(String command) { int drinkIndex = Integer.parseInt(command.substring(12)) - 1; + assert drinkIndex >= 0: "drink index out of bounds"; String drinkName = drinkList.get(drinkIndex).getName(); drinkList.remove(drinkIndex); System.out.println("Removed " + drinkName + " from drinks"); @@ -204,6 +215,9 @@ public void handleDeleteDrink(String command) { public void handleClear() { mealList.clear(); drinkList.clear(); + assert mealList.isEmpty(): "clearing of meal list failed"; + assert drinkList.isEmpty(): "clearing of drink list failed"; + System.out.println("All entries have been deleted"); } From 52e64c7963ff9cdf114b957c9e9df2f9a25746ea Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:33:17 +0800 Subject: [PATCH 032/274] Reorganise and rebuild project for FitNus to be main class --- build.gradle | 4 +-- src/main/java/seedu/duke/Duke.java | 21 --------------- .../seedu/{duke => fitnus}/CSVReader.java | 2 +- .../java/seedu/{duke => fitnus}/Drink.java | 4 +-- .../java/seedu/{duke => fitnus}/FitNus.java | 4 +-- .../java/seedu/{duke => fitnus}/Meal.java | 4 +-- .../java/seedu/{duke => fitnus}/Parser.java | 18 ++++++------- src/main/java/seedu/{duke => fitnus}/Ui.java | 2 +- .../java/seedu/{duke => fitnus}/Water.java | 2 +- .../exception/IncompleteDrinkException.java | 2 +- .../exception/IncompleteMealException.java | 2 +- .../exception/IncompleteWaterException.java | 2 +- .../exception/InvalidCommandException.java | 2 +- .../exception/UnregisteredDrinkException.java | 2 +- .../exception/UnregisteredMealException.java | 2 +- .../exception/invalidIndexException.java | 2 +- .../seedu/{duke => fitnus}/user/User.java | 26 +++++++++---------- src/test/java/seedu/duke/DukeTest.java | 12 --------- .../seedu/{duke => fitnus}/user/UserTest.java | 16 ++++++------ 19 files changed, 47 insertions(+), 82 deletions(-) delete mode 100644 src/main/java/seedu/duke/Duke.java rename src/main/java/seedu/{duke => fitnus}/CSVReader.java (97%) rename src/main/java/seedu/{duke => fitnus}/Drink.java (96%) rename src/main/java/seedu/{duke => fitnus}/FitNus.java (94%) rename src/main/java/seedu/{duke => fitnus}/Meal.java (97%) rename src/main/java/seedu/{duke => fitnus}/Parser.java (95%) rename src/main/java/seedu/{duke => fitnus}/Ui.java (98%) rename src/main/java/seedu/{duke => fitnus}/Water.java (90%) rename src/main/java/seedu/{duke => fitnus}/exception/IncompleteDrinkException.java (65%) rename src/main/java/seedu/{duke => fitnus}/exception/IncompleteMealException.java (64%) rename src/main/java/seedu/{duke => fitnus}/exception/IncompleteWaterException.java (65%) rename src/main/java/seedu/{duke => fitnus}/exception/InvalidCommandException.java (64%) rename src/main/java/seedu/{duke => fitnus}/exception/UnregisteredDrinkException.java (65%) rename src/main/java/seedu/{duke => fitnus}/exception/UnregisteredMealException.java (65%) rename src/main/java/seedu/{duke => fitnus}/exception/invalidIndexException.java (64%) rename src/main/java/seedu/{duke => fitnus}/user/User.java (93%) delete mode 100644 src/test/java/seedu/duke/DukeTest.java rename src/test/java/seedu/{duke => fitnus}/user/UserTest.java (79%) diff --git a/build.gradle b/build.gradle index ea82051fab..80848df2f1 100644 --- a/build.gradle +++ b/build.gradle @@ -29,11 +29,11 @@ test { } application { - mainClass.set("seedu.duke.Duke") + mainClass.set("seedu.fitnus.FitNus") } shadowJar { - archiveBaseName.set("duke") + archiveBaseName.set("fitnus") archiveClassifier.set("") } 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/duke/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java similarity index 97% rename from src/main/java/seedu/duke/CSVReader.java rename to src/main/java/seedu/fitnus/CSVReader.java index c507dae88f..38a77e7b38 100644 --- a/src/main/java/seedu/duke/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.fitnus; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; diff --git a/src/main/java/seedu/duke/Drink.java b/src/main/java/seedu/fitnus/Drink.java similarity index 96% rename from src/main/java/seedu/duke/Drink.java rename to src/main/java/seedu/fitnus/Drink.java index 3c3bffb7ce..3492de33ae 100644 --- a/src/main/java/seedu/duke/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -1,6 +1,6 @@ -package seedu.duke; +package seedu.fitnus; -import seedu.duke.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredDrinkException; import java.util.HashMap; public class Drink { diff --git a/src/main/java/seedu/duke/FitNus.java b/src/main/java/seedu/fitnus/FitNus.java similarity index 94% rename from src/main/java/seedu/duke/FitNus.java rename to src/main/java/seedu/fitnus/FitNus.java index 2b678164eb..53372a00e1 100644 --- a/src/main/java/seedu/duke/FitNus.java +++ b/src/main/java/seedu/fitnus/FitNus.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.fitnus; public class FitNus { @@ -19,6 +19,4 @@ public void run() { public static void main(String[] args) { new FitNus().run(); } - - } diff --git a/src/main/java/seedu/duke/Meal.java b/src/main/java/seedu/fitnus/Meal.java similarity index 97% rename from src/main/java/seedu/duke/Meal.java rename to src/main/java/seedu/fitnus/Meal.java index c3e35761e7..8a48066d30 100644 --- a/src/main/java/seedu/duke/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -1,6 +1,6 @@ -package seedu.duke; +package seedu.fitnus; -import seedu.duke.exception.UnregisteredMealException; +import seedu.fitnus.exception.UnregisteredMealException; import java.util.HashMap; diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/fitnus/Parser.java similarity index 95% rename from src/main/java/seedu/duke/Parser.java rename to src/main/java/seedu/fitnus/Parser.java index 184303015b..18e0f19e11 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -1,13 +1,13 @@ -package seedu.duke; +package seedu.fitnus; -import seedu.duke.exception.IncompleteDrinkException; -import seedu.duke.exception.IncompleteMealException; -import seedu.duke.exception.IncompleteWaterException; -import seedu.duke.exception.InvalidCommandException; -import seedu.duke.exception.UnregisteredDrinkException; -import seedu.duke.exception.UnregisteredMealException; -import seedu.duke.exception.invalidIndexException; -import seedu.duke.user.User; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.IncompleteWaterException; +import seedu.fitnus.exception.InvalidCommandException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.invalidIndexException; +import seedu.fitnus.user.User; public class Parser { public static String mealDescription; diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/fitnus/Ui.java similarity index 98% rename from src/main/java/seedu/duke/Ui.java rename to src/main/java/seedu/fitnus/Ui.java index 537cab35ed..78eb6f9615 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.fitnus; import java.util.Scanner; diff --git a/src/main/java/seedu/duke/Water.java b/src/main/java/seedu/fitnus/Water.java similarity index 90% rename from src/main/java/seedu/duke/Water.java rename to src/main/java/seedu/fitnus/Water.java index b8bcb73964..5c481c8379 100644 --- a/src/main/java/seedu/duke/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.fitnus; public class Water { private int waterIntake; diff --git a/src/main/java/seedu/duke/exception/IncompleteDrinkException.java b/src/main/java/seedu/fitnus/exception/IncompleteDrinkException.java similarity index 65% rename from src/main/java/seedu/duke/exception/IncompleteDrinkException.java rename to src/main/java/seedu/fitnus/exception/IncompleteDrinkException.java index f65e9eb7b0..8bbd175165 100644 --- a/src/main/java/seedu/duke/exception/IncompleteDrinkException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteDrinkException.java @@ -1,4 +1,4 @@ -package seedu.duke.exception; +package seedu.fitnus.exception; public class IncompleteDrinkException extends Exception{ } diff --git a/src/main/java/seedu/duke/exception/IncompleteMealException.java b/src/main/java/seedu/fitnus/exception/IncompleteMealException.java similarity index 64% rename from src/main/java/seedu/duke/exception/IncompleteMealException.java rename to src/main/java/seedu/fitnus/exception/IncompleteMealException.java index 15965cc126..36cecf5d8e 100644 --- a/src/main/java/seedu/duke/exception/IncompleteMealException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteMealException.java @@ -1,4 +1,4 @@ -package seedu.duke.exception; +package seedu.fitnus.exception; public class IncompleteMealException extends Exception{ } diff --git a/src/main/java/seedu/duke/exception/IncompleteWaterException.java b/src/main/java/seedu/fitnus/exception/IncompleteWaterException.java similarity index 65% rename from src/main/java/seedu/duke/exception/IncompleteWaterException.java rename to src/main/java/seedu/fitnus/exception/IncompleteWaterException.java index 29804d6ff9..c1df973172 100644 --- a/src/main/java/seedu/duke/exception/IncompleteWaterException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteWaterException.java @@ -1,4 +1,4 @@ -package seedu.duke.exception; +package seedu.fitnus.exception; public class IncompleteWaterException extends Exception{ } diff --git a/src/main/java/seedu/duke/exception/InvalidCommandException.java b/src/main/java/seedu/fitnus/exception/InvalidCommandException.java similarity index 64% rename from src/main/java/seedu/duke/exception/InvalidCommandException.java rename to src/main/java/seedu/fitnus/exception/InvalidCommandException.java index 8f9584c8f5..957702a9ea 100644 --- a/src/main/java/seedu/duke/exception/InvalidCommandException.java +++ b/src/main/java/seedu/fitnus/exception/InvalidCommandException.java @@ -1,4 +1,4 @@ -package seedu.duke.exception; +package seedu.fitnus.exception; public class InvalidCommandException extends Exception{ } diff --git a/src/main/java/seedu/duke/exception/UnregisteredDrinkException.java b/src/main/java/seedu/fitnus/exception/UnregisteredDrinkException.java similarity index 65% rename from src/main/java/seedu/duke/exception/UnregisteredDrinkException.java rename to src/main/java/seedu/fitnus/exception/UnregisteredDrinkException.java index 0b2850d9f3..92c1e52f28 100644 --- a/src/main/java/seedu/duke/exception/UnregisteredDrinkException.java +++ b/src/main/java/seedu/fitnus/exception/UnregisteredDrinkException.java @@ -1,4 +1,4 @@ -package seedu.duke.exception; +package seedu.fitnus.exception; public class UnregisteredDrinkException extends Exception{ } diff --git a/src/main/java/seedu/duke/exception/UnregisteredMealException.java b/src/main/java/seedu/fitnus/exception/UnregisteredMealException.java similarity index 65% rename from src/main/java/seedu/duke/exception/UnregisteredMealException.java rename to src/main/java/seedu/fitnus/exception/UnregisteredMealException.java index 627cb7dacb..0748dbb1a8 100644 --- a/src/main/java/seedu/duke/exception/UnregisteredMealException.java +++ b/src/main/java/seedu/fitnus/exception/UnregisteredMealException.java @@ -1,4 +1,4 @@ -package seedu.duke.exception; +package seedu.fitnus.exception; public class UnregisteredMealException extends Exception{ } diff --git a/src/main/java/seedu/duke/exception/invalidIndexException.java b/src/main/java/seedu/fitnus/exception/invalidIndexException.java similarity index 64% rename from src/main/java/seedu/duke/exception/invalidIndexException.java rename to src/main/java/seedu/fitnus/exception/invalidIndexException.java index 7356bc2443..e71e8dd434 100644 --- a/src/main/java/seedu/duke/exception/invalidIndexException.java +++ b/src/main/java/seedu/fitnus/exception/invalidIndexException.java @@ -1,4 +1,4 @@ -package seedu.duke.exception; +package seedu.fitnus.exception; public class invalidIndexException extends Exception { } diff --git a/src/main/java/seedu/duke/user/User.java b/src/main/java/seedu/fitnus/user/User.java similarity index 93% rename from src/main/java/seedu/duke/user/User.java rename to src/main/java/seedu/fitnus/user/User.java index dec51c1d09..318e37136d 100644 --- a/src/main/java/seedu/duke/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -1,16 +1,16 @@ -package seedu.duke.user; +package seedu.fitnus.user; -import seedu.duke.Drink; -import seedu.duke.Meal; -import seedu.duke.Parser; -import seedu.duke.Water; +import seedu.fitnus.Drink; +import seedu.fitnus.Meal; +import seedu.fitnus.Parser; +import seedu.fitnus.Water; -import seedu.duke.exception.IncompleteDrinkException; -import seedu.duke.exception.IncompleteMealException; -import seedu.duke.exception.IncompleteWaterException; -import seedu.duke.exception.UnregisteredDrinkException; -import seedu.duke.exception.UnregisteredMealException; -import seedu.duke.exception.invalidIndexException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.IncompleteWaterException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.invalidIndexException; import java.util.ArrayList; @@ -170,7 +170,7 @@ public void handleListEverything() { } } - public static void handleEditMealServingSize(String command) throws invalidIndexException{ + public static void handleEditMealServingSize(String command) throws invalidIndexException { Parser.parseEditMeal(command); assert Parser.editMealIndex != 0: "meal index out of bounds"; if (Parser.editMealIndex >= mealList.size()) { @@ -217,7 +217,7 @@ public void handleClear() { drinkList.clear(); assert mealList.isEmpty(): "clearing of meal list failed"; assert drinkList.isEmpty(): "clearing of drink list failed"; - + System.out.println("All entries have been deleted"); } 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/duke/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java similarity index 79% rename from src/test/java/seedu/duke/user/UserTest.java rename to src/test/java/seedu/fitnus/user/UserTest.java index 791044e8a7..f6bf8ebf66 100644 --- a/src/test/java/seedu/duke/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -1,13 +1,13 @@ -package seedu.duke.user; +package seedu.fitnus.user; import org.junit.jupiter.api.Test; -import seedu.duke.Drink; -import seedu.duke.Meal; -import seedu.duke.Parser; -import seedu.duke.Water; -import seedu.duke.exception.IncompleteMealException; -import seedu.duke.exception.IncompleteWaterException; -import seedu.duke.exception.UnregisteredMealException; +import seedu.fitnus.Drink; +import seedu.fitnus.Meal; +import seedu.fitnus.Parser; +import seedu.fitnus.Water; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.IncompleteWaterException; +import seedu.fitnus.exception.UnregisteredMealException; import java.util.ArrayList; From fcc28da2c1659ffa4b57bf7e35b13d45e080a46e Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:33:33 +0800 Subject: [PATCH 033/274] Add text-ui-text test for FitNus --- text-ui-test/EXPECTED.TXT | 18 +++++++++--------- text-ui-test/input.txt | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 892cb6cae7..9c89a00092 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,9 +1,9 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| - -What is your name? -Hello James Gosling +_________________________________________________________________ +Hello! Welcome to FitNUS +What would you like to track today? +Available meals: pizza, chicken rice, fried rice, etc. +Available drinks: lemon tea, sprite, milk coffee, etc. +_________________________________________________________________ +_________________________________________________________________ +Bye. Hope to see you again soon! +_________________________________________________________________ \ No newline at end of file diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index f6ec2e9f95..ae3bc0a936 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1 +1 @@ -James Gosling \ No newline at end of file +exit \ No newline at end of file From 9d381b7fc89458b026ec7b49fb1a45f51e6c3fc6 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:41:37 +0800 Subject: [PATCH 034/274] Update input.txt and EXPECTED.txt --- text-ui-test/EXPECTED.TXT | 12 +++++++++++- text-ui-test/input.txt | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 9c89a00092..22c82f21f7 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -5,5 +5,15 @@ Available meals: pizza, chicken rice, fried rice, etc. Available drinks: lemon tea, sprite, milk coffee, etc. _________________________________________________________________ _________________________________________________________________ +Invalid command, type [help] to view all commands. +_________________________________________________________________ +_________________________________________________________________ +Added 2 serving of chicken rice +_________________________________________________________________ +_________________________________________________________________ +here's what you have eaten today +1. chicken rice +_________________________________________________________________ +_________________________________________________________________ Bye. Hope to see you again soon! -_________________________________________________________________ \ No newline at end of file +_________________________________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index ae3bc0a936..d85f9017a1 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1 +1,4 @@ +add m/chicken rice s/2 +ate m/chicken rice s/2 +listMeals exit \ No newline at end of file From 1520e1ba94b8c100d0a76343d1e428a118fc393c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:42:16 +0800 Subject: [PATCH 035/274] Add files for ios/ubuntu ui test --- text-ui-test/ACTUAL-SH.TXT | 0 text-ui-test/EXPECTED-SH.TXT | 0 text-ui-test/runtest.sh | 7 +++---- 3 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 text-ui-test/ACTUAL-SH.TXT create mode 100644 text-ui-test/EXPECTED-SH.TXT diff --git a/text-ui-test/ACTUAL-SH.TXT b/text-ui-test/ACTUAL-SH.TXT new file mode 100644 index 0000000000..e69de29bb2 diff --git a/text-ui-test/EXPECTED-SH.TXT b/text-ui-test/EXPECTED-SH.TXT new file mode 100644 index 0000000000..e69de29bb2 diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh index 1dcbd12021..c11c98e2e6 100755 --- a/text-ui-test/runtest.sh +++ b/text-ui-test/runtest.sh @@ -8,11 +8,10 @@ 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-SH.TXT + +diff EXPECTED-SH.TXT ACTUAL-SH.TXT -cp EXPECTED.TXT EXPECTED-UNIX.TXT -dos2unix EXPECTED-UNIX.TXT ACTUAL.TXT -diff EXPECTED-UNIX.TXT ACTUAL.TXT if [ $? -eq 0 ] then echo "Test passed!" From 036df9c0f97aa0743ffc4314e2074d9904edfc12 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 22:54:23 +0800 Subject: [PATCH 036/274] Update README with 4 commands --- docs/README.md | 52 ++++++++++++++++++++++++++++++++++++++++++----- docs/UserGuide.md | 41 ------------------------------------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2244f8b22c..12e4433fad 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,50 @@ # FitNUS -{Give product intro here} +## 1) Features List +### 1.1 Information for users +### 1.1.1 Viewing all commands:** `help` +Shows a list of all possible command inputs. +**Format**: help +**Sample Input**: help +**Expected Output**: +here's all the valid commands i recognise: +- Add a meal eaten: ate m/MEAL s/SERVING_SIZE +- Add a drink: drink d/DRINK s/SERVING_SIZE +- Add water: water s/SERVING_SIZE +- Find the information about a certain meal: infoMeal MEAL +- Find the information about a certain drink: infoDrink DRINK +- View daily calories consumed: calories +- View daily carbohydrates consumed: carbs +- View daily proteins consumed: protein +- View daily fat consumed: fat +- View daily sugar consumed: sugar +- View daily fiber consumed: fiber +- View daily water consumption: viewWater +- List meal intake: listMeals +- List drink intake: listDrinks +- List entire food intake for the day: listEverything +- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE +- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE +- Delete certain meal entry: deleteMeal INDEX +- Delete certain drink entry: deleteDrink INDEX +- Clear all entries: clear +- Exit the app: exit -Useful links: -* [User Guide](UserGuide.md) -* [Developer Guide](DeveloperGuide.md) -* [About Us](AboutUs.md) +### 1.2 For user to add data +### 1.2.1 Add a meal eaten: `ate` +Adds a meal to the list of meals +**Format**: ate m/MEAL s/SERVING_SIZE +**Sample Input**: ate m/Chicken Rice s/1 +**Expected Output**: Added 1 serving of Chicken Rice + +### 1.2.2 Add a drink: `drink` +Adds a drink to the list of drinks +**Format**: drink d/DRINK s/SERVING_SIZE +**Sample Input**: drink d/Lemon Tea s/100 +**Expected Output**: Added 100ml of Lemon Tea + +### 1.2.3 Add water: `water` +Adds water (in ml) to the daily water intake count +**Format**: water s/SERVING_SIZE +**Sample Input**: water s/200 +**Expected Output**: Added 200ml of water diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..cd3d452278 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,42 +1 @@ # User Guide - -## Introduction - -{Give a product intro} - -## Quick Start - -{Give steps to get started quickly} - -1. Ensure that you have Java 11 or above installed. -1. Down the latest version of `Duke` from [here](http://link.to/duke). - -## Features - -{Give detailed description of each feature} - -### Adding a todo: `todo` -Adds a new item to the list of todo items. - -Format: `todo n/TODO_NAME d/DEADLINE` - -* The `DEADLINE` can be in a natural language format. -* The `TODO_NAME` cannot contain punctuation. - -Example of usage: - -`todo n/Write the rest of the User Guide d/next week` - -`todo n/Refactor the User Guide to remove passive voice d/13/04/2020` - -## FAQ - -**Q**: How do I transfer my data to another computer? - -**A**: {your answer here} - -## Command Summary - -{Give a 'cheat sheet' of commands here} - -* Add todo `todo n/TODO_NAME d/DEADLINE` From 8ea46928433f231a4d877fbbd911408e8e4deda0 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 23:05:29 +0800 Subject: [PATCH 037/274] Update .txt files for mac/ubuntu --- text-ui-test/ACTUAL-SH.TXT | 19 +++++++++++++++++++ text-ui-test/EXPECTED-SH.TXT | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/text-ui-test/ACTUAL-SH.TXT b/text-ui-test/ACTUAL-SH.TXT index e69de29bb2..22c82f21f7 100644 --- a/text-ui-test/ACTUAL-SH.TXT +++ b/text-ui-test/ACTUAL-SH.TXT @@ -0,0 +1,19 @@ +_________________________________________________________________ +Hello! Welcome to FitNUS +What would you like to track today? +Available meals: pizza, chicken rice, fried rice, etc. +Available drinks: lemon tea, sprite, milk coffee, etc. +_________________________________________________________________ +_________________________________________________________________ +Invalid command, type [help] to view all commands. +_________________________________________________________________ +_________________________________________________________________ +Added 2 serving of chicken rice +_________________________________________________________________ +_________________________________________________________________ +here's what you have eaten today +1. chicken rice +_________________________________________________________________ +_________________________________________________________________ +Bye. Hope to see you again soon! +_________________________________________________________________ diff --git a/text-ui-test/EXPECTED-SH.TXT b/text-ui-test/EXPECTED-SH.TXT index e69de29bb2..22c82f21f7 100644 --- a/text-ui-test/EXPECTED-SH.TXT +++ b/text-ui-test/EXPECTED-SH.TXT @@ -0,0 +1,19 @@ +_________________________________________________________________ +Hello! Welcome to FitNUS +What would you like to track today? +Available meals: pizza, chicken rice, fried rice, etc. +Available drinks: lemon tea, sprite, milk coffee, etc. +_________________________________________________________________ +_________________________________________________________________ +Invalid command, type [help] to view all commands. +_________________________________________________________________ +_________________________________________________________________ +Added 2 serving of chicken rice +_________________________________________________________________ +_________________________________________________________________ +here's what you have eaten today +1. chicken rice +_________________________________________________________________ +_________________________________________________________________ +Bye. Hope to see you again soon! +_________________________________________________________________ From dc6990320e1dd8c5f26944cf3d85959016a43268 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 23:34:48 +0800 Subject: [PATCH 038/274] Update List to show serving size --- src/main/java/seedu/fitnus/Parser.java | 2 +- src/main/java/seedu/fitnus/user/User.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 18e0f19e11..048c613fcf 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -182,7 +182,7 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce if (!Meal.getNutrientDetails().containsKey(infoDrinkDescription)) { throw new UnregisteredDrinkException(); } - return command.substring(drinkIndex).trim(); + return infoDrinkDescription; } public static void parseEditMeal(String command) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 318e37136d..674349ac6e 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -128,7 +128,8 @@ public void handleViewSugar() { public void printMealList(int startIndex) { for (int i = 0; i < mealList.size(); i++) { Meal currentMeal = mealList.get(i); - System.out.println((startIndex+i) + ". " + currentMeal.getName()); + System.out.println((startIndex+i) + ". " + currentMeal.getName() + " (serving size: " + + currentMeal.getServingSize() + ")"); } } public void handleListMeals() { @@ -143,7 +144,8 @@ public void handleListMeals() { public void printDrinkList(int startIndex) { for (int i = 0; i < drinkList.size(); i++) { Drink currentDrink = drinkList.get(i); - System.out.print((startIndex+i) + ". " + currentDrink.getName()); + System.out.print((startIndex+i) + ". " + currentDrink.getName() + " (serving size: " + + currentDrink.getDrinkVolumeSize() + ")"); } } From 938e958322388094d177424949093dc56c88187e Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 23:35:05 +0800 Subject: [PATCH 039/274] Enable assertions in build.gradle --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 80848df2f1..3451227b3b 100644 --- a/build.gradle +++ b/build.gradle @@ -43,4 +43,5 @@ checkstyle { run{ standardInput = System.in + enableAssertions = true } From af78f66b35c885f730e9c871794fd2e1ffd69e30 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 23:45:30 +0800 Subject: [PATCH 040/274] Update README file --- README.md | 283 +++++++++++++++++----- docs/README.md | 169 +++++++++++++ docs/UserGuide.md | 220 ++++++++++++++++- src/main/java/seedu/fitnus/user/User.java | 2 +- 4 files changed, 608 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index f82e2494b7..ed30464514 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,219 @@ -# Duke project template - -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. - -## Setting up in Intellij - -Prerequisites: JDK 11 (use the exact version), update Intellij to the most recent version. - -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: - ``` - > Task :compileJava - > Task :processResources NO-SOURCE - > Task :classes - - > Task :Duke.main() - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - - What is your name? - ``` - Type some word and press enter to let the execution proceed to the end. - -## Build automation using Gradle - -* This project uses Gradle for build automation and dependency management. It includes a basic build script as well (i.e. the `build.gradle` file). -* If you are new to Gradle, refer to the [Gradle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/gradle.html). - -## Testing - -### I/O redirection tests - -* To run _I/O redirection_ tests (aka _Text UI tests_), navigate to the `text-ui-test` and run the `runtest(.bat/.sh)` script. - -### JUnit tests - -* 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 - -* A sample CheckStyle rule configuration is provided in this project. -* If you are new to Checkstyle, refer to the [Checkstyle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/checkstyle.html). - -## CI using GitHub Actions - -The project uses [GitHub actions](https://github.com/features/actions) for CI. When you push a commit to this repo or PR against it, GitHub actions will run automatically to build and verify the code as updated by the commit/PR. - -## Documentation - -`/docs` folder contains a skeleton version of the project documentation. - -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. -1. Scroll down to the `GitHub Pages` section. -1. Set the `source` as `master branch /docs folder`. -1. Optionally, use the `choose a theme` button to choose a theme for your documentation. +# FitNUS +## Project Introduction +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Promote healthy lifestyle. + +Users are able to track the meals and drinks they have in a day. + +## Table of Contents + +[1) Features List](#1-features-list) +* [1.1 Information for users](#11-information-for-users) + * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help-) +* [1.2 For user to add data](#12-for-user-to-add-data) + * [1.2.1 Add a meal eaten: `ate`](#121-add-a-meal-eaten-ate) + * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) + * [1.2.3 Add water: `water`](#123-add-water-water) +* [1.3 For data retrieval](#13-for-data-retrieval) + * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) + * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) + * [1.3.3 View daily calories consumed: `calories`](#133-view-daily-calories-consumed-calories) + * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-carbohydrates-consumed-carbs) + * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-proteins-consumed-protein) + * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-fat-consumed-fat) + * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-sugar-consumed-sugar) + * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-fiber-consumed-fiber) + * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-water-consumption-viewwater) +* [1.4 For listing arrays](#14-for-listing-arrays) + * [1.4.1 List meal intake: `listMeals`](#141-list-meal-intake-listmeals) + * [1.4.2 List drink intake: `listDrinks`](#142-list-drink-intake-listdrinks) + * [1.4.3 List entire food intake for the day: `listEverything`](#143-list-entire-food-intake-for-the-day-listeverything) +* [1.5 For editing existing data](#15-for-editing-existing-data) + * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) + * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) + * [1.5.3 Edit water intake after inserted: `editWater`](#153-edit-water-intake-after-inserted-editwater) +* [1.6 For deleting data](#16-for-deleting-data) + * [1.6.1 Delete certain meal entry: `deleteMeal`](#161-delete-certain-meal-entry-deletemeal) + * [1.6.2 Delete certain drink entry: `deleteDrink`](#162-delete-certain-drink-entry-deletedrink) +* [1.7 For clearing data](#17-for-clearing-data-) + * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) +* [1.8: Exit program](#18-exit-program) + * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) + + +## 1) Features List +### 1.1 Information for users +### 1.1.1 Viewing all commands:** `help` +Shows a list of all possible command inputs. +**Format**: help +**Sample Input**: help +**Expected Output**: +here's all the valid commands i recognise: +- Add a meal eaten: ate m/MEAL s/SERVING_SIZE +- Add a drink: drink d/DRINK s/SERVING_SIZE +- Add water: water s/SERVING_SIZE +- Find the information about a certain meal: infoMeal MEAL +- Find the information about a certain drink: infoDrink DRINK +- View daily calories consumed: calories +- View daily carbohydrates consumed: carbs +- View daily proteins consumed: protein +- View daily fat consumed: fat +- View daily sugar consumed: sugar +- View daily fiber consumed: fiber +- View daily water consumption: viewWater +- List meal intake: listMeals +- List drink intake: listDrinks +- List entire food intake for the day: listEverything +- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE +- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE +- Delete certain meal entry: deleteMeal INDEX +- Delete certain drink entry: deleteDrink INDEX +- Clear all entries: clear +- Exit the app: exit + +### 1.2 For user to add data +### 1.2.1 Add a meal eaten: `ate` +Adds a meal to the list of meals +**Format**: ate m/MEAL s/SERVING_SIZE +**Sample Input**: ate m/Chicken Rice s/1 +**Expected Output**: Added 1 serving of Chicken Rice + +### 1.2.2 Add a drink: `drink` +Adds a drink to the list of drinks +**Format**: drink d/DRINK s/SERVING_SIZE +**Sample Input**: drink d/Lemon Tea s/100 +**Expected Output**: Added 100ml of Lemon Tea + +### 1.2.3 Add water: `water` +Adds water (in ml) to the daily water intake count +**Format**: water s/SERVING_SIZE +**Sample Input**: water s/200 +**Expected Output**: Added 200ml of water + +## 1.3 For data retrieval +### 1.3.1 Find the information about a certain meal: `infoMeal` +For the specified meal, display its nutritional content to the user +**Format**: infoMeal MEAL +**Sample Input**: infoMeal chicken rice +**Expected Output**: +Meal: chicken rice (per serving) +Calories: 400 +Carbs: 50 +Protein: 30 +Fat: 20 +Fiber: 10 +Sugar: 5 + +### 1.3.2 Find the information about a certain drink: `infoDrink` +For the inputed drink, display its nutritional content to the user +**Format**: infoDrink DRINK +**Sample input**: infoDrink sprite +**Expected output**: +SPRITE (473 ml) +Calories: 194 kcal +Carbs: 50g +Protein: 0.2g +Fat: 0.1g + +### 1.3.3 View daily calories consumed: `calories` +Display current total calorie intake for the day +**Format**: calories +**Expected output**: Total calories: 100 cal + +### 1.3.4 View daily carbohydrates consumed: `carbs` +Display current total carbohydrates intake for the day +**Format**: carbs +**Expected output**: Total Carbohydrates: 150 grams + +### 1.3.5 View daily proteins consumed: `protein` +Display current total protein intake for the day +**Format**: protein +**Expected output**: Total proteins: 100 grams + +### 1.3.6 View daily fat consumed: `fat` +Display current total fat intake for the day +**Format**: fat +**Expected output**: Total fat: 50 grams + +### 1.3.7 View daily sugar consumed: `sugar` +Display current total sugar intake for the day +**Format**: sugar +**Expected output**: Total sugar: 20 grams + +### 1.3.8 View daily fiber consumed: `fiber` +Display current total fiber intake (g) for the day +**Format**: viewFiber +**Expected output**: Total fiber: 20 grams + +### 1.3.9 View daily water consumption: `viewWater` +Display current total water intake (in ml) for the day +**Format**: viewWater +**Expected output**: Total water intake: 0 ml + +## 1.4 For listing arrays +### 1.4.1 List meal intake: `listMeals` +List all the meals user inputted today +**Format**: listMeals +**Expected output**: +here's what you have eaten today +1.pizza (serving size: 1) + +### 1.4.2 List drink intake: `listDrinks` +List all the drinks user inputted today +**Format**: listDrinks +**Expected output**: +here's what you have drank today +1.sprite (serving size: 1) +Total water intake: 0 ml + +### 1.4.3 List entire food intake for the day: `listEverything` +List all the drinks and meals inputted today +**Format**: listEverything +**Expected output**: +here's what you have consumed today +1.pizza (serving size: 1) +2.sprite (serving size: 1) +Total water intake: 0 ml + +## 1.5 For editing existing data +### 1.5.1 Edit an existing meal after inserted: `editMeal` +For a meal that was inputted in the day, edit its serving size +**Format**: editMealServingSize INDEX s/NEW_SERVING_SIZE +**Sample input**: editMeal 2 s/2 +**Expected output**: Pizza has been edited to 2 servings + +### 1.5.2 Edit an existing drink after inserted: `editDrink` +For a drink that was inputted in the day, edit its serving size +**Format**: editDrinkServingSize INDEX s/NEW_SERVING_SIZE +**Sample input**: editDrink 1 s/200 +**Expected output**: Sprite has been edited to 200 ml + +### 1.5.3 Edit water intake after inserted: `editWater` +Edit serving size of total water intake +**Format**: editWaterIntake s/TOTAL_WATER_INTAKE +**Sample input**: editWaterIntake 200 +**Expected output**: Total water has been edited to 200 ml + +## 1.6 For deleting data +### 1.6.1 Delete certain meal entry: `deleteMeal` +For a meal that was inputted in the day, delete its input based on its index in the meal list +**Format**: deleteMeal INDEX +**Sample Input**: deleteMeal 1 +**Expected output**: Removed Chicken Rice From Meals + +### 1.6.2 Delete certain drink entry: `deleteDrink` +For a drink that was inputted in the day, delete its input based on its index in the drink list +**Format**: deleteDrink INDEX +**Sample input**: deleteDrink 1 +**Expected output:** Removed Iced Lemon Tea From Drinks + +## 1.7 For clearing data +### 1.7.1 Clear all entries: `clear` +Clear all entries in mealList and drinkList +**Format**: clear +**Expected output**: All entries have been deleted + +## 1.8: Exit program +### 1.8.1 Exit the app: `exit` +**Format**: exit +**Expected output**: Bye. Hope to see you again soon! diff --git a/docs/README.md b/docs/README.md index 12e4433fad..1351409705 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,45 @@ # FitNUS +## Project Introduction +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Promote healthy lifestyle. + +Users are able to track the meals and drinks they have in a day. + +## Table of Contents + +[1) Features List](#1-features-list) + * [1.1 Information for users](#11-information-for-users) + * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help-) + * [1.2 For user to add data](#12-for-user-to-add-data) + * [1.2.1 Add a meal eaten: `ate`](#121-add-a-meal-eaten-ate) + * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) + * [1.2.3 Add water: `water`](#123-add-water-water) + * [1.3 For data retrieval](#13-for-data-retrieval) + * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) + * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) + * [1.3.3 View daily calories consumed: `calories`](#133-view-daily-calories-consumed-calories) + * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-carbohydrates-consumed-carbs) + * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-proteins-consumed-protein) + * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-fat-consumed-fat) + * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-sugar-consumed-sugar) + * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-fiber-consumed-fiber) + * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-water-consumption-viewwater) + * [1.4 For listing arrays](#14-for-listing-arrays) + * [1.4.1 List meal intake: `listMeals`](#141-list-meal-intake-listmeals) + * [1.4.2 List drink intake: `listDrinks`](#142-list-drink-intake-listdrinks) + * [1.4.3 List entire food intake for the day: `listEverything`](#143-list-entire-food-intake-for-the-day-listeverything) + * [1.5 For editing existing data](#15-for-editing-existing-data) + * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) + * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) + * [1.5.3 Edit water intake after inserted: `editWater`](#153-edit-water-intake-after-inserted-editwater) + * [1.6 For deleting data](#16-for-deleting-data) + * [1.6.1 Delete certain meal entry: `deleteMeal`](#161-delete-certain-meal-entry-deletemeal) + * [1.6.2 Delete certain drink entry: `deleteDrink`](#162-delete-certain-drink-entry-deletedrink) + * [1.7 For clearing data](#17-for-clearing-data-) + * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) + * [1.8: Exit program](#18-exit-program) + * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) + ## 1) Features List ### 1.1 Information for users @@ -48,3 +89,131 @@ Adds water (in ml) to the daily water intake count **Format**: water s/SERVING_SIZE **Sample Input**: water s/200 **Expected Output**: Added 200ml of water + +## 1.3 For data retrieval +### 1.3.1 Find the information about a certain meal: `infoMeal` +For the specified meal, display its nutritional content to the user +**Format**: infoMeal MEAL +**Sample Input**: infoMeal chicken rice +**Expected Output**: +Meal: chicken rice (per serving) +Calories: 400 +Carbs: 50 +Protein: 30 +Fat: 20 +Fiber: 10 +Sugar: 5 + +### 1.3.2 Find the information about a certain drink: `infoDrink` +For the inputed drink, display its nutritional content to the user +**Format**: infoDrink DRINK +**Sample input**: infoDrink sprite +**Expected output**: +SPRITE (473 ml) +Calories: 194 kcal +Carbs: 50g +Protein: 0.2g +Fat: 0.1g + +### 1.3.3 View daily calories consumed: `calories` +Display current total calorie intake for the day +**Format**: calories +**Expected output**: Total calories: 100 cal + +### 1.3.4 View daily carbohydrates consumed: `carbs` +Display current total carbohydrates intake for the day +**Format**: carbs +**Expected output**: Total Carbohydrates: 150 grams + +### 1.3.5 View daily proteins consumed: `protein` +Display current total protein intake for the day +**Format**: protein +**Expected output**: Total proteins: 100 grams + +### 1.3.6 View daily fat consumed: `fat` +Display current total fat intake for the day +**Format**: fat +**Expected output**: Total fat: 50 grams + +### 1.3.7 View daily sugar consumed: `sugar` +Display current total sugar intake for the day +**Format**: sugar +**Expected output**: Total sugar: 20 grams + +### 1.3.8 View daily fiber consumed: `fiber` +Display current total fiber intake (g) for the day +**Format**: viewFiber +**Expected output**: Total fiber: 20 grams + +### 1.3.9 View daily water consumption: `viewWater` +Display current total water intake (in ml) for the day +**Format**: viewWater +**Expected output**: Total water intake: 0 ml + +## 1.4 For listing arrays +### 1.4.1 List meal intake: `listMeals` +List all the meals user inputted today +**Format**: listMeals +**Expected output**: +here's what you have eaten today +1.pizza (serving size: 1) + +### 1.4.2 List drink intake: `listDrinks` +List all the drinks user inputted today +**Format**: listDrinks +**Expected output**: +here's what you have drank today +1.sprite (serving size: 1) +Total water intake: 0 ml + +### 1.4.3 List entire food intake for the day: `listEverything` +List all the drinks and meals inputted today +**Format**: listEverything +**Expected output**: +here's what you have consumed today +1.pizza (serving size: 1) +2.sprite (serving size: 1) +Total water intake: 0 ml + +## 1.5 For editing existing data +### 1.5.1 Edit an existing meal after inserted: `editMeal` +For a meal that was inputted in the day, edit its serving size +**Format**: editMealServingSize INDEX s/NEW_SERVING_SIZE +**Sample input**: editMeal 2 s/2 +**Expected output**: Pizza has been edited to 2 servings + +### 1.5.2 Edit an existing drink after inserted: `editDrink` +For a drink that was inputted in the day, edit its serving size +**Format**: editDrinkServingSize INDEX s/NEW_SERVING_SIZE +**Sample input**: editDrink 1 s/200 +**Expected output**: Sprite has been edited to 200 ml + +### 1.5.3 Edit water intake after inserted: `editWater` +Edit serving size of total water intake +**Format**: editWaterIntake s/TOTAL_WATER_INTAKE +**Sample input**: editWaterIntake 200 +**Expected output**: Total water has been edited to 200 ml + +## 1.6 For deleting data +### 1.6.1 Delete certain meal entry: `deleteMeal` +For a meal that was inputted in the day, delete its input based on its index in the meal list +**Format**: deleteMeal INDEX +**Sample Input**: deleteMeal 1 +**Expected output**: Removed Chicken Rice From Meals + +### 1.6.2 Delete certain drink entry: `deleteDrink` +For a drink that was inputted in the day, delete its input based on its index in the drink list +**Format**: deleteDrink INDEX +**Sample input**: deleteDrink 1 +**Expected output:** Removed Iced Lemon Tea From Drinks + +## 1.7 For clearing data +### 1.7.1 Clear all entries: `clear` +Clear all entries in mealList and drinkList +**Format**: clear +**Expected output**: All entries have been deleted + +## 1.8: Exit program +### 1.8.1 Exit the app: `exit` +**Format**: exit +**Expected output**: Bye. Hope to see you again soon! diff --git a/docs/UserGuide.md b/docs/UserGuide.md index cd3d452278..fb64b38117 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1 +1,219 @@ -# User Guide +# User Guide: FitNUS +## Project Introduction +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Promote healthy lifestyle. + +Users are able to track the meals and drinks they have in a day. + +## Table of Contents + +[1) Features List](#1-features-list) +* [1.1 Information for users](#11-information-for-users) + * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help-) +* [1.2 For user to add data](#12-for-user-to-add-data) + * [1.2.1 Add a meal eaten: `ate`](#121-add-a-meal-eaten-ate) + * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) + * [1.2.3 Add water: `water`](#123-add-water-water) +* [1.3 For data retrieval](#13-for-data-retrieval) + * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) + * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) + * [1.3.3 View daily calories consumed: `calories`](#133-view-daily-calories-consumed-calories) + * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-carbohydrates-consumed-carbs) + * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-proteins-consumed-protein) + * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-fat-consumed-fat) + * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-sugar-consumed-sugar) + * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-fiber-consumed-fiber) + * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-water-consumption-viewwater) +* [1.4 For listing arrays](#14-for-listing-arrays) + * [1.4.1 List meal intake: `listMeals`](#141-list-meal-intake-listmeals) + * [1.4.2 List drink intake: `listDrinks`](#142-list-drink-intake-listdrinks) + * [1.4.3 List entire food intake for the day: `listEverything`](#143-list-entire-food-intake-for-the-day-listeverything) +* [1.5 For editing existing data](#15-for-editing-existing-data) + * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) + * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) + * [1.5.3 Edit water intake after inserted: `editWater`](#153-edit-water-intake-after-inserted-editwater) +* [1.6 For deleting data](#16-for-deleting-data) + * [1.6.1 Delete certain meal entry: `deleteMeal`](#161-delete-certain-meal-entry-deletemeal) + * [1.6.2 Delete certain drink entry: `deleteDrink`](#162-delete-certain-drink-entry-deletedrink) +* [1.7 For clearing data](#17-for-clearing-data-) + * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) +* [1.8: Exit program](#18-exit-program) + * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) + + +## 1) Features List +### 1.1 Information for users +### 1.1.1 Viewing all commands:** `help` +Shows a list of all possible command inputs. +**Format**: help +**Sample Input**: help +**Expected Output**: +here's all the valid commands i recognise: +- Add a meal eaten: ate m/MEAL s/SERVING_SIZE +- Add a drink: drink d/DRINK s/SERVING_SIZE +- Add water: water s/SERVING_SIZE +- Find the information about a certain meal: infoMeal MEAL +- Find the information about a certain drink: infoDrink DRINK +- View daily calories consumed: calories +- View daily carbohydrates consumed: carbs +- View daily proteins consumed: protein +- View daily fat consumed: fat +- View daily sugar consumed: sugar +- View daily fiber consumed: fiber +- View daily water consumption: viewWater +- List meal intake: listMeals +- List drink intake: listDrinks +- List entire food intake for the day: listEverything +- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE +- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE +- Delete certain meal entry: deleteMeal INDEX +- Delete certain drink entry: deleteDrink INDEX +- Clear all entries: clear +- Exit the app: exit + +### 1.2 For user to add data +### 1.2.1 Add a meal eaten: `ate` +Adds a meal to the list of meals +**Format**: ate m/MEAL s/SERVING_SIZE +**Sample Input**: ate m/Chicken Rice s/1 +**Expected Output**: Added 1 serving of Chicken Rice + +### 1.2.2 Add a drink: `drink` +Adds a drink to the list of drinks +**Format**: drink d/DRINK s/SERVING_SIZE +**Sample Input**: drink d/Lemon Tea s/100 +**Expected Output**: Added 100ml of Lemon Tea + +### 1.2.3 Add water: `water` +Adds water (in ml) to the daily water intake count +**Format**: water s/SERVING_SIZE +**Sample Input**: water s/200 +**Expected Output**: Added 200ml of water + +## 1.3 For data retrieval +### 1.3.1 Find the information about a certain meal: `infoMeal` +For the specified meal, display its nutritional content to the user +**Format**: infoMeal MEAL +**Sample Input**: infoMeal chicken rice +**Expected Output**: +Meal: chicken rice (per serving) +Calories: 400 +Carbs: 50 +Protein: 30 +Fat: 20 +Fiber: 10 +Sugar: 5 + +### 1.3.2 Find the information about a certain drink: `infoDrink` +For the inputed drink, display its nutritional content to the user +**Format**: infoDrink DRINK +**Sample input**: infoDrink sprite +**Expected output**: +SPRITE (473 ml) +Calories: 194 kcal +Carbs: 50g +Protein: 0.2g +Fat: 0.1g + +### 1.3.3 View daily calories consumed: `calories` +Display current total calorie intake for the day +**Format**: calories +**Expected output**: Total calories: 100 cal + +### 1.3.4 View daily carbohydrates consumed: `carbs` +Display current total carbohydrates intake for the day +**Format**: carbs +**Expected output**: Total Carbohydrates: 150 grams + +### 1.3.5 View daily proteins consumed: `protein` +Display current total protein intake for the day +**Format**: protein +**Expected output**: Total proteins: 100 grams + +### 1.3.6 View daily fat consumed: `fat` +Display current total fat intake for the day +**Format**: fat +**Expected output**: Total fat: 50 grams + +### 1.3.7 View daily sugar consumed: `sugar` +Display current total sugar intake for the day +**Format**: sugar +**Expected output**: Total sugar: 20 grams + +### 1.3.8 View daily fiber consumed: `fiber` +Display current total fiber intake (g) for the day +**Format**: viewFiber +**Expected output**: Total fiber: 20 grams + +### 1.3.9 View daily water consumption: `viewWater` +Display current total water intake (in ml) for the day +**Format**: viewWater +**Expected output**: Total water intake: 0 ml + +## 1.4 For listing arrays +### 1.4.1 List meal intake: `listMeals` +List all the meals user inputted today +**Format**: listMeals +**Expected output**: +here's what you have eaten today +1.pizza (serving size: 1) + +### 1.4.2 List drink intake: `listDrinks` +List all the drinks user inputted today +**Format**: listDrinks +**Expected output**: +here's what you have drank today +1.sprite (serving size: 1) +Total water intake: 0 ml + +### 1.4.3 List entire food intake for the day: `listEverything` +List all the drinks and meals inputted today +**Format**: listEverything +**Expected output**: +here's what you have consumed today +1.pizza (serving size: 1) +2.sprite (serving size: 1) +Total water intake: 0 ml + +## 1.5 For editing existing data +### 1.5.1 Edit an existing meal after inserted: `editMeal` +For a meal that was inputted in the day, edit its serving size +**Format**: editMealServingSize INDEX s/NEW_SERVING_SIZE +**Sample input**: editMeal 2 s/2 +**Expected output**: Pizza has been edited to 2 servings + +### 1.5.2 Edit an existing drink after inserted: `editDrink` +For a drink that was inputted in the day, edit its serving size +**Format**: editDrinkServingSize INDEX s/NEW_SERVING_SIZE +**Sample input**: editDrink 1 s/200 +**Expected output**: Sprite has been edited to 200 ml + +### 1.5.3 Edit water intake after inserted: `editWater` +Edit serving size of total water intake +**Format**: editWaterIntake s/TOTAL_WATER_INTAKE +**Sample input**: editWaterIntake 200 +**Expected output**: Total water has been edited to 200 ml + +## 1.6 For deleting data +### 1.6.1 Delete certain meal entry: `deleteMeal` +For a meal that was inputted in the day, delete its input based on its index in the meal list +**Format**: deleteMeal INDEX +**Sample Input**: deleteMeal 1 +**Expected output**: Removed Chicken Rice From Meals + +### 1.6.2 Delete certain drink entry: `deleteDrink` +For a drink that was inputted in the day, delete its input based on its index in the drink list +**Format**: deleteDrink INDEX +**Sample input**: deleteDrink 1 +**Expected output:** Removed Iced Lemon Tea From Drinks + +## 1.7 For clearing data +### 1.7.1 Clear all entries: `clear` +Clear all entries in mealList and drinkList +**Format**: clear +**Expected output**: All entries have been deleted + +## 1.8: Exit program +### 1.8.1 Exit the app: `exit` +**Format**: exit +**Expected output**: Bye. Hope to see you again soon! diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 674349ac6e..4eb84ed648 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -161,7 +161,7 @@ public void handleListDrinks() { } public void handleListEverything() { - System.out.println("here's what you have drank today"); + System.out.println("here's what you have consumed today"); if (drinkList.isEmpty() && mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { From 3255def6b2207fabf47756540716bc843d09b9c7 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 19 Mar 2024 23:47:48 +0800 Subject: [PATCH 041/274] Update test files --- text-ui-test/ACTUAL-SH.TXT | 4 ---- text-ui-test/EXPECTED-SH.TXT | 4 ---- text-ui-test/EXPECTED.TXT | 4 ---- text-ui-test/input.txt | 1 - 4 files changed, 13 deletions(-) diff --git a/text-ui-test/ACTUAL-SH.TXT b/text-ui-test/ACTUAL-SH.TXT index 22c82f21f7..1a160a5b1e 100644 --- a/text-ui-test/ACTUAL-SH.TXT +++ b/text-ui-test/ACTUAL-SH.TXT @@ -11,9 +11,5 @@ _________________________________________________________________ Added 2 serving of chicken rice _________________________________________________________________ _________________________________________________________________ -here's what you have eaten today -1. chicken rice -_________________________________________________________________ -_________________________________________________________________ Bye. Hope to see you again soon! _________________________________________________________________ diff --git a/text-ui-test/EXPECTED-SH.TXT b/text-ui-test/EXPECTED-SH.TXT index 22c82f21f7..1a160a5b1e 100644 --- a/text-ui-test/EXPECTED-SH.TXT +++ b/text-ui-test/EXPECTED-SH.TXT @@ -11,9 +11,5 @@ _________________________________________________________________ Added 2 serving of chicken rice _________________________________________________________________ _________________________________________________________________ -here's what you have eaten today -1. chicken rice -_________________________________________________________________ -_________________________________________________________________ Bye. Hope to see you again soon! _________________________________________________________________ diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 22c82f21f7..1a160a5b1e 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -11,9 +11,5 @@ _________________________________________________________________ Added 2 serving of chicken rice _________________________________________________________________ _________________________________________________________________ -here's what you have eaten today -1. chicken rice -_________________________________________________________________ -_________________________________________________________________ Bye. Hope to see you again soon! _________________________________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index d85f9017a1..8be321cd63 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,4 +1,3 @@ add m/chicken rice s/2 ate m/chicken rice s/2 -listMeals exit \ No newline at end of file From c73032b2a78064d09a3b03058b82ae766f1eebf7 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 24 Mar 2024 22:05:59 +0800 Subject: [PATCH 042/274] Fix parseInfoDrink --- src/main/java/seedu/fitnus/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 048c613fcf..f21c3a0ba8 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -179,7 +179,7 @@ public static String parseInfoMeal(String command) throws UnregisteredMealExcept public static String parseInfoDrink(String command) throws UnregisteredDrinkException { int drinkIndex = 10; String infoDrinkDescription = command.substring(drinkIndex).trim(); - if (!Meal.getNutrientDetails().containsKey(infoDrinkDescription)) { + if (!Drink.getNutrientDetails().containsKey(infoDrinkDescription)) { throw new UnregisteredDrinkException(); } return infoDrinkDescription; From 92b6f8ca2d908dd858a62d8442792c04f94eccac Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 24 Mar 2024 23:36:43 +0800 Subject: [PATCH 043/274] Add Storage Created storage to store meal, drink, and water --- data/DrinkList.txt | 5 ++ data/MealList.txt | 4 + src/main/java/seedu/fitnus/Parser.java | 27 ++++++- src/main/java/seedu/fitnus/Ui.java | 10 ++- .../java/seedu/fitnus/storage/Storage.java | 81 +++++++++++++++++++ src/main/java/seedu/fitnus/user/User.java | 75 ++++++++++++++++- 6 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 data/DrinkList.txt create mode 100644 data/MealList.txt create mode 100644 src/main/java/seedu/fitnus/storage/Storage.java diff --git a/data/DrinkList.txt b/data/DrinkList.txt new file mode 100644 index 0000000000..6cd2d1c69e --- /dev/null +++ b/data/DrinkList.txt @@ -0,0 +1,5 @@ +water,500 +water,500 +lemon tea,2 +sprite,200 +sprite,500 diff --git a/data/MealList.txt b/data/MealList.txt new file mode 100644 index 0000000000..ee59104283 --- /dev/null +++ b/data/MealList.txt @@ -0,0 +1,4 @@ +fried rice,3 +chicken rice,2 +fried rice,1 +chicken rice,2 diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index f21c3a0ba8..84c88171d5 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -20,11 +20,16 @@ public class Parser { public static int editDrinkIndex; public static int editDrinkSize; public static int editWaterSize; + public static String mealStorageDescription; + public static int mealStorageSize; + public static String drinkStorageDescription; + public static int drinkStorageSize; private User user; - public Parser() { - this.user = new User(); + public Parser(User user) { + this.user = user; } + public void handleCommand(String command) { try { if (command.equals("help")) { @@ -127,7 +132,7 @@ public static void parseMeal(String command) throws IncompleteMealException, Unr if (sizeIndex >= command.length()) { throw new IncompleteMealException(); } - mealDescription = command.substring(descriptionIndex, sizeIndex - 2).trim(); + mealDescription = command.substring(descriptionIndex, sizeIndex - 2).trim().toLowerCase(); if (mealDescription.isEmpty()) { throw new IncompleteMealException(); } @@ -146,7 +151,7 @@ public static void parseDrink(String command) throws IncompleteDrinkException, U if (sizeIndex >= command.length()) { throw new IncompleteDrinkException(); } - drinkDescription = command.substring(descriptionIndex, sizeIndex - 2).trim(); + drinkDescription = command.substring(descriptionIndex, sizeIndex - 2).trim().toLowerCase(); if (drinkDescription.isEmpty()) { throw new IncompleteDrinkException(); } @@ -201,4 +206,18 @@ public static void parseEditWater(String command) { int waterSizePosition = command.indexOf("s/") + 2; editWaterSize = Integer.parseInt(command.substring(waterSizePosition).trim()); } + + public static void parseMealStorage(String data) { + String delimiter = ","; + String[] arrayOfMealData = data.split(delimiter); + mealStorageDescription = arrayOfMealData[0]; + mealStorageSize = Integer.parseInt(arrayOfMealData[1]); + } + + public static void parseDrinkStorage(String data) { + String delimiter = ","; + String[] arrayOfDrinkData = data.split(delimiter); + drinkStorageDescription = arrayOfDrinkData[0]; + drinkStorageSize = Integer.parseInt(arrayOfDrinkData[1]); + } } diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 78eb6f9615..1dc5bb1d7e 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -1,5 +1,8 @@ package seedu.fitnus; +import seedu.fitnus.storage.Storage; +import seedu.fitnus.user.User; + import java.util.Scanner; public class Ui { @@ -8,7 +11,10 @@ public class Ui { /** Specifies whether user has input the exit command */ public boolean isExit = false; - private Parser parser = new Parser(); + private Storage mealStorage = new Storage("./data", "data/MealList.txt"); + private Storage drinkStorage = new Storage("./data", "data/DrinkList.txt"); + private User user = new User(mealStorage, drinkStorage); + private Parser parser = new Parser(user); /** Prints the welcome message upon the start of the application */ public void printWelcomeMessage() { @@ -24,6 +30,8 @@ public void handleExit() { System.out.println("Bye. Hope to see you again soon!"); input.close(); isExit = true; + user.saveMeal(mealStorage); + user.saveDrink(drinkStorage); } public static void showLine() { diff --git a/src/main/java/seedu/fitnus/storage/Storage.java b/src/main/java/seedu/fitnus/storage/Storage.java new file mode 100644 index 0000000000..ae977985f4 --- /dev/null +++ b/src/main/java/seedu/fitnus/storage/Storage.java @@ -0,0 +1,81 @@ +package seedu.fitnus.storage; + +import seedu.fitnus.user.User; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Scanner; +import java.io.FileWriter; +import java.io.IOException; + +public class Storage { + public String textContent; + public String folderPath; + public String filePath; + private User user; + + public Storage(String folderPath, String filePath) { + this.textContent = ""; + this.folderPath = folderPath; + this.filePath = filePath; + } + + /** + * Append the contents to a single string that will be saved + * @param content String to be appended + */ + public void appendTextContent(String content) { + textContent += (content + '\n'); + } + + /** + * Load the saved file and convert it into list of text formatted commands + * @return List of text formatted commands + * @throws FileNotFoundException If the file does not exist + */ + public ArrayList readFile() throws FileNotFoundException { + ArrayList input = new ArrayList<>(); + File file = new File(filePath); + Scanner s = new Scanner(file); + while (s.hasNext()) { + input.add(s.nextLine()); + } + s.close(); + return input; + } + + /** + * Creates new folder and file if both did not exist + */ + public void createFile() { + try { + File dataFolder = new File(folderPath); + if (!dataFolder.exists()) { + System.out.println("Folder not found, attempting to create folder."); + if (dataFolder.mkdirs()) { + System.out.println("Data folder has been created successfully."); + } else { + System.err.println("Failed to create data folder."); + } + } + File textFile = new File(filePath); + if (textFile.createNewFile()) { + System.out.println("File has been created."); + } + } catch (IOException err) { + System.out.println("Failed to create file."); + } + } + + /** + * Write the given string to the text file + * @param textToAdd String to be written + * @throws IOException If there is any error encountered + */ + public void writeFile(String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath); + fw.write(textToAdd); + fw.close(); + } +} diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 4eb84ed648..6410462cf4 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -4,6 +4,7 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; +import seedu.fitnus.storage.Storage; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; @@ -12,6 +13,8 @@ import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.invalidIndexException; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; public class User { @@ -19,10 +22,78 @@ public class User { protected static ArrayList drinkList; private static ArrayList totalWaterIntake; - public User() { + public User(Storage mealStorage, Storage drinkStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); totalWaterIntake = new ArrayList<>(); + loadMeal(mealStorage); + loadDrink(drinkStorage); + } + + public void loadMeal(Storage mealStorage) { + try { + ArrayList mealStorageList = mealStorage.readFile(); + if (!mealStorageList.isEmpty()) { + for (String s : mealStorageList) { + Parser.parseMealStorage(s); + String mealDescription = Parser.mealStorageDescription; + int mealSize = Parser.mealStorageSize; + mealList.add(new Meal(mealDescription, mealSize)); + } + } + } catch (FileNotFoundException e) { + System.out.println("File not found, attempting to create file."); + mealStorage.createFile(); + } + } + + public void loadDrink(Storage drinkStorage) { + try { + ArrayList drinkStorageList = drinkStorage.readFile(); + if (!drinkStorageList.isEmpty()) { + for (String s : drinkStorageList) { + Parser.parseDrinkStorage(s); + String drinkDescription = Parser.drinkStorageDescription; + int drinkSize = Parser.drinkStorageSize; + if (drinkDescription.equals("water")) { + totalWaterIntake.add(new Water(drinkSize)); + } else { + drinkList.add(new Drink(drinkDescription, drinkSize)); + } + } + } + } catch (FileNotFoundException e) { + System.out.println("File not found, attempting to create file."); + drinkStorage.createFile(); + } + } + + public void saveMeal(Storage mealStorage) { + for (Meal meal : mealList) { + String mealSavedData = meal.getName() + "," + meal.getServingSize(); + mealStorage.appendTextContent(mealSavedData); + } + try { + mealStorage.writeFile(mealStorage.textContent); + } catch (IOException e) { + System.out.println("Failed saving meal: " + e.getMessage()); + } + } + + public void saveDrink(Storage drinkStorage) { + for (Water water: totalWaterIntake) { + String waterSavedData = "water" + "," + water.getWater(); + drinkStorage.appendTextContent(waterSavedData); + } + for (Drink drink : drinkList) { + String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize(); + drinkStorage.appendTextContent(drinkSavedData); + } + try { + drinkStorage.writeFile(drinkStorage.textContent); + } catch (IOException e) { + System.out.println("Failed saving drink: " + e.getMessage()); + } } public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException { @@ -144,7 +215,7 @@ public void handleListMeals() { public void printDrinkList(int startIndex) { for (int i = 0; i < drinkList.size(); i++) { Drink currentDrink = drinkList.get(i); - System.out.print((startIndex+i) + ". " + currentDrink.getName() + " (serving size: " + System.out.println((startIndex+i) + ". " + currentDrink.getName() + " (serving size: " + currentDrink.getDrinkVolumeSize() + ")"); } } From c4c35144e2014f49aa72d07508fbee2eedc3c613 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 25 Mar 2024 19:54:27 +0800 Subject: [PATCH 044/274] Remove print statements in Storage --- data/DrinkList.txt | 5 ----- data/MealList.txt | 4 ---- src/main/java/seedu/fitnus/storage/Storage.java | 11 ++++------- src/main/java/seedu/fitnus/user/User.java | 2 -- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/data/DrinkList.txt b/data/DrinkList.txt index 6cd2d1c69e..e69de29bb2 100644 --- a/data/DrinkList.txt +++ b/data/DrinkList.txt @@ -1,5 +0,0 @@ -water,500 -water,500 -lemon tea,2 -sprite,200 -sprite,500 diff --git a/data/MealList.txt b/data/MealList.txt index ee59104283..e69de29bb2 100644 --- a/data/MealList.txt +++ b/data/MealList.txt @@ -1,4 +0,0 @@ -fried rice,3 -chicken rice,2 -fried rice,1 -chicken rice,2 diff --git a/src/main/java/seedu/fitnus/storage/Storage.java b/src/main/java/seedu/fitnus/storage/Storage.java index ae977985f4..b714c55fbe 100644 --- a/src/main/java/seedu/fitnus/storage/Storage.java +++ b/src/main/java/seedu/fitnus/storage/Storage.java @@ -52,19 +52,16 @@ public void createFile() { try { File dataFolder = new File(folderPath); if (!dataFolder.exists()) { - System.out.println("Folder not found, attempting to create folder."); - if (dataFolder.mkdirs()) { - System.out.println("Data folder has been created successfully."); - } else { + if (!dataFolder.mkdirs()) { System.err.println("Failed to create data folder."); } } File textFile = new File(filePath); - if (textFile.createNewFile()) { - System.out.println("File has been created."); + if (!textFile.createNewFile()) { + System.err.println("Failed to create file."); } } catch (IOException err) { - System.out.println("Failed to create file."); + System.out.println("Failed to create file: " + err.getMessage()); } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 6410462cf4..251587ba71 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -42,7 +42,6 @@ public void loadMeal(Storage mealStorage) { } } } catch (FileNotFoundException e) { - System.out.println("File not found, attempting to create file."); mealStorage.createFile(); } } @@ -63,7 +62,6 @@ public void loadDrink(Storage drinkStorage) { } } } catch (FileNotFoundException e) { - System.out.println("File not found, attempting to create file."); drinkStorage.createFile(); } } From a7ab8b442fb4ff9d09273c7874535c6b8594f85d Mon Sep 17 00:00:00 2001 From: tinaliu27 <27tinaliu@gmail.com> Date: Tue, 26 Mar 2024 06:04:44 +0800 Subject: [PATCH 045/274] added methods for reading and writing --- db/Drink_db.csv | 1 - db/Meal_db.csv | 1 - db/Output_Drink_2024-03-26.csv | 1 + db/Output_Food_2024-03-26.csv | 1 + src/main/java/seedu/fitnus/CSVReader.java | 54 ++++++++++++++++++++--- src/main/java/seedu/fitnus/CSVWriter.java | 37 ++++++++++++++++ 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 db/Output_Drink_2024-03-26.csv create mode 100644 db/Output_Food_2024-03-26.csv create mode 100644 src/main/java/seedu/fitnus/CSVWriter.java diff --git a/db/Drink_db.csv b/db/Drink_db.csv index ffc5d5e231..c2e4f277b5 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -1,4 +1,3 @@ -Drink Name,Calories,Carbs,Protein,Fat Teh C Bing,231,24,15,1 Teh,151,29,4,0.8 Kopi,141,26.7,2.3,2.8 diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 2bed965bdf..9d2d4e90aa 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,4 +1,3 @@ -Meal Name,Calories,Carbs,Proteins,Fats,Fiber Chicken Rice (382g),607,75,25,23,2 Char Kway Teow (384g),744,76,23,29.2,7.3 Laksa,377,71,18,2,4 diff --git a/db/Output_Drink_2024-03-26.csv b/db/Output_Drink_2024-03-26.csv new file mode 100644 index 0000000000..45b983be36 --- /dev/null +++ b/db/Output_Drink_2024-03-26.csv @@ -0,0 +1 @@ +hi diff --git a/db/Output_Food_2024-03-26.csv b/db/Output_Food_2024-03-26.csv new file mode 100644 index 0000000000..45b983be36 --- /dev/null +++ b/db/Output_Food_2024-03-26.csv @@ -0,0 +1 @@ +hi diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java index 38a77e7b38..3e9da5dc78 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -3,12 +3,18 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.util.HashMap; public class CSVReader { + private static HashMap foodItems = new HashMap<>(); + public static final String DELIMITER = ","; public static void main(String[] args){ - String csvFile = "./db/Meal_db.csv"; - CSVReader.read(csvFile); + String mealCsvFile = "./db/Meal_db.csv"; + String drinkCSVFile = "./db/Drink_db.csv"; + CSVReader.read(mealCsvFile); + printInfo(); + readMealInfo(mealCsvFile, "Pepper lunch "); } public static void read(String filename) { try{ @@ -20,14 +26,52 @@ public static void read(String filename) { String[] tempArr; while ((line = br.readLine()) != null) { tempArr = line.split(DELIMITER); - for (String tempStr : tempArr) { - System.out.print(tempStr + " "); + String itemFullName = tempArr[0]; + String[] itemDetails = new String[tempArr.length-1]; + for(int i = 1; i < tempArr.length; i++) { + itemDetails[i-1] = tempArr[i]; } - System.out.println(); + foodItems.put(itemFullName, itemDetails); + } br.close(); } catch (IOException ex) { ex.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + public static void readMealInfo(String filename, String foodName) { + read(filename); + boolean found = false; + String[] nutrientInfo = null; + if (foodItems.containsKey(foodName)) { + nutrientInfo = foodItems.get(foodName); + found = true; + } else { + System.out.println("Error! Food not found. Please input a valid item."); + } + if(found && nutrientInfo != null) + for(String nutrients: nutrientInfo) { + System.out.println(nutrients); + } + } + + + + public static void printInfo() { + for (HashMap.Entry entry : foodItems.entrySet()) { + String key = entry.getKey(); + String[] value = entry.getValue(); + System.out.print("Key: " + key + ", Value: ["); + for (int i = 0; i < value.length; i++) { + System.out.print(value[i]); + if (i < value.length - 1) { + System.out.print(", "); + } + } + System.out.println("]"); } } } + diff --git a/src/main/java/seedu/fitnus/CSVWriter.java b/src/main/java/seedu/fitnus/CSVWriter.java new file mode 100644 index 0000000000..ddd621d0e9 --- /dev/null +++ b/src/main/java/seedu/fitnus/CSVWriter.java @@ -0,0 +1,37 @@ +package seedu.fitnus; + +import java.io.*; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +public class CSVWriter { + public static void main(String[] args) { + writeIntoFile("hi", "FOOD"); + } + public static void writeIntoFile(String foodItem, String fileName) { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + File file = null; + if (fileName.toLowerCase().contains("food")) { + file = new File("./db/Output_Food_" + df.format(new Date())+".csv"); + } else { + file = new File("./db/Output_Drink_" + df.format(new Date())+".csv"); + } + if (!file.exists()) { + try{ + file.createNewFile(); + } catch (IOException e) { + System.out.println("error with creating a file"); + } + } + try (FileWriter fw = new FileWriter(file)){ + BufferedWriter writer = new BufferedWriter(fw); + writer.write(foodItem); + writer.newLine(); + writer.close(); + } catch (IOException e) { + System.out.println("error trying to add something into the file"); + } + } +} From 772fb3d0c8319dab8479524cfb9b49f33aa45340 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 26 Mar 2024 18:21:05 +0800 Subject: [PATCH 046/274] Inherit drink from water class --- data/DrinkList.txt | 3 +++ data/MealList.txt | 1 + src/main/java/seedu/fitnus/CSVReader.java | 2 +- src/main/java/seedu/fitnus/CSVWriter.java | 6 +++-- src/main/java/seedu/fitnus/Drink.java | 4 +++- src/main/java/seedu/fitnus/Parser.java | 22 ++----------------- .../exception/IncompleteWaterException.java | 4 ---- src/main/java/seedu/fitnus/user/User.java | 21 ++++++------------ src/test/java/seedu/fitnus/user/UserTest.java | 13 ----------- 9 files changed, 21 insertions(+), 55 deletions(-) delete mode 100644 src/main/java/seedu/fitnus/exception/IncompleteWaterException.java diff --git a/data/DrinkList.txt b/data/DrinkList.txt index e69de29bb2..66a2b4f44c 100644 --- a/data/DrinkList.txt +++ b/data/DrinkList.txt @@ -0,0 +1,3 @@ +water,100 +water,1000000000 +water,100 diff --git a/data/MealList.txt b/data/MealList.txt index e69de29bb2..47dcdcd772 100644 --- a/data/MealList.txt +++ b/data/MealList.txt @@ -0,0 +1 @@ +pizza,2 diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java index 3e9da5dc78..003f73a5be 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -8,7 +8,7 @@ public class CSVReader { private static HashMap foodItems = new HashMap<>(); - public static final String DELIMITER = ","; + private static final String DELIMITER = ","; public static void main(String[] args){ String mealCsvFile = "./db/Meal_db.csv"; String drinkCSVFile = "./db/Drink_db.csv"; diff --git a/src/main/java/seedu/fitnus/CSVWriter.java b/src/main/java/seedu/fitnus/CSVWriter.java index ddd621d0e9..3cfbd260ab 100644 --- a/src/main/java/seedu/fitnus/CSVWriter.java +++ b/src/main/java/seedu/fitnus/CSVWriter.java @@ -1,10 +1,12 @@ package seedu.fitnus; -import java.io.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Locale; public class CSVWriter { public static void main(String[] args) { diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 3492de33ae..11610c3948 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -3,7 +3,7 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import java.util.HashMap; -public class Drink { +public class Drink extends Water { private static HashMap nutrientDetails = new HashMap<>(); private String name; private int drinkVolume; @@ -14,6 +14,7 @@ public class Drink { private int fat; public Drink(String name, int volume) { + super(volume); this.name = name; this.drinkVolume = volume; setNutrientValues(name); @@ -24,6 +25,7 @@ public Drink(String name, int volume) { nutrientDetails.put("sprite", new int[]{40, 50, 30, 20, 2}); nutrientDetails.put("lemon tea", new int[]{150, 30, 25, 1, 20}); nutrientDetails.put("milk coffee", new int[]{20, 27, 25, 4, 3}); + nutrientDetails.put("water", new int[]{0, 0, 0, 0, 0}); } private void setNutrientValues(String name) { diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 84c88171d5..e516d69191 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -2,7 +2,6 @@ import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.IncompleteWaterException; import seedu.fitnus.exception.InvalidCommandException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; @@ -14,7 +13,6 @@ public class Parser { public static int mealSize; public static String drinkDescription; public static int drinkSize; - public static int waterSize; public static int editMealIndex; public static int editMealSize; public static int editDrinkIndex; @@ -38,8 +36,6 @@ public void handleCommand(String command) { user.handleMeal(command); } else if (command.startsWith("drink")) { user.handleDrink(command); - } else if (command.startsWith("water")) { - user.handleWater(command); } else if (command.startsWith("infoMeal")) { Meal.handleInfoMeal(command); } else if (command.startsWith("infoDrink")) { @@ -81,8 +77,6 @@ public void handleCommand(String command) { } } catch (InvalidCommandException e) { System.out.println("Invalid command, type [help] to view all commands."); - } catch (IncompleteWaterException e) { - System.out.println("Incomplete command, the format must be [water s/SERVING_SIZE]."); } catch (IncompleteDrinkException e) { System.out.println("Incomplete command, the format must be [drink d/DRINK s/SERVING_SIZE]."); } catch (IncompleteMealException e) { @@ -100,8 +94,7 @@ public void handleCommand(String command) { public static void handleHelp() { System.out.println("here's all the valid commands i recognise: "); System.out.println("- Add a meal eaten: ate m/MEAL s/SERVING_SIZE"); - System.out.println("- Add a drink: drink d/DRINK s/SERVING_SIZE"); - System.out.println("- Add water: water s/SERVING_SIZE"); + System.out.println("- Add a drink: drink d/DRINK s/VOLUME(ML)"); System.out.println("- Find the information about a certain meal: infoMeal MEAL"); System.out.println("- Find the information about a certain drink: infoDrink DRINK"); System.out.println("- View daily calories consumed: calories"); @@ -155,23 +148,12 @@ public static void parseDrink(String command) throws IncompleteDrinkException, U if (drinkDescription.isEmpty()) { throw new IncompleteDrinkException(); } - if (!Drink.getNutrientDetails().containsKey(drinkDescription)) { + if (!Drink.getNutrientDetails().containsKey(drinkDescription) && !drinkDescription.equals("water")) { throw new UnregisteredDrinkException(); } drinkSize = Integer.parseInt(command.substring(sizeIndex).trim()); } - public static void parseWater(String command) throws IncompleteWaterException { - if (!command.contains("s/")) { - throw new IncompleteWaterException(); - } - int sizeIndex = command.indexOf("s/") + 2; - if (sizeIndex >= command.length()) { - throw new IncompleteWaterException(); - } - waterSize = Integer.parseInt(command.substring(sizeIndex).trim()); - } - public static String parseInfoMeal(String command) throws UnregisteredMealException { int mealIndex = 9; String infoMealDescription = command.substring(mealIndex).trim(); diff --git a/src/main/java/seedu/fitnus/exception/IncompleteWaterException.java b/src/main/java/seedu/fitnus/exception/IncompleteWaterException.java deleted file mode 100644 index c1df973172..0000000000 --- a/src/main/java/seedu/fitnus/exception/IncompleteWaterException.java +++ /dev/null @@ -1,4 +0,0 @@ -package seedu.fitnus.exception; - -public class IncompleteWaterException extends Exception{ -} diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 251587ba71..12c60f68d7 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -8,7 +8,6 @@ import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.IncompleteWaterException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.invalidIndexException; @@ -109,20 +108,14 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; - - drinkList.add(new Drink(drinkName, servingSize)); + if (drinkName.equals("water")) { + totalWaterIntake.add(new Water(servingSize)); + } else { + drinkList.add(new Drink(drinkName, servingSize)); + } System.out.println("Added " + servingSize + " ml of " + drinkName); } - public void handleWater(String command) throws IncompleteWaterException { - Parser.parseWater(command); - int volume = Parser.waterSize; - assert volume > 0: "invalid volume"; - - totalWaterIntake.add(new Water(volume)); - System.out.println("Added " + volume + " ml of water"); - } - public void handleViewCalories() { int caloriesCount = 0; for (Meal meal: mealList) { @@ -213,8 +206,8 @@ public void handleListMeals() { public void printDrinkList(int startIndex) { for (int i = 0; i < drinkList.size(); i++) { Drink currentDrink = drinkList.get(i); - System.out.println((startIndex+i) + ". " + currentDrink.getName() + " (serving size: " - + currentDrink.getDrinkVolumeSize() + ")"); + System.out.println((startIndex+i) + ". " + currentDrink.getName() + " (volume: " + + currentDrink.getDrinkVolumeSize() + "ml)"); } } diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index f6bf8ebf66..ad9f42a688 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -6,7 +6,6 @@ import seedu.fitnus.Parser; import seedu.fitnus.Water; import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.IncompleteWaterException; import seedu.fitnus.exception.UnregisteredMealException; import java.util.ArrayList; @@ -33,16 +32,4 @@ public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealExcep assertEquals(3, testMealList.get(0).getServingSize()); } - @Test - public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWaterException { - try { - Parser.parseWater("water 1"); - new Water(Parser.waterSize); - } catch (IncompleteWaterException e) { - return; - } - - String error = "Incomplete command, the format must be [water s/SERVING_SIZE]."; - fail(error); - } } From b887712ff8efcc218ba8e593bee9080aba87eb4a Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 26 Mar 2024 23:38:11 +0800 Subject: [PATCH 047/274] Add JUnit and Assertions Added additional JUnit tests and assertions to meal class --- src/main/java/seedu/fitnus/Meal.java | 2 ++ text-ui-test/ACTUAL-SH.TXT | 3 +++ text-ui-test/EXPECTED-SH.TXT | 3 +++ text-ui-test/EXPECTED.TXT | 3 +++ text-ui-test/data/DrinkList.txt | 0 text-ui-test/data/MealList.txt | 7 +++++++ text-ui-test/input.txt | 1 + 7 files changed, 19 insertions(+) create mode 100644 text-ui-test/data/DrinkList.txt create mode 100644 text-ui-test/data/MealList.txt diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 8a48066d30..82171e6993 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -17,7 +17,9 @@ public class Meal { // Constructor with only serving size and meal name public Meal(String name, int servingSize) { + assert name != null : "Name must not be null"; this.name = name; + assert servingSize > 0 : "Serving size must be greater than 0"; this.servingSize = servingSize; setNutrientValues(name); // Assign nutrient values based on the name } diff --git a/text-ui-test/ACTUAL-SH.TXT b/text-ui-test/ACTUAL-SH.TXT index 1a160a5b1e..ba310e6eee 100644 --- a/text-ui-test/ACTUAL-SH.TXT +++ b/text-ui-test/ACTUAL-SH.TXT @@ -11,5 +11,8 @@ _________________________________________________________________ Added 2 serving of chicken rice _________________________________________________________________ _________________________________________________________________ +Added 1 serving of fried rice +_________________________________________________________________ +_________________________________________________________________ Bye. Hope to see you again soon! _________________________________________________________________ diff --git a/text-ui-test/EXPECTED-SH.TXT b/text-ui-test/EXPECTED-SH.TXT index 1a160a5b1e..ba310e6eee 100644 --- a/text-ui-test/EXPECTED-SH.TXT +++ b/text-ui-test/EXPECTED-SH.TXT @@ -11,5 +11,8 @@ _________________________________________________________________ Added 2 serving of chicken rice _________________________________________________________________ _________________________________________________________________ +Added 1 serving of fried rice +_________________________________________________________________ +_________________________________________________________________ Bye. Hope to see you again soon! _________________________________________________________________ diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 1a160a5b1e..ba310e6eee 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -11,5 +11,8 @@ _________________________________________________________________ Added 2 serving of chicken rice _________________________________________________________________ _________________________________________________________________ +Added 1 serving of fried rice +_________________________________________________________________ +_________________________________________________________________ Bye. Hope to see you again soon! _________________________________________________________________ diff --git a/text-ui-test/data/DrinkList.txt b/text-ui-test/data/DrinkList.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/text-ui-test/data/MealList.txt b/text-ui-test/data/MealList.txt new file mode 100644 index 0000000000..941d682511 --- /dev/null +++ b/text-ui-test/data/MealList.txt @@ -0,0 +1,7 @@ +chicken rice,2 +chicken rice,2 +fried rice,1 +chicken rice,2 +fried rice,1 +chicken rice,2 +fried rice,1 diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 8be321cd63..9bc19b21c4 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,3 +1,4 @@ add m/chicken rice s/2 ate m/chicken rice s/2 +ate m/fried rice s/1 exit \ No newline at end of file From 81d1b65ff9c991ab9f63b2d4d2807856c95612b4 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 26 Mar 2024 23:46:31 +0800 Subject: [PATCH 048/274] Add JUnit test Added JUnit test for drinks --- src/test/java/seedu/fitnus/user/UserTest.java | 13 ++++++++++--- text-ui-test/data/MealList.txt | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index f6bf8ebf66..884a4889cc 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -5,9 +5,7 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.IncompleteWaterException; -import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.*; import java.util.ArrayList; @@ -45,4 +43,13 @@ public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWat String error = "Incomplete command, the format must be [water s/SERVING_SIZE]."; fail(error); } + + @Test + public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, UnregisteredDrinkException { + Drink newDrink = new Drink("sprite", 100); + testDrinkList.add(newDrink); + + assertEquals("sprite", testDrinkList.get(0).getName()); + assertEquals(100, testDrinkList.get(0).getDrinkVolumeSize()); + } } diff --git a/text-ui-test/data/MealList.txt b/text-ui-test/data/MealList.txt index 941d682511..1e3b80d0a9 100644 --- a/text-ui-test/data/MealList.txt +++ b/text-ui-test/data/MealList.txt @@ -5,3 +5,5 @@ chicken rice,2 fried rice,1 chicken rice,2 fried rice,1 +chicken rice,2 +fried rice,1 From 8f11a2bd794d20e480c316731685a27c478ee2cb Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 26 Mar 2024 23:59:36 +0800 Subject: [PATCH 049/274] Fix Checkstyle errors fixed checkstyle errors in CSVreader and CSVwriter --- src/main/java/seedu/fitnus/CSVReader.java | 9 ++++----- src/main/java/seedu/fitnus/CSVWriter.java | 7 +++++-- src/test/java/seedu/fitnus/user/UserTest.java | 9 +++++++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java index 3e9da5dc78..30f424f6b7 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -6,9 +6,9 @@ import java.util.HashMap; public class CSVReader { + public static final String DELIMITER = ","; private static HashMap foodItems = new HashMap<>(); - public static final String DELIMITER = ","; public static void main(String[] args){ String mealCsvFile = "./db/Meal_db.csv"; String drinkCSVFile = "./db/Drink_db.csv"; @@ -51,14 +51,13 @@ public static void readMealInfo(String filename, String foodName) { } else { System.out.println("Error! Food not found. Please input a valid item."); } - if(found && nutrientInfo != null) - for(String nutrients: nutrientInfo) { + if (found && nutrientInfo != null) { + for (String nutrients : nutrientInfo) { System.out.println(nutrients); } + } } - - public static void printInfo() { for (HashMap.Entry entry : foodItems.entrySet()) { String key = entry.getKey(); diff --git a/src/main/java/seedu/fitnus/CSVWriter.java b/src/main/java/seedu/fitnus/CSVWriter.java index ddd621d0e9..1ae2561a2c 100644 --- a/src/main/java/seedu/fitnus/CSVWriter.java +++ b/src/main/java/seedu/fitnus/CSVWriter.java @@ -1,10 +1,13 @@ package seedu.fitnus; -import java.io.*; +import java.io.BufferedWriter; +import java.io.File; + +import java.io.FileWriter; +import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Locale; public class CSVWriter { public static void main(String[] args) { diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 884a4889cc..ac43b4b412 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -5,7 +5,11 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; -import seedu.fitnus.exception.*; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.IncompleteWaterException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.UnregisteredDrinkException; import java.util.ArrayList; @@ -45,7 +49,8 @@ public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWat } @Test - public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, UnregisteredDrinkException { + public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, + UnregisteredDrinkException { Drink newDrink = new Drink("sprite", 100); testDrinkList.add(newDrink); From 19d9608233c7c26a3598405562bb4eca1c25bacd Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 27 Mar 2024 00:14:27 +0800 Subject: [PATCH 050/274] Edit water class methods --- data/DrinkList.txt | 4 +--- data/MealList.txt | 1 - src/main/java/seedu/fitnus/Drink.java | 5 ++--- src/main/java/seedu/fitnus/Parser.java | 8 +++---- src/main/java/seedu/fitnus/Water.java | 26 +++++++++++++++++++---- src/main/java/seedu/fitnus/user/User.java | 26 +++++++++++++---------- 6 files changed, 44 insertions(+), 26 deletions(-) diff --git a/data/DrinkList.txt b/data/DrinkList.txt index 66a2b4f44c..df399cdc13 100644 --- a/data/DrinkList.txt +++ b/data/DrinkList.txt @@ -1,3 +1 @@ -water,100 -water,1000000000 -water,100 +water,10100 diff --git a/data/MealList.txt b/data/MealList.txt index 47dcdcd772..e69de29bb2 100644 --- a/data/MealList.txt +++ b/data/MealList.txt @@ -1 +0,0 @@ -pizza,2 diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 11610c3948..5c3b892f3d 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -3,7 +3,7 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import java.util.HashMap; -public class Drink extends Water { +public class Drink { private static HashMap nutrientDetails = new HashMap<>(); private String name; private int drinkVolume; @@ -14,7 +14,6 @@ public class Drink extends Water { private int fat; public Drink(String name, int volume) { - super(volume); this.name = name; this.drinkVolume = volume; setNutrientValues(name); @@ -22,10 +21,10 @@ public Drink(String name, int volume) { // Add nutrient details per 100 milliliter to the static HashMap static { + nutrientDetails.put("water", new int[]{0, 0, 0, 0, 0}); nutrientDetails.put("sprite", new int[]{40, 50, 30, 20, 2}); nutrientDetails.put("lemon tea", new int[]{150, 30, 25, 1, 20}); nutrientDetails.put("milk coffee", new int[]{20, 27, 25, 4, 3}); - nutrientDetails.put("water", new int[]{0, 0, 0, 0, 0}); } private void setNutrientValues(String name) { diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index e516d69191..ee3ab1be49 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -65,7 +65,7 @@ public void handleCommand(String command) { } else if (command.startsWith("editDrink")) { User.handleEditDrinkServingSize(command); } else if (command.startsWith("editWater")) { - //User.handleEditWaterIntake(command); + User.handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { user.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { @@ -86,8 +86,8 @@ public void handleCommand(String command) { } catch (UnregisteredMealException e) { System.out.println("Sorry that meal is not registered in the database."); } catch (invalidIndexException e) { - System.out.println("Sorry the index you provided is invalid, check listMeals/listDrinks to view valid " + - "indexes."); + System.out.println("Sorry the index you provided is invalid, check [listMeals or listDrinks] " + + "to view valid " + "indexes."); } } @@ -109,7 +109,7 @@ public static void handleHelp() { System.out.println("- List entire food intake for the day: listEverything"); System.out.println("- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE"); System.out.println("- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE"); - //System.out.println("- Edit water intake after inserted: editWater s/TOTAL_WATER_INTAKE"); + System.out.println("- Edit total water intake after inserted: editWater s/TOTAL_WATER_INTAKE"); System.out.println("- Delete certain meal entry: deleteMeal INDEX"); System.out.println("- Delete certain drink entry: deleteDrink INDEX"); System.out.println("- Clear all entries: clear"); diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/Water.java index 5c481c8379..c7d4c8d619 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -1,13 +1,31 @@ package seedu.fitnus; public class Water { - private int waterIntake; + private static Water instance = null; + private static int waterIntake = 0; - public Water(int waterIntake) { - this.waterIntake = waterIntake; + public Water(int amount) { + waterIntake = amount; } - public int getWater() { + public static Water getInstance(int amount) { + if (instance == null) { + instance = new Water(amount); + } else { + addWaterIntake(amount); + } + return instance; + } + + public static int getWater() { return waterIntake; } + + public static void addWaterIntake(int amount) { + waterIntake += amount; + } + + public static void editWaterIntake(int amount) { + waterIntake = amount; + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 12c60f68d7..e1d3090ddc 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -19,12 +19,11 @@ public class User { protected static ArrayList mealList; protected static ArrayList drinkList; - private static ArrayList totalWaterIntake; + public User(Storage mealStorage, Storage drinkStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); - totalWaterIntake = new ArrayList<>(); loadMeal(mealStorage); loadDrink(drinkStorage); } @@ -54,7 +53,7 @@ public void loadDrink(Storage drinkStorage) { String drinkDescription = Parser.drinkStorageDescription; int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { - totalWaterIntake.add(new Water(drinkSize)); + Water.getInstance(drinkSize); } else { drinkList.add(new Drink(drinkDescription, drinkSize)); } @@ -78,10 +77,8 @@ public void saveMeal(Storage mealStorage) { } public void saveDrink(Storage drinkStorage) { - for (Water water: totalWaterIntake) { - String waterSavedData = "water" + "," + water.getWater(); - drinkStorage.appendTextContent(waterSavedData); - } + String waterSavedData = "water" + "," + Water.getWater(); + drinkStorage.appendTextContent(waterSavedData); for (Drink drink : drinkList) { String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize(); drinkStorage.appendTextContent(drinkSavedData); @@ -108,8 +105,9 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; + if (drinkName.equals("water")) { - totalWaterIntake.add(new Water(servingSize)); + Water.getInstance(servingSize); } else { drinkList.add(new Drink(drinkName, servingSize)); } @@ -151,9 +149,7 @@ public void handleViewProteins() { public void handleViewWaterIntake() { int waterIntake = 0; - for (Water water: totalWaterIntake) { - waterIntake += water.getWater(); - } + waterIntake += Water.getWater(); System.out.println("Total water intake: " + waterIntake + " ml"); } @@ -226,6 +222,8 @@ public void handleListEverything() { System.out.println("here's what you have consumed today"); if (drinkList.isEmpty() && mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); + System.out.println(); + handleViewWaterIntake(); } else { printMealList(1); printDrinkList(mealList.size()+1); @@ -260,6 +258,12 @@ public static void handleEditDrinkServingSize(String command) throws invalidInde System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } + public static void handleEditWaterIntake(String command) throws invalidIndexException { + Parser.parseEditWater(command); + Water.editWaterIntake(Parser.editWaterSize); + System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); + } + public void handleDeleteMeal(String command) { int mealIndex = Integer.parseInt(command.substring(11)) - 1; assert mealIndex >= 0: "meal index out of bounds"; From 5ff4a61395621f7a78fa14134c8008860be61347 Mon Sep 17 00:00:00 2001 From: Jason Lienardi <76238813+jasonlienardi@users.noreply.github.com> Date: Wed, 27 Mar 2024 00:30:28 +0800 Subject: [PATCH 051/274] Update DeveloperGuide.md add implementation description of 'track exerscise' feature --- docs/DeveloperGuide.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 64e1f0ed2b..8f83b7fed4 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -8,6 +8,14 @@ {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +# Tracking Exercise Feature +- Create a CSV which stores data regarding how many calories are burnt per hour for each exercise type (eg. swimming, running, cycling). +- Implement a 'track exercise' function which will be parsed with the format: + track exercise t/{type of exercise} d/{duration of exercise} +- Parse the command +- Using a hashmap, access the data regarding the amount of calories burnt per hour for the given exercise and calculate the total calories burnt for the given duration. +- Store the total calories burnt through exercise in the User class + ## Product scope ### Target user profile From ed5cbae4527096c72cce16efe15ed06dac20fb65 Mon Sep 17 00:00:00 2001 From: Jason Lienardi <76238813+jasonlienardi@users.noreply.github.com> Date: Wed, 27 Mar 2024 00:30:46 +0800 Subject: [PATCH 052/274] Update DeveloperGuide.md --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 8f83b7fed4..b8771dc9c7 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -8,7 +8,7 @@ {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} -# Tracking Exercise Feature +### Tracking Exercise Feature - Create a CSV which stores data regarding how many calories are burnt per hour for each exercise type (eg. swimming, running, cycling). - Implement a 'track exercise' function which will be parsed with the format: track exercise t/{type of exercise} d/{duration of exercise} From 8814411ca53934b4f755e5b99fbb179c8db3860a Mon Sep 17 00:00:00 2001 From: Bryvo <110611186+BryanCastorius@users.noreply.github.com> Date: Wed, 27 Mar 2024 00:38:12 +0800 Subject: [PATCH 053/274] Update UserTest.java bug --- src/test/java/seedu/fitnus/user/UserTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index b0f7d459de..7a70e28a11 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -34,6 +34,7 @@ public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealExcep assertEquals(3, testMealList.get(0).getServingSize()); } + /* @Test public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWaterException { try { @@ -46,6 +47,7 @@ public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWat String error = "Incomplete command, the format must be [water s/SERVING_SIZE]."; fail(error); } + */ @Test public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, From 079397f1df029c0583b95c3647ec3b55e9a2463d Mon Sep 17 00:00:00 2001 From: Bryvo <110611186+BryanCastorius@users.noreply.github.com> Date: Wed, 27 Mar 2024 00:41:56 +0800 Subject: [PATCH 054/274] Update UserTest.java bug-2 --- src/test/java/seedu/fitnus/user/UserTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 7a70e28a11..46ca720b03 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -3,8 +3,8 @@ import org.junit.jupiter.api.Test; import seedu.fitnus.Drink; import seedu.fitnus.Meal; -import seedu.fitnus.Parser; -import seedu.fitnus.Water; +//import seedu.fitnus.Parser; +//import seedu.fitnus.Water; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.IncompleteDrinkException; @@ -13,7 +13,7 @@ import java.util.ArrayList; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; +//import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertTrue; public class UserTest { From 68ef66cf2a30b93306fd57f4c7d3752e98715f95 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 27 Mar 2024 00:47:09 +0800 Subject: [PATCH 055/274] Edit ACTUAL.TXT and EXPECTED.TXT --- text-ui-test/ACTUAL-SH.TXT | 2 +- text-ui-test/EXPECTED-SH.TXT | 2 +- text-ui-test/EXPECTED.TXT | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/text-ui-test/ACTUAL-SH.TXT b/text-ui-test/ACTUAL-SH.TXT index 1a160a5b1e..66856b91a4 100644 --- a/text-ui-test/ACTUAL-SH.TXT +++ b/text-ui-test/ACTUAL-SH.TXT @@ -2,7 +2,7 @@ _________________________________________________________________ Hello! Welcome to FitNUS What would you like to track today? Available meals: pizza, chicken rice, fried rice, etc. -Available drinks: lemon tea, sprite, milk coffee, etc. +Available drinks: lemon tea, sprite, water, milk coffee, etc. _________________________________________________________________ _________________________________________________________________ Invalid command, type [help] to view all commands. diff --git a/text-ui-test/EXPECTED-SH.TXT b/text-ui-test/EXPECTED-SH.TXT index 1a160a5b1e..66856b91a4 100644 --- a/text-ui-test/EXPECTED-SH.TXT +++ b/text-ui-test/EXPECTED-SH.TXT @@ -2,7 +2,7 @@ _________________________________________________________________ Hello! Welcome to FitNUS What would you like to track today? Available meals: pizza, chicken rice, fried rice, etc. -Available drinks: lemon tea, sprite, milk coffee, etc. +Available drinks: lemon tea, sprite, water, milk coffee, etc. _________________________________________________________________ _________________________________________________________________ Invalid command, type [help] to view all commands. diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 1a160a5b1e..66856b91a4 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -2,7 +2,7 @@ _________________________________________________________________ Hello! Welcome to FitNUS What would you like to track today? Available meals: pizza, chicken rice, fried rice, etc. -Available drinks: lemon tea, sprite, milk coffee, etc. +Available drinks: lemon tea, sprite, water, milk coffee, etc. _________________________________________________________________ _________________________________________________________________ Invalid command, type [help] to view all commands. From 2e634808169d0534b815b1dbbf0be7021b6513c9 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 27 Mar 2024 00:50:28 +0800 Subject: [PATCH 056/274] Edit water class --- src/main/java/seedu/fitnus/Water.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/Water.java index c7d4c8d619..82af04a18c 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -8,13 +8,12 @@ public Water(int amount) { waterIntake = amount; } - public static Water getInstance(int amount) { + public static void getInstance(int amount) { if (instance == null) { instance = new Water(amount); } else { addWaterIntake(amount); } - return instance; } public static int getWater() { From 1d8a86d1536eda23c23bc5725644a3b3ecb900a5 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 27 Mar 2024 01:00:52 +0800 Subject: [PATCH 057/274] Fix bug when clearing water --- data/DrinkList.txt | 2 +- src/main/java/seedu/fitnus/user/User.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/data/DrinkList.txt b/data/DrinkList.txt index df399cdc13..8822aa6e81 100644 --- a/data/DrinkList.txt +++ b/data/DrinkList.txt @@ -1 +1 @@ -water,10100 +water,400 diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index e1d3090ddc..737b1b6589 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -283,6 +283,7 @@ public void handleDeleteDrink(String command) { public void handleClear() { mealList.clear(); drinkList.clear(); + Water.editWaterIntake(0); assert mealList.isEmpty(): "clearing of meal list failed"; assert drinkList.isEmpty(): "clearing of drink list failed"; From b21bc7c2ea6226a7d15de76f00284864465cbfdd Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Wed, 27 Mar 2024 17:19:38 +0800 Subject: [PATCH 058/274] Add exercise feature Added exercise feature which allows users to track their exercise, the duration as well as the intensity in 3 different levels (HIGH, MEDIUM, LOW). Also allows to track how many calories burnt in total. --- src/main/java/seedu/fitnus/Exercise.java | 106 ++++++++++++++++++ .../java/seedu/fitnus/ExerciseIntensity.java | 6 + src/main/java/seedu/fitnus/Parser.java | 60 ++++++++++ src/main/java/seedu/fitnus/Ui.java | 1 + .../IncompleteExerciseException.java | 4 + .../UnregisteredExerciseException.java | 4 + src/main/java/seedu/fitnus/user/User.java | 46 +++++++- 7 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 src/main/java/seedu/fitnus/Exercise.java create mode 100644 src/main/java/seedu/fitnus/ExerciseIntensity.java create mode 100644 src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java create mode 100644 src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java new file mode 100644 index 0000000000..39d6f48a7b --- /dev/null +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -0,0 +1,106 @@ +package seedu.fitnus; + +import seedu.fitnus.exception.UnregisteredExerciseException; + +import java.util.HashMap; + +public class Exercise { + private static HashMap exerciseDetails = new HashMap<>(); + private String name; + private int duration; // Duration in minutes + private ExerciseIntensity intensity; + private int caloriesBurnt; + + // Constructor with only duration and exercise name + public Exercise(String name, int duration, ExerciseIntensity intensity) throws UnregisteredExerciseException { + assert name != null : "Name must not be null"; + this.name = name; + assert duration > 0 : "Duration must be greater than 0"; + this.duration = duration; + assert isValidIntensity(intensity) : "Intensity must be HIGH, MEDIUM, or LOW"; + this.intensity = intensity; + setCaloriesBurnt(); // Assign exercise details based on the name and intensity + } + + // Add exercise details to the static HashMap + static { + exerciseDetails.put("running", new int[]{8, 5, 3}); + exerciseDetails.put("cycling", new int[]{6, 4, 2}); + exerciseDetails.put("swimming", new int[]{10, 7, 4}); + } + + // Method to set exercise details based on exercise name + private void setCaloriesBurnt() throws UnregisteredExerciseException { + int[] details = exerciseDetails.get(name); + if (details == null) { + throw new UnregisteredExerciseException(); + } + this.caloriesBurnt = duration * details[intensity.ordinal()]; + } + + private boolean isValidIntensity(ExerciseIntensity intensity) { + return intensity == ExerciseIntensity.HIGH || intensity == ExerciseIntensity.MEDIUM || + intensity == ExerciseIntensity.LOW; + } + + // Getter methods + public String getName() { + return name; + } + + public int getDuration() { + return duration; + } + + public ExerciseIntensity getIntensity() { + return intensity; + } + + // Setter method for name + public void setName(String name) { + this.name = name; + } + + // Setter method for duration + public void setDuration(int duration) { + this.duration = duration; + } + + // Setter method for intensity + public void setIntensity(ExerciseIntensity intensity) { + this.intensity = intensity; + } + + public int getCaloriesBurnt() { + return caloriesBurnt; + } + + // Method to print exercise details + public static void handleInfoExercise(String command) throws UnregisteredExerciseException { + String name = Parser.parseInfoExercise(command); + int[] details = exerciseDetails.get(name); + if (details == null) { + throw new UnregisteredExerciseException(); + } + System.out.println("Exercise: " + name); + System.out.println("Calories Burnt: "); + System.out.println("HIGH intensity: " + details[0]); + System.out.println("MEDIUM intensity: " + details[1]); + System.out.println("LOW intensity: " + details[2]); + } + + // Print all available exercises registered in the database + public static void printAvailableExercises() { + System.out.print("Available exercises: "); + for (String exercise : exerciseDetails.keySet()) { + System.out.print(exercise); + System.out.print(", "); + } + System.out.print("etc."); + System.out.println(); + } + + public static HashMap getExerciseDetails() { + return exerciseDetails; + } +} diff --git a/src/main/java/seedu/fitnus/ExerciseIntensity.java b/src/main/java/seedu/fitnus/ExerciseIntensity.java new file mode 100644 index 0000000000..f274be48e1 --- /dev/null +++ b/src/main/java/seedu/fitnus/ExerciseIntensity.java @@ -0,0 +1,6 @@ +package seedu.fitnus; +public enum ExerciseIntensity { + HIGH, + MEDIUM, + LOW +} diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index ee3ab1be49..847955d558 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -2,10 +2,12 @@ import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.InvalidCommandException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.invalidIndexException; +import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.user.User; public class Parser { @@ -22,6 +24,10 @@ public class Parser { public static int mealStorageSize; public static String drinkStorageDescription; public static int drinkStorageSize; + public static String exerciseDescription; + public static int exerciseDuration; + + public static ExerciseIntensity exerciseIntensity; private User user; public Parser(User user) { @@ -36,10 +42,14 @@ public void handleCommand(String command) { user.handleMeal(command); } else if (command.startsWith("drink")) { user.handleDrink(command); + } else if (command.startsWith("exercise")) { + user.handleExercise(command); } else if (command.startsWith("infoMeal")) { Meal.handleInfoMeal(command); } else if (command.startsWith("infoDrink")) { Drink.handleInfoDrink(command); + } else if (command.startsWith("infoExercise")) { + Exercise.handleInfoExercise(command); } else if (command.equals("calories")) { user.handleViewCalories(); } else if (command.equals("carbs")) { @@ -60,6 +70,8 @@ public void handleCommand(String command) { user.handleListDrinks(); } else if (command.equals("listEverything")) { user.handleListEverything(); + }else if (command.equals("listExercises")) { + user.handleListExercises(); } else if (command.startsWith("editMeal")) { User.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { @@ -70,6 +82,8 @@ public void handleCommand(String command) { user.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { user.handleDeleteDrink(command); + } else if (command.equals("caloriesBurnt")) { + user.handleCaloriesBurnt(); } else if (command.equals("clear")) { user.handleClear(); } else { @@ -81,6 +95,8 @@ public void handleCommand(String command) { System.out.println("Incomplete command, the format must be [drink d/DRINK s/SERVING_SIZE]."); } catch (IncompleteMealException e) { System.out.println("Incomplete command, the format must be [ate m/MEAL s/SERVING_SIZE]."); + } catch (IncompleteExerciseException e) { + System.out.println("Incomplete command, the format must be [exercise e/MEAL d/SERVING_SIZE]."); } catch (UnregisteredDrinkException e) { System.out.println("Sorry that drink is not registered in the database."); } catch (UnregisteredMealException e) { @@ -88,6 +104,8 @@ public void handleCommand(String command) { } catch (invalidIndexException e) { System.out.println("Sorry the index you provided is invalid, check [listMeals or listDrinks] " + "to view valid " + "indexes."); + } catch (UnregisteredExerciseException e) { + System.out.println("Sorry that exercise is not registered in the database."); } } @@ -95,8 +113,11 @@ public static void handleHelp() { System.out.println("here's all the valid commands i recognise: "); System.out.println("- Add a meal eaten: ate m/MEAL s/SERVING_SIZE"); System.out.println("- Add a drink: drink d/DRINK s/VOLUME(ML)"); + System.out.println("- Track and exercise: exercise e/EXERCISE d/DURATION(MINUTES) " + + "i/INTENSITY(HIGH, MEDIUM, LOW)"); System.out.println("- Find the information about a certain meal: infoMeal MEAL"); System.out.println("- Find the information about a certain drink: infoDrink DRINK"); + System.out.println("- Find the information about a certain exercise: infoExercise EXERCISE"); System.out.println("- View daily calories consumed: calories"); System.out.println("- View daily carbohydrates consumed: carbs"); System.out.println("- View daily proteins consumed: protein"); @@ -104,8 +125,10 @@ public static void handleHelp() { System.out.println("- View daily sugar consumed: sugar"); System.out.println("- View daily fiber consumed: fiber"); System.out.println("- View daily water consumption: viewWater"); + System.out.println("- View daily calories burnt: caloriesBurnt"); System.out.println("- List meal intake: listMeals"); System.out.println("- List drink intake: listDrinks"); + System.out.println("- List exercises done: listExercises"); System.out.println("- List entire food intake for the day: listEverything"); System.out.println("- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE"); System.out.println("- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE"); @@ -163,6 +186,15 @@ public static String parseInfoMeal(String command) throws UnregisteredMealExcept return infoMealDescription; } + public static String parseInfoExercise(String command) throws UnregisteredExerciseException { + int exerciseIndex = 13; + String infoExerciseDescription = command.substring(exerciseIndex).trim(); + if (!Exercise.getExerciseDetails().containsKey(infoExerciseDescription)) { + throw new UnregisteredExerciseException(); + } + return infoExerciseDescription; + } + public static String parseInfoDrink(String command) throws UnregisteredDrinkException { int drinkIndex = 10; String infoDrinkDescription = command.substring(drinkIndex).trim(); @@ -202,4 +234,32 @@ public static void parseDrinkStorage(String data) { drinkStorageDescription = arrayOfDrinkData[0]; drinkStorageSize = Integer.parseInt(arrayOfDrinkData[1]); } + + public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException { + if (!command.contains("e/") || !command.contains("d/") || !command.contains("i/")) { + throw new IncompleteExerciseException(); + } + int descriptionIndex = command.indexOf("e/") + 2; + int durationIndex = command.indexOf("d/") + 2; + int intensityIndex = command.indexOf("i/") + 2; + if (intensityIndex >= command.length()) { + throw new IncompleteExerciseException(); + } + exerciseDescription = command.substring(descriptionIndex, durationIndex - 2).trim().toLowerCase(); + if (exerciseDescription.isEmpty()) { + throw new IncompleteExerciseException(); + } + if (!Exercise.getExerciseDetails().containsKey(exerciseDescription)) { + throw new UnregisteredExerciseException(); + } + + exerciseDuration = Integer.parseInt(command.substring(durationIndex, intensityIndex - 2).trim()); + + String intensityString = command.substring(intensityIndex).trim().toUpperCase(); + try { + exerciseIntensity = ExerciseIntensity.valueOf(intensityString); + } catch (IllegalArgumentException e) { + throw new IncompleteExerciseException(); // Invalid intensity + } + } } diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 1dc5bb1d7e..13006e9339 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -23,6 +23,7 @@ public void printWelcomeMessage() { System.out.println("What would you like to track today?"); Meal.printAvailableMeals(); Drink.printAvailableDrinks(); + Exercise.printAvailableExercises(); System.out.println(LINE); } diff --git a/src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java b/src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java new file mode 100644 index 0000000000..cbd0327434 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java @@ -0,0 +1,4 @@ +package seedu.fitnus.exception; + +public class IncompleteExerciseException extends Exception{ +} diff --git a/src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java b/src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java new file mode 100644 index 0000000000..d43b8f2480 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java @@ -0,0 +1,4 @@ +package seedu.fitnus.exception; + +public class UnregisteredExerciseException extends Exception { +} diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 737b1b6589..277377e5bc 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -1,16 +1,19 @@ package seedu.fitnus.user; import seedu.fitnus.Drink; +import seedu.fitnus.Exercise; +import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; -import seedu.fitnus.storage.Storage; - import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.invalidIndexException; +import seedu.fitnus.storage.Storage; import java.io.FileNotFoundException; import java.io.IOException; @@ -19,11 +22,13 @@ public class User { protected static ArrayList mealList; protected static ArrayList drinkList; + protected static ArrayList exerciseList; public User(Storage mealStorage, Storage drinkStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); + exerciseList = new ArrayList<>(); loadMeal(mealStorage); loadDrink(drinkStorage); } @@ -153,7 +158,7 @@ public void handleViewWaterIntake() { System.out.println("Total water intake: " + waterIntake + " ml"); } - public static void handleViewFiber() { + public void handleViewFiber() { int fibreCount = 0; for (Meal meal: mealList) { fibreCount += meal.getFiber(); @@ -190,6 +195,14 @@ public void printMealList(int startIndex) { + currentMeal.getServingSize() + ")"); } } + + public void printExerciseList() { + for (int i = 0; i < exerciseList.size(); i++) { + Exercise currentExercise = exerciseList.get(i); + System.out.println((i+1) + ". " + currentExercise.getName() + "duration:" + currentExercise.getDuration() + + " (intensity: " + currentExercise.getIntensity() + ")"); + } + } public void handleListMeals() { System.out.println("here's what you have eaten today"); if (mealList.isEmpty()) { @@ -280,6 +293,17 @@ public void handleDeleteDrink(String command) { System.out.println("Removed " + drinkName + " from drinks"); } + public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException { + Parser.parseExercise(command); + String exerciseType = Parser.exerciseDescription; + int duration = Parser.exerciseDuration; + ExerciseIntensity intensity = Parser.exerciseIntensity; + exerciseList.add(new Exercise(exerciseType, duration, intensity)); + assert !exerciseList.isEmpty(): "failed to track exercise"; + + System.out.println("Tracked " + duration + " minutes of " + exerciseType); + } + public void handleClear() { mealList.clear(); drinkList.clear(); @@ -290,4 +314,20 @@ public void handleClear() { System.out.println("All entries have been deleted"); } + public void handleCaloriesBurnt() { + int caloriesBurnt = 0; + for (Exercise exercise: exerciseList) { + caloriesBurnt += exercise.getCaloriesBurnt(); + } + System.out.println("Total calories burnt: " + caloriesBurnt); + } + + public void handleListExercises() { + System.out.println("here's the exercises you've done today"); + if (exerciseList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printExerciseList(); + } + } } From 11a4daa2867376583860ed6067242afc9e93cd9e Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Wed, 27 Mar 2024 17:27:22 +0800 Subject: [PATCH 059/274] Add exercise feature Added exercise feature which allows users to track their exercise, the duration as well as the intensity in 3 different levels (HIGH, MEDIUM, LOW). Also allows to track how many calories burnt in total. --- text-ui-test/ACTUAL-SH.TXT | 1 + text-ui-test/EXPECTED-SH.TXT | 1 + text-ui-test/EXPECTED.TXT | 1 + text-ui-test/data/DrinkList.txt | 1 + text-ui-test/data/MealList.txt | 4 ++++ 5 files changed, 8 insertions(+) diff --git a/text-ui-test/ACTUAL-SH.TXT b/text-ui-test/ACTUAL-SH.TXT index dc5d76c0a8..ae8b803e9e 100644 --- a/text-ui-test/ACTUAL-SH.TXT +++ b/text-ui-test/ACTUAL-SH.TXT @@ -3,6 +3,7 @@ Hello! Welcome to FitNUS What would you like to track today? Available meals: pizza, chicken rice, fried rice, etc. Available drinks: lemon tea, sprite, water, milk coffee, etc. +Available exercises: running, swimming, cycling, etc. _________________________________________________________________ _________________________________________________________________ Invalid command, type [help] to view all commands. diff --git a/text-ui-test/EXPECTED-SH.TXT b/text-ui-test/EXPECTED-SH.TXT index dc5d76c0a8..ae8b803e9e 100644 --- a/text-ui-test/EXPECTED-SH.TXT +++ b/text-ui-test/EXPECTED-SH.TXT @@ -3,6 +3,7 @@ Hello! Welcome to FitNUS What would you like to track today? Available meals: pizza, chicken rice, fried rice, etc. Available drinks: lemon tea, sprite, water, milk coffee, etc. +Available exercises: running, swimming, cycling, etc. _________________________________________________________________ _________________________________________________________________ Invalid command, type [help] to view all commands. diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index dc5d76c0a8..ae8b803e9e 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -3,6 +3,7 @@ Hello! Welcome to FitNUS What would you like to track today? Available meals: pizza, chicken rice, fried rice, etc. Available drinks: lemon tea, sprite, water, milk coffee, etc. +Available exercises: running, swimming, cycling, etc. _________________________________________________________________ _________________________________________________________________ Invalid command, type [help] to view all commands. diff --git a/text-ui-test/data/DrinkList.txt b/text-ui-test/data/DrinkList.txt index e69de29bb2..1d89457c3e 100644 --- a/text-ui-test/data/DrinkList.txt +++ b/text-ui-test/data/DrinkList.txt @@ -0,0 +1 @@ +water,0 diff --git a/text-ui-test/data/MealList.txt b/text-ui-test/data/MealList.txt index 1e3b80d0a9..ea5580fbe8 100644 --- a/text-ui-test/data/MealList.txt +++ b/text-ui-test/data/MealList.txt @@ -7,3 +7,7 @@ chicken rice,2 fried rice,1 chicken rice,2 fried rice,1 +chicken rice,2 +fried rice,1 +chicken rice,2 +fried rice,1 From 2f73cfb85043b4dd9a579f47af07f6864d55e7f4 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 27 Mar 2024 20:43:30 +0800 Subject: [PATCH 060/274] Add assertions for storage --- src/main/java/seedu/fitnus/storage/Storage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/seedu/fitnus/storage/Storage.java b/src/main/java/seedu/fitnus/storage/Storage.java index b714c55fbe..0dfd52563d 100644 --- a/src/main/java/seedu/fitnus/storage/Storage.java +++ b/src/main/java/seedu/fitnus/storage/Storage.java @@ -19,6 +19,8 @@ public Storage(String folderPath, String filePath) { this.textContent = ""; this.folderPath = folderPath; this.filePath = filePath; + assert (filePath != null && !filePath.isEmpty()) : "File path should not be empty"; + assert (folderPath != null && !folderPath.isEmpty()) : "Folder path should not be empty"; } /** @@ -35,6 +37,7 @@ public void appendTextContent(String content) { * @throws FileNotFoundException If the file does not exist */ public ArrayList readFile() throws FileNotFoundException { + assert (filePath != null && !filePath.isEmpty()) : "File path should not be empty"; ArrayList input = new ArrayList<>(); File file = new File(filePath); Scanner s = new Scanner(file); From e8b918cf2bd3da19380457432d333d8e92fc6b45 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 27 Mar 2024 20:45:50 +0800 Subject: [PATCH 061/274] Move parser to new package --- src/main/java/seedu/fitnus/Drink.java | 2 ++ src/main/java/seedu/fitnus/Exercise.java | 1 + src/main/java/seedu/fitnus/Meal.java | 1 + src/main/java/seedu/fitnus/Ui.java | 1 + src/main/java/seedu/fitnus/{ => parser}/Parser.java | 6 +++++- src/main/java/seedu/fitnus/user/User.java | 2 +- src/test/java/seedu/fitnus/user/UserTest.java | 2 +- 7 files changed, 12 insertions(+), 3 deletions(-) rename src/main/java/seedu/fitnus/{ => parser}/Parser.java (98%) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 5c3b892f3d..c6dc09bbf5 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -1,6 +1,8 @@ package seedu.fitnus; import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.parser.Parser; + import java.util.HashMap; public class Drink { diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index 39d6f48a7b..39f97cfa48 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -1,6 +1,7 @@ package seedu.fitnus; import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.parser.Parser; import java.util.HashMap; diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 82171e6993..85c371c542 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -1,6 +1,7 @@ package seedu.fitnus; import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.parser.Parser; import java.util.HashMap; diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 13006e9339..b20305130f 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import seedu.fitnus.parser.Parser; import seedu.fitnus.storage.Storage; import seedu.fitnus.user.User; diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java similarity index 98% rename from src/main/java/seedu/fitnus/Parser.java rename to src/main/java/seedu/fitnus/parser/Parser.java index 847955d558..f81b3e7b73 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,5 +1,9 @@ -package seedu.fitnus; +package seedu.fitnus.parser; +import seedu.fitnus.Drink; +import seedu.fitnus.Exercise; +import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.Meal; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.IncompleteExerciseException; diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 277377e5bc..cce577ae75 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -4,7 +4,7 @@ import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; -import seedu.fitnus.Parser; +import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteExerciseException; diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 46ca720b03..9ace6d3fcf 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Test; import seedu.fitnus.Drink; import seedu.fitnus.Meal; -//import seedu.fitnus.Parser; +//import seedu.fitnus.parser.Parser; //import seedu.fitnus.Water; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.UnregisteredMealException; From 78332f009c62eba662ad139988c03fe69b3cf593 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 27 Mar 2024 21:14:25 +0800 Subject: [PATCH 062/274] Add JUnit test for Parser --- .../java/seedu/fitnus/parser/ParserTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/test/java/seedu/fitnus/parser/ParserTest.java diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java new file mode 100644 index 0000000000..2a62415671 --- /dev/null +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -0,0 +1,39 @@ +package seedu.fitnus.parser; + +import org.junit.jupiter.api.Test; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredMealException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +public class ParserTest { + @Test + public void parseMeal_validInputs_success() throws IncompleteMealException, UnregisteredMealException { + String command = "ate m/chicken rice s/1"; + Parser.parseMeal(command); + assertEquals("chicken rice", Parser.mealDescription); + assertEquals(1, Parser.mealSize); + } + + @Test + public void parseDrink_validInputs_success() throws IncompleteDrinkException, UnregisteredDrinkException { + String command = "drink d/sprite s/300"; + Parser.parseDrink(command); + assertEquals("sprite", Parser.drinkDescription); + assertEquals(300, Parser.drinkSize); + } + + @Test + public void parseInfoMeal_unregisteredMeal_exceptionThrown() { + String command = "infoMeal blablabla"; + try { + Parser.parseInfoMeal(command); + } catch (UnregisteredMealException e) { + assertTrue(true); + } + } +} From 99f60fa4a60a4193dd8cb7ffe9d769bef239378c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 11:32:24 +0800 Subject: [PATCH 063/274] Remove text-ui-test folder --- text-ui-test/ACTUAL-SH.TXT | 19 ------------------- text-ui-test/EXPECTED-SH.TXT | 19 ------------------- text-ui-test/EXPECTED.TXT | 19 ------------------- text-ui-test/data/DrinkList.txt | 1 - text-ui-test/data/MealList.txt | 13 ------------- text-ui-test/input.txt | 4 ---- text-ui-test/runtest.bat | 19 ------------------- text-ui-test/runtest.sh | 22 ---------------------- 8 files changed, 116 deletions(-) delete mode 100644 text-ui-test/ACTUAL-SH.TXT delete mode 100644 text-ui-test/EXPECTED-SH.TXT delete mode 100644 text-ui-test/EXPECTED.TXT delete mode 100644 text-ui-test/data/DrinkList.txt delete mode 100644 text-ui-test/data/MealList.txt delete mode 100644 text-ui-test/input.txt delete mode 100644 text-ui-test/runtest.bat delete mode 100755 text-ui-test/runtest.sh diff --git a/text-ui-test/ACTUAL-SH.TXT b/text-ui-test/ACTUAL-SH.TXT deleted file mode 100644 index ae8b803e9e..0000000000 --- a/text-ui-test/ACTUAL-SH.TXT +++ /dev/null @@ -1,19 +0,0 @@ -_________________________________________________________________ -Hello! Welcome to FitNUS -What would you like to track today? -Available meals: pizza, chicken rice, fried rice, etc. -Available drinks: lemon tea, sprite, water, milk coffee, etc. -Available exercises: running, swimming, cycling, etc. -_________________________________________________________________ -_________________________________________________________________ -Invalid command, type [help] to view all commands. -_________________________________________________________________ -_________________________________________________________________ -Added 2 serving of chicken rice -_________________________________________________________________ -_________________________________________________________________ -Added 1 serving of fried rice -_________________________________________________________________ -_________________________________________________________________ -Bye. Hope to see you again soon! -_________________________________________________________________ diff --git a/text-ui-test/EXPECTED-SH.TXT b/text-ui-test/EXPECTED-SH.TXT deleted file mode 100644 index ae8b803e9e..0000000000 --- a/text-ui-test/EXPECTED-SH.TXT +++ /dev/null @@ -1,19 +0,0 @@ -_________________________________________________________________ -Hello! Welcome to FitNUS -What would you like to track today? -Available meals: pizza, chicken rice, fried rice, etc. -Available drinks: lemon tea, sprite, water, milk coffee, etc. -Available exercises: running, swimming, cycling, etc. -_________________________________________________________________ -_________________________________________________________________ -Invalid command, type [help] to view all commands. -_________________________________________________________________ -_________________________________________________________________ -Added 2 serving of chicken rice -_________________________________________________________________ -_________________________________________________________________ -Added 1 serving of fried rice -_________________________________________________________________ -_________________________________________________________________ -Bye. Hope to see you again soon! -_________________________________________________________________ diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT deleted file mode 100644 index ae8b803e9e..0000000000 --- a/text-ui-test/EXPECTED.TXT +++ /dev/null @@ -1,19 +0,0 @@ -_________________________________________________________________ -Hello! Welcome to FitNUS -What would you like to track today? -Available meals: pizza, chicken rice, fried rice, etc. -Available drinks: lemon tea, sprite, water, milk coffee, etc. -Available exercises: running, swimming, cycling, etc. -_________________________________________________________________ -_________________________________________________________________ -Invalid command, type [help] to view all commands. -_________________________________________________________________ -_________________________________________________________________ -Added 2 serving of chicken rice -_________________________________________________________________ -_________________________________________________________________ -Added 1 serving of fried rice -_________________________________________________________________ -_________________________________________________________________ -Bye. Hope to see you again soon! -_________________________________________________________________ diff --git a/text-ui-test/data/DrinkList.txt b/text-ui-test/data/DrinkList.txt deleted file mode 100644 index 1d89457c3e..0000000000 --- a/text-ui-test/data/DrinkList.txt +++ /dev/null @@ -1 +0,0 @@ -water,0 diff --git a/text-ui-test/data/MealList.txt b/text-ui-test/data/MealList.txt deleted file mode 100644 index ea5580fbe8..0000000000 --- a/text-ui-test/data/MealList.txt +++ /dev/null @@ -1,13 +0,0 @@ -chicken rice,2 -chicken rice,2 -fried rice,1 -chicken rice,2 -fried rice,1 -chicken rice,2 -fried rice,1 -chicken rice,2 -fried rice,1 -chicken rice,2 -fried rice,1 -chicken rice,2 -fried rice,1 diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt deleted file mode 100644 index 9bc19b21c4..0000000000 --- a/text-ui-test/input.txt +++ /dev/null @@ -1,4 +0,0 @@ -add m/chicken rice s/2 -ate m/chicken rice s/2 -ate m/fried rice s/1 -exit \ No newline at end of file diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat deleted file mode 100644 index 25ac7a2989..0000000000 --- a/text-ui-test/runtest.bat +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -setlocal enableextensions -pushd %~dp0 - -cd .. -call gradlew clean shadowJar - -cd build\libs -for /f "tokens=*" %%a in ( - 'dir /b *.jar' -) do ( - set jarloc=%%a -) - -java -jar %jarloc% < ..\..\text-ui-test\input.txt > ..\..\text-ui-test\ACTUAL.TXT - -cd ..\..\text-ui-test - -FC ACTUAL.TXT EXPECTED.TXT >NUL && ECHO Test passed! || Echo Test failed! diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh deleted file mode 100755 index c11c98e2e6..0000000000 --- a/text-ui-test/runtest.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# change to script directory -cd "${0%/*}" - -cd .. -./gradlew clean shadowJar - -cd text-ui-test - -java -jar $(find ../build/libs/ -mindepth 1 -print -quit) < input.txt > ACTUAL-SH.TXT - -diff EXPECTED-SH.TXT ACTUAL-SH.TXT - -if [ $? -eq 0 ] -then - echo "Test passed!" - exit 0 -else - echo "Test failed!" - exit 1 -fi From cfa1b44f0a6645064b7e377d0f5baef9ea59f958 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 11:39:26 +0800 Subject: [PATCH 064/274] Add Date variable to Meal class --- src/main/java/seedu/fitnus/Date.java | 20 ++++++++++++++++++++ src/main/java/seedu/fitnus/Meal.java | 7 ++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/fitnus/Date.java diff --git a/src/main/java/seedu/fitnus/Date.java b/src/main/java/seedu/fitnus/Date.java new file mode 100644 index 0000000000..1f99668082 --- /dev/null +++ b/src/main/java/seedu/fitnus/Date.java @@ -0,0 +1,20 @@ +package seedu.fitnus; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class Date { + // reference: https://www.javatpoint.com/java-get-current-date + private static java.sql.Date currentDate; + + public Date() { + long millis = System.currentTimeMillis(); + java.sql.Date date = new java.sql.Date(millis); + + this.currentDate = date; + } + + public static java.sql.Date getCurrentDate() { + return currentDate; + } +} diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 82171e6993..0dced16bf9 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -8,6 +8,7 @@ public class Meal { private static HashMap nutrientDetails = new HashMap<>(); private String name; private int servingSize; + private Date dateAdded; private int calories; private int carbs; private int protein; @@ -16,12 +17,13 @@ public class Meal { private int sugar; // Constructor with only serving size and meal name - public Meal(String name, int servingSize) { + public Meal(String name, int servingSize, Date currentDate) { assert name != null : "Name must not be null"; this.name = name; assert servingSize > 0 : "Serving size must be greater than 0"; this.servingSize = servingSize; setNutrientValues(name); // Assign nutrient values based on the name + this.dateAdded = currentDate; } // Add nutrient details to the static HashMap @@ -103,4 +105,7 @@ public static HashMap getNutrientDetails() { return nutrientDetails; } + public Date getDate() { + return dateAdded; + } } From 63488b0fde8d94acb80c7f3c8a939a19d4e33350 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 12:15:53 +0800 Subject: [PATCH 065/274] Add date when saving meal --- src/main/java/seedu/fitnus/Date.java | 12 +++++++----- src/main/java/seedu/fitnus/Meal.java | 6 +++--- src/main/java/seedu/fitnus/Parser.java | 1 + src/main/java/seedu/fitnus/user/User.java | 13 +++++++++---- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/java/seedu/fitnus/Date.java b/src/main/java/seedu/fitnus/Date.java index 1f99668082..1deeb2ec0b 100644 --- a/src/main/java/seedu/fitnus/Date.java +++ b/src/main/java/seedu/fitnus/Date.java @@ -1,20 +1,22 @@ package seedu.fitnus; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; +import java.text.SimpleDateFormat; public class Date { // reference: https://www.javatpoint.com/java-get-current-date - private static java.sql.Date currentDate; + private static String currentDate; public Date() { long millis = System.currentTimeMillis(); java.sql.Date date = new java.sql.Date(millis); - this.currentDate = date; + SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy"); + String formattedDate = DATE_FORMAT.format(date); + + this.currentDate = formattedDate; } - public static java.sql.Date getCurrentDate() { + public static String getDate() { return currentDate; } } diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 0dced16bf9..aaa0312c5a 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -8,7 +8,7 @@ public class Meal { private static HashMap nutrientDetails = new HashMap<>(); private String name; private int servingSize; - private Date dateAdded; + private String dateAdded; private int calories; private int carbs; private int protein; @@ -17,7 +17,7 @@ public class Meal { private int sugar; // Constructor with only serving size and meal name - public Meal(String name, int servingSize, Date currentDate) { + public Meal(String name, int servingSize, String currentDate) { assert name != null : "Name must not be null"; this.name = name; assert servingSize > 0 : "Serving size must be greater than 0"; @@ -105,7 +105,7 @@ public static HashMap getNutrientDetails() { return nutrientDetails; } - public Date getDate() { + public String getDate() { return dateAdded; } } diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 847955d558..66b843361d 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -28,6 +28,7 @@ public class Parser { public static int exerciseDuration; public static ExerciseIntensity exerciseIntensity; + public static String mealStorageDate; private User user; public Parser(User user) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 277377e5bc..ab4e4cea2b 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -1,5 +1,6 @@ package seedu.fitnus.user; +import seedu.fitnus.Date; import seedu.fitnus.Drink; import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; @@ -41,7 +42,8 @@ public void loadMeal(Storage mealStorage) { Parser.parseMealStorage(s); String mealDescription = Parser.mealStorageDescription; int mealSize = Parser.mealStorageSize; - mealList.add(new Meal(mealDescription, mealSize)); + String currentDate = Parser.mealStorageDate; + mealList.add(new Meal(mealDescription, mealSize, currentDate)); } } } catch (FileNotFoundException e) { @@ -71,7 +73,7 @@ public void loadDrink(Storage drinkStorage) { public void saveMeal(Storage mealStorage) { for (Meal meal : mealList) { - String mealSavedData = meal.getName() + "," + meal.getServingSize(); + String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); mealStorage.appendTextContent(mealSavedData); } try { @@ -100,7 +102,9 @@ public void handleMeal(String command) throws IncompleteMealException, Unregiste String mealName = Parser.mealDescription; int servingSize = Parser.mealSize; - mealList.add(new Meal(mealName, servingSize)); + Date currentDate = new Date(); + + mealList.add(new Meal(mealName, servingSize, currentDate.getDate())); assert !mealList.isEmpty(): "failed to add meal"; System.out.println("Added " + servingSize + " serving of " + mealName); @@ -253,7 +257,8 @@ public static void handleEditMealServingSize(String command) throws invalidIndex } String mealName = mealList.get(Parser.editMealIndex).getName(); - Meal updatedMeal = new Meal(mealName, Parser.editMealSize); + String mealDate = mealList.get(Parser.editMealIndex).getDate(); + Meal updatedMeal = new Meal(mealName, Parser.editMealSize, mealDate); mealList.set(Parser.editMealIndex, updatedMeal); System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } From 5c3e0d2b9b41b3e00df3ef4a9e491b09673df750 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 12:26:08 +0800 Subject: [PATCH 066/274] Add date variable to Drink class --- src/main/java/seedu/fitnus/Drink.java | 7 ++++++- src/main/java/seedu/fitnus/Parser.java | 5 ++++- src/main/java/seedu/fitnus/user/User.java | 13 +++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 5c3b892f3d..2c796ed91f 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -7,16 +7,18 @@ public class Drink { private static HashMap nutrientDetails = new HashMap<>(); private String name; private int drinkVolume; + private String dateAdded; private int calories; private int carbs; private int sugar; private int protein; private int fat; - public Drink(String name, int volume) { + public Drink(String name, int volume, String currentDate) { this.name = name; this.drinkVolume = volume; setNutrientValues(name); + this.dateAdded = currentDate; } // Add nutrient details per 100 milliliter to the static HashMap @@ -89,4 +91,7 @@ public static HashMap getNutrientDetails() { return nutrientDetails; } + public String getDate() { + return dateAdded; + } } diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 66b843361d..8c33673fa4 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -22,13 +22,16 @@ public class Parser { public static int editWaterSize; public static String mealStorageDescription; public static int mealStorageSize; + public static String mealStorageDate; + public static String drinkStorageDescription; public static int drinkStorageSize; + public static String drinkStorageDate; + public static String exerciseDescription; public static int exerciseDuration; public static ExerciseIntensity exerciseIntensity; - public static String mealStorageDate; private User user; public Parser(User user) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index ab4e4cea2b..f3f8875e30 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -58,11 +58,12 @@ public void loadDrink(Storage drinkStorage) { for (String s : drinkStorageList) { Parser.parseDrinkStorage(s); String drinkDescription = Parser.drinkStorageDescription; + String drinkDate = Parser.drinkStorageDate; int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { Water.getInstance(drinkSize); } else { - drinkList.add(new Drink(drinkDescription, drinkSize)); + drinkList.add(new Drink(drinkDescription, drinkSize, drinkDate)); } } } @@ -87,7 +88,7 @@ public void saveDrink(Storage drinkStorage) { String waterSavedData = "water" + "," + Water.getWater(); drinkStorage.appendTextContent(waterSavedData); for (Drink drink : drinkList) { - String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize(); + String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); drinkStorage.appendTextContent(drinkSavedData); } try { @@ -115,10 +116,12 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; + Date currentDate = new Date(); + if (drinkName.equals("water")) { Water.getInstance(servingSize); } else { - drinkList.add(new Drink(drinkName, servingSize)); + drinkList.add(new Drink(drinkName, servingSize, currentDate.getDate())); } System.out.println("Added " + servingSize + " ml of " + drinkName); } @@ -271,7 +274,9 @@ public static void handleEditDrinkServingSize(String command) throws invalidInde throw new invalidIndexException(); } String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); - Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize); + String drinkDate = drinkList.get(Parser.editDrinkIndex).getDate(); + + Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize, drinkDate); drinkList.set(Parser.editDrinkIndex, updatedDrink); System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } From 663f6789a1ec0ff67a91731c193c4ab061a30c65 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 12:38:19 +0800 Subject: [PATCH 067/274] Add date variable to Water class --- src/main/java/seedu/fitnus/Water.java | 12 +++++++++--- src/main/java/seedu/fitnus/user/User.java | 6 +++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/Water.java index 82af04a18c..6ba48b6d5b 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -3,14 +3,16 @@ public class Water { private static Water instance = null; private static int waterIntake = 0; + private static String dateAdded; - public Water(int amount) { + public Water(int amount, String dateAdded) { waterIntake = amount; + this.dateAdded = dateAdded; } - public static void getInstance(int amount) { + public static void getInstance(int amount, String dateAdded) { if (instance == null) { - instance = new Water(amount); + instance = new Water(amount, dateAdded); } else { addWaterIntake(amount); } @@ -27,4 +29,8 @@ public static void addWaterIntake(int amount) { public static void editWaterIntake(int amount) { waterIntake = amount; } + + public static String getDate() { + return dateAdded; + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f3f8875e30..2ddb2a29fe 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -61,7 +61,7 @@ public void loadDrink(Storage drinkStorage) { String drinkDate = Parser.drinkStorageDate; int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { - Water.getInstance(drinkSize); + Water.getInstance(drinkSize, drinkDate); } else { drinkList.add(new Drink(drinkDescription, drinkSize, drinkDate)); } @@ -85,7 +85,7 @@ public void saveMeal(Storage mealStorage) { } public void saveDrink(Storage drinkStorage) { - String waterSavedData = "water" + "," + Water.getWater(); + String waterSavedData = "water" + "," + Water.getWater() + "," + Water.getDate(); drinkStorage.appendTextContent(waterSavedData); for (Drink drink : drinkList) { String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); @@ -119,7 +119,7 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis Date currentDate = new Date(); if (drinkName.equals("water")) { - Water.getInstance(servingSize); + Water.getInstance(servingSize, currentDate.getDate()); } else { drinkList.add(new Drink(drinkName, servingSize, currentDate.getDate())); } From ab5978470500a7d8cd57c7143e9fffdc859276bd Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 12:44:40 +0800 Subject: [PATCH 068/274] Remove IO redirection test --- .github/workflows/gradle.yml | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index fd8c44d086..133b0e7f2b 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -31,20 +31,4 @@ jobs: java-package: jdk+fx - name: Build and check with Gradle - run: ./gradlew check - - - name: Perform IO redirection test (*NIX) - if: runner.os == 'Linux' - working-directory: ${{ github.workspace }}/text-ui-test - run: ./runtest.sh - - - name: Perform IO redirection test (MacOS) - if: always() && runner.os == 'macOS' - working-directory: ${{ github.workspace }}/text-ui-test - run: ./runtest.sh - - - name: Perform IO redirection test (Windows) - if: always() && runner.os == 'Windows' - working-directory: ${{ github.workspace }}/text-ui-test - shell: cmd - run: runtest.bat \ No newline at end of file + run: ./gradlew check \ No newline at end of file From 0fa1b2572b5c0ce3c9fde691d436a838e86fac45 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 12:51:14 +0800 Subject: [PATCH 069/274] Update UserTest file --- src/test/java/seedu/fitnus/user/UserTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 46ca720b03..dde6381b94 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -3,8 +3,6 @@ import org.junit.jupiter.api.Test; import seedu.fitnus.Drink; import seedu.fitnus.Meal; -//import seedu.fitnus.Parser; -//import seedu.fitnus.Water; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.IncompleteDrinkException; @@ -27,7 +25,7 @@ public void sampleUser() { @Test public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException { - Meal newMeal = new Meal("pizza", 3); + Meal newMeal = new Meal("pizza", 3, "28-03-2024"); testMealList.add(newMeal); assertEquals("pizza", testMealList.get(0).getName()); @@ -52,7 +50,7 @@ public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWat @Test public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, UnregisteredDrinkException { - Drink newDrink = new Drink("sprite", 100); + Drink newDrink = new Drink("sprite", 100, "28-03-2024"); testDrinkList.add(newDrink); assertEquals("sprite", testDrinkList.get(0).getName()); From e9ddf40a905506ded63f8facbcec4bd536363038 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 16:25:54 +0800 Subject: [PATCH 070/274] Add more Junit test for User methods --- src/test/java/seedu/fitnus/user/UserTest.java | 118 +++++++++++++----- 1 file changed, 87 insertions(+), 31 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index dde6381b94..4cb17bd034 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -1,59 +1,115 @@ package seedu.fitnus.user; -import org.junit.jupiter.api.Test; import seedu.fitnus.Drink; +import seedu.fitnus.Exercise; import seedu.fitnus.Meal; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.UnregisteredMealException; + import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.storage.Storage; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.ArrayList; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; //import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class UserTest { - ArrayList testMealList = new ArrayList<>(); - ArrayList testDrinkList = new ArrayList<>(); + User testUser; + ArrayList testMealList; + ArrayList testDrinkList; + ArrayList testExerciseList; + private Storage testMealStorage; + private Storage testDrinkStorage; - @Test - public void sampleUser() { - assertTrue(true); + + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + @BeforeEach + public void setUp() { + testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); + testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); + testUser = new User(testMealStorage, testDrinkStorage); + + testMealList = testUser.mealList; + testDrinkList = testUser.drinkList; + + System.setOut(new PrintStream(outputStream)); } @Test - public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException { - Meal newMeal = new Meal("pizza", 3, "28-03-2024"); - testMealList.add(newMeal); + public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, InvalidServingSizeException { + String command = "ate m/pizza s/3"; + testUser.handleMeal(command); + + assertFalse(testMealList.isEmpty()); assertEquals("pizza", testMealList.get(0).getName()); assertEquals(3, testMealList.get(0).getServingSize()); } - /* @Test - public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWaterException { - try { - Parser.parseWater("water 1"); - new Water(Parser.waterSize); - } catch (IncompleteWaterException e) { - return; - } - - String error = "Incomplete command, the format must be [water s/SERVING_SIZE]."; - fail(error); + public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, UnregisteredDrinkException, + InvalidServingSizeException { + String command = "drink d/sprite s/500"; + testUser.handleDrink(command); + + assertEquals("sprite", testDrinkList.get(0).getName()); + assertEquals(500, testDrinkList.get(0).getDrinkVolumeSize()); } - */ @Test - public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, - UnregisteredDrinkException { - Drink newDrink = new Drink("sprite", 100, "28-03-2024"); - testDrinkList.add(newDrink); + public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { + System.setOut(new PrintStream(outputStream)); - assertEquals("sprite", testDrinkList.get(0).getName()); - assertEquals(100, testDrinkList.get(0).getDrinkVolumeSize()); + testMealList.add(new Meal("pizza", 4, "28-03-2024")); + testMealList.add(new Meal("chicken rice", 10, "28-03-2024")); + testDrinkList.add(new Drink("sprite", 100, "28-03-2024")); + + testUser.handleViewCalories(); + + String expectedOutput = "Total Calories: 6440"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); } + + +// @Test +// public void handleDrink_unknownServingSize_addDrinkFailed() throws IncompleteDrinkException, UnregisteredDrinkException, +// InvalidServingSizeException { +// +// Exception exception = assertThrows(IncompleteDrinkException.class, () -> { +// String command = "drink d/sprite"; +// testUser.handleDrink(command); +// }); +// +// String error = "Incomplete command, the format must be [drink d/DRINK s/SERVING_SIZE]."; +// String actualMessage = exception.getMessage(); +// +// assertEquals(error, actualMessage); +// } +// +// @Test +// public void handleDrink_invalidServingSize_addDrinkFailed() throws IncompleteDrinkException, UnregisteredDrinkException, +// InvalidServingSizeException { +// +// Exception exception = assertThrows(NumberFormatException.class, () -> { +// String command = "drink d/sprite s/null"; +// testUser.handleDrink(command); +// }); +// +// String expectedMessage = "An integer value is expected, try again please :)"; +// String actualMessage = exception.getMessage(); +// +// assertTrue(actualMessage.contains(expectedMessage)); +// } +// } From 38f09f64a80515bf61f5c5a96b4f6cc24909bffb Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Thu, 28 Mar 2024 16:26:34 +0800 Subject: [PATCH 071/274] Add exceptions for invalid serving sizes --- src/main/java/seedu/fitnus/Parser.java | 36 +++++++++++++++---- .../InvalidServingSizeException.java | 4 +++ src/main/java/seedu/fitnus/user/User.java | 19 ++++------ 3 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 8c33673fa4..27f6e76945 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -1,13 +1,14 @@ package seedu.fitnus; import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidCommandException; +import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.invalidIndexException; -import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.user.User; public class Parser { @@ -110,6 +111,10 @@ public void handleCommand(String command) { "to view valid " + "indexes."); } catch (UnregisteredExerciseException e) { System.out.println("Sorry that exercise is not registered in the database."); + } catch (InvalidServingSizeException e) { + System.out.println("Serving Size must be at least 0!"); + } catch (NumberFormatException e) { + System.out.println("An integer value is expected, try again please :)"); } } @@ -143,7 +148,7 @@ public static void handleHelp() { System.out.println("- Exit the app: exit "); } - public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException { + public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException, InvalidServingSizeException { if (!command.contains("m/") || !command.contains("s/")) { throw new IncompleteMealException(); } @@ -160,9 +165,13 @@ public static void parseMeal(String command) throws IncompleteMealException, Unr throw new UnregisteredMealException(); } mealSize = Integer.parseInt(command.substring(sizeIndex).trim()); + if (mealSize <= 0) { + throw new InvalidServingSizeException(); + } } - public static void parseDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException { + public static void parseDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, + InvalidServingSizeException { if (!command.contains("d/") || !command.contains("s/")) { throw new IncompleteDrinkException(); } @@ -178,7 +187,11 @@ public static void parseDrink(String command) throws IncompleteDrinkException, U if (!Drink.getNutrientDetails().containsKey(drinkDescription) && !drinkDescription.equals("water")) { throw new UnregisteredDrinkException(); } + drinkSize = Integer.parseInt(command.substring(sizeIndex).trim()); + if (drinkSize <= 0) { + throw new InvalidServingSizeException(); + } } public static String parseInfoMeal(String command) throws UnregisteredMealException { @@ -208,21 +221,30 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce return infoDrinkDescription; } - public static void parseEditMeal(String command) { + public static void parseEditMeal(String command) throws InvalidServingSizeException { int mealSizePosition = command.indexOf("/"); editMealIndex = Integer.parseInt(command.substring(9, mealSizePosition - 2).trim()) - 1; editMealSize = Integer.parseInt(command.substring(mealSizePosition + 1).trim()); + if (editMealSize <= 0) { + throw new InvalidServingSizeException(); + } } - public static void parseEditDrink(String command) { + public static void parseEditDrink(String command) throws InvalidServingSizeException { int drinkSizePosition = command.indexOf("/"); editDrinkIndex = Integer.parseInt(command.substring(10, drinkSizePosition - 2).trim()) - 1; editDrinkSize = Integer.parseInt(command.substring(drinkSizePosition + 1).trim()); + if (editDrinkSize <= 0) { + throw new InvalidServingSizeException(); + } } - public static void parseEditWater(String command) { + public static void parseEditWater(String command) throws InvalidServingSizeException { int waterSizePosition = command.indexOf("s/") + 2; editWaterSize = Integer.parseInt(command.substring(waterSizePosition).trim()); + if (editWaterSize <= 0) { + throw new InvalidServingSizeException(); + } } public static void parseMealStorage(String data) { diff --git a/src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java b/src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java new file mode 100644 index 0000000000..7a7bfed6c3 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java @@ -0,0 +1,4 @@ +package seedu.fitnus.exception; + +public class InvalidServingSizeException extends Exception { +} diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 2ddb2a29fe..b3d15b9720 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -7,13 +7,7 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteExerciseException; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.UnregisteredDrinkException; -import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.invalidIndexException; +import seedu.fitnus.exception.*; import seedu.fitnus.storage.Storage; import java.io.FileNotFoundException; @@ -98,7 +92,7 @@ public void saveDrink(Storage drinkStorage) { } } - public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException { + public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, InvalidServingSizeException { Parser.parseMeal(command); String mealName = Parser.mealDescription; int servingSize = Parser.mealSize; @@ -111,7 +105,8 @@ public void handleMeal(String command) throws IncompleteMealException, Unregiste System.out.println("Added " + servingSize + " serving of " + mealName); } - public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException { + public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, + InvalidServingSizeException { Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; @@ -252,7 +247,7 @@ public void handleListEverything() { } } - public static void handleEditMealServingSize(String command) throws invalidIndexException { + public static void handleEditMealServingSize(String command) throws invalidIndexException, InvalidServingSizeException { Parser.parseEditMeal(command); assert Parser.editMealIndex != 0: "meal index out of bounds"; if (Parser.editMealIndex >= mealList.size()) { @@ -266,7 +261,7 @@ public static void handleEditMealServingSize(String command) throws invalidIndex System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } - public static void handleEditDrinkServingSize(String command) throws invalidIndexException { + public static void handleEditDrinkServingSize(String command) throws invalidIndexException, InvalidServingSizeException { Parser.parseEditDrink(command); assert Parser.editDrinkIndex != 0: "drink index out of bounds"; @@ -281,7 +276,7 @@ public static void handleEditDrinkServingSize(String command) throws invalidInde System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } - public static void handleEditWaterIntake(String command) throws invalidIndexException { + public static void handleEditWaterIntake(String command) throws invalidIndexException, InvalidServingSizeException { Parser.parseEditWater(command); Water.editWaterIntake(Parser.editWaterSize); System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); From cfd90093f5855ae1665fb7ed29118b081027575d Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 19:13:47 +0800 Subject: [PATCH 072/274] Fix bugs to throw invalidIndexException --- src/main/java/seedu/fitnus/user/User.java | 24 ++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index b3d15b9720..9d96a19d52 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -248,14 +248,14 @@ public void handleListEverything() { } public static void handleEditMealServingSize(String command) throws invalidIndexException, InvalidServingSizeException { - Parser.parseEditMeal(command); - assert Parser.editMealIndex != 0: "meal index out of bounds"; - if (Parser.editMealIndex >= mealList.size()) { + Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 + if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { throw new invalidIndexException(); } String mealName = mealList.get(Parser.editMealIndex).getName(); String mealDate = mealList.get(Parser.editMealIndex).getDate(); + Meal updatedMeal = new Meal(mealName, Parser.editMealSize, mealDate); mealList.set(Parser.editMealIndex, updatedMeal); System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); @@ -263,9 +263,8 @@ public static void handleEditMealServingSize(String command) throws invalidIndex public static void handleEditDrinkServingSize(String command) throws invalidIndexException, InvalidServingSizeException { Parser.parseEditDrink(command); - assert Parser.editDrinkIndex != 0: "drink index out of bounds"; - if (Parser.editDrinkIndex >= drinkList.size()) { + if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { throw new invalidIndexException(); } String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); @@ -282,17 +281,24 @@ public static void handleEditWaterIntake(String command) throws invalidIndexExce System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } - public void handleDeleteMeal(String command) { + public void handleDeleteMeal(String command) throws invalidIndexException { int mealIndex = Integer.parseInt(command.substring(11)) - 1; - assert mealIndex >= 0: "meal index out of bounds"; + + if (mealIndex >= mealList.size() || mealIndex < 0) { + throw new invalidIndexException(); + } + String mealName = mealList.get(mealIndex).getName(); mealList.remove(mealIndex); System.out.println("Removed " + mealName + " from meals"); } - public void handleDeleteDrink(String command) { + public void handleDeleteDrink(String command) throws invalidIndexException { int drinkIndex = Integer.parseInt(command.substring(12)) - 1; - assert drinkIndex >= 0: "drink index out of bounds"; + if (drinkIndex >= drinkList.size() || drinkIndex < 0) { + throw new invalidIndexException(); + } + String drinkName = drinkList.get(drinkIndex).getName(); drinkList.remove(drinkIndex); System.out.println("Removed " + drinkName + " from drinks"); From e0145e545010792fa7ed9f9bbd639b920ab1bccd Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 19:14:25 +0800 Subject: [PATCH 073/274] Add JUnit test, UserTest now 76% --- src/main/java/seedu/fitnus/Parser.java | 2 +- src/test/java/seedu/fitnus/user/UserTest.java | 224 +++++++++++++++++- 2 files changed, 214 insertions(+), 12 deletions(-) diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 27f6e76945..6bffe115c9 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -108,7 +108,7 @@ public void handleCommand(String command) { System.out.println("Sorry that meal is not registered in the database."); } catch (invalidIndexException e) { System.out.println("Sorry the index you provided is invalid, check [listMeals or listDrinks] " + - "to view valid " + "indexes."); + "to view valid indexes."); } catch (UnregisteredExerciseException e) { System.out.println("Sorry that exercise is not registered in the database."); } catch (InvalidServingSizeException e) { diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 4cb17bd034..833a48cadf 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -4,12 +4,14 @@ import seedu.fitnus.Exercise; import seedu.fitnus.Meal; +import seedu.fitnus.Water; + import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; - +import seedu.fitnus.exception.invalidIndexException; import seedu.fitnus.storage.Storage; import java.io.ByteArrayOutputStream; @@ -19,7 +21,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; //import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class UserTest { User testUser; @@ -41,6 +46,10 @@ public void setUp() { testMealList = testUser.mealList; testDrinkList = testUser.drinkList; + testMealList.add(new Meal("pizza", 4, "28-03-2024")); + testMealList.add(new Meal("chicken rice", 10, "28-03-2024")); + testDrinkList.add(new Drink("sprite", 100, "28-03-2024")); + System.setOut(new PrintStream(outputStream)); } @@ -51,8 +60,8 @@ public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealExcep assertFalse(testMealList.isEmpty()); - assertEquals("pizza", testMealList.get(0).getName()); - assertEquals(3, testMealList.get(0).getServingSize()); + assertEquals("pizza", testMealList.get(2).getName()); + assertEquals(3, testMealList.get(2).getServingSize()); } @Test @@ -61,26 +70,219 @@ public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkEx String command = "drink d/sprite s/500"; testUser.handleDrink(command); - assertEquals("sprite", testDrinkList.get(0).getName()); - assertEquals(500, testDrinkList.get(0).getDrinkVolumeSize()); + assertEquals("sprite", testDrinkList.get(1).getName()); + assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); } @Test public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { + testUser.handleViewCalories(); + String expectedOutput = "Total Calories: 6440"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { + testUser.handleViewCarbohydrates(); + String expectedOutput = "Total Carbohydrates: 830"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { System.setOut(new PrintStream(outputStream)); - testMealList.add(new Meal("pizza", 4, "28-03-2024")); - testMealList.add(new Meal("chicken rice", 10, "28-03-2024")); - testDrinkList.add(new Drink("sprite", 100, "28-03-2024")); + testUser.handleViewProteins(); + String expectedOutput = "Total Proteins: 400"; + String actualOutput = outputStream.toString().trim(); - testUser.handleViewCalories(); + assertTrue(actualOutput.contains(expectedOutput)); + } - String expectedOutput = "Total Calories: 6440"; + @Test + public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { + Water.getInstance(500, "28-04-2024"); + + testUser.handleViewWaterIntake(); + String expectedOutput = "Total water intake: 500"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFiber(); + String expectedOutput = "Total Fiber: 220"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewFat_correctFatCalculation_viewFatAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFat(); + String expectedOutput = "Total Fat: 302"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewSugar(); + String expectedOutput = "Total Sugar: 88"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleListMeals_emptyList_printListAccurate() { + testMealList.clear(); + testUser.handleListMeals(); + + String expectedOutput = "here's what you have eaten today\r\n" + + " >> nothing so far :o"; String actualOutput = outputStream.toString().trim(); assertTrue(actualOutput.contains(expectedOutput)); } + @Test + public void handleListMeals_validList_printListAccurate() { + testUser.handleListMeals(); + + String expectedOutput = "here's what you have eaten today\r\n" + + "1. pizza (serving size: 4)\r\n" + + "2. chicken rice (serving size: 10)"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleListDrinks_emptyList_printListAccurate() { + testDrinkList.clear(); + testUser.handleListDrinks(); + + String expectedOutput = "here's what you have drank today\r\n" + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + + @Test + public void handleListDrinks_validList_printListAccurate() { + testUser.handleListDrinks(); + + String expectedOutput = "here's what you have drank today\r\n" + + "1. sprite (volume: 100ml)\r\n\r\n" + + "Total water intake: 0 ml"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleListEverything_bothEmptyLists_printListAccurate() { + testMealList.clear(); + testDrinkList.clear(); + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today\r\n" + + " >> nothing so far :o\r\n\r\n" + + "Total water intake: 0 ml"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleListEverything_validList_printListAccurate() { + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today\r\n" + + "1. pizza (serving size: 4)\r\n" + + "2. chicken rice (serving size: 10)\r\n" + + "3. sprite (volume: 100ml)\r\n\r\n" + + "Total water intake: 0 ml"; + String actualOutput = outputStream.toString().trim(); + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws invalidIndexException, + InvalidServingSizeException { + Exception exception = assertThrows(invalidIndexException.class, () -> { + String command = "editMeal 5 s/10"; + testUser.handleEditMealServingSize(command); + }); + } + + @Test + public void handleEditMealServingSize_validCommand_editMealSuccessful() throws invalidIndexException, + InvalidServingSizeException { + String command = "editMeal 2 s/100000000"; + testUser.handleEditMealServingSize(command); + + int mealIndex = 2 - 1; + assertEquals("chicken rice", testMealList.get(mealIndex).getName()); + assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); + } + + @Test + public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws invalidIndexException, + InvalidServingSizeException { + String command = "editDrink 1 s/100000000"; + testUser.handleEditDrinkServingSize(command); + + int drinkIndex = 1 - 1; + assertEquals("sprite", testDrinkList.get(drinkIndex).getName()); + assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); + } + + @Test + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws invalidIndexException { + String command = "deleteMeal 1"; + testUser.handleDeleteMeal(command); + assertEquals(1, testMealList.size()); + assertEquals("chicken rice", testMealList.get(0).getName()); + } + + @Test + public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws invalidIndexException { + Exception exception = assertThrows(invalidIndexException.class, () -> { + String command = "deleteDrink 5"; + testUser.handleDeleteDrink(command); + }); + } + + @Test + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws invalidIndexException { + String command = "deleteDrink 1"; + testUser.handleDeleteDrink(command); + assertEquals(0, testDrinkList.size()); + } + + @Test + public void handleClear_validCommand_clearListsSuccessful() { + testUser.handleClear(); + assertEquals(0, testMealList.size()); + assertEquals(0, testDrinkList.size()); + } // @Test // public void handleDrink_unknownServingSize_addDrinkFailed() throws IncompleteDrinkException, UnregisteredDrinkException, From e0723659f49d43e9fa5c8d69a5065aca7f89fefe Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 19:20:53 +0800 Subject: [PATCH 074/274] Fix Checkstyle errors --- src/test/java/seedu/fitnus/user/UserTest.java | 34 ++----------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 833a48cadf..43fe1508ce 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -54,7 +54,8 @@ public void setUp() { } @Test - public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, InvalidServingSizeException { + public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, + InvalidServingSizeException { String command = "ate m/pizza s/3"; testUser.handleMeal(command); @@ -283,35 +284,4 @@ public void handleClear_validCommand_clearListsSuccessful() { assertEquals(0, testMealList.size()); assertEquals(0, testDrinkList.size()); } - -// @Test -// public void handleDrink_unknownServingSize_addDrinkFailed() throws IncompleteDrinkException, UnregisteredDrinkException, -// InvalidServingSizeException { -// -// Exception exception = assertThrows(IncompleteDrinkException.class, () -> { -// String command = "drink d/sprite"; -// testUser.handleDrink(command); -// }); -// -// String error = "Incomplete command, the format must be [drink d/DRINK s/SERVING_SIZE]."; -// String actualMessage = exception.getMessage(); -// -// assertEquals(error, actualMessage); -// } -// -// @Test -// public void handleDrink_invalidServingSize_addDrinkFailed() throws IncompleteDrinkException, UnregisteredDrinkException, -// InvalidServingSizeException { -// -// Exception exception = assertThrows(NumberFormatException.class, () -> { -// String command = "drink d/sprite s/null"; -// testUser.handleDrink(command); -// }); -// -// String expectedMessage = "An integer value is expected, try again please :)"; -// String actualMessage = exception.getMessage(); -// -// assertTrue(actualMessage.contains(expectedMessage)); -// } -// } From 76461927dee217812e1bcd778e9db9ec68ee4e67 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 19:38:02 +0800 Subject: [PATCH 075/274] Fix Checkstyle Error in User class --- src/main/java/seedu/fitnus/user/User.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 9d96a19d52..c792af6d8c 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -7,9 +7,17 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; -import seedu.fitnus.exception.*; import seedu.fitnus.storage.Storage; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidServingSizeException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.invalidIndexException; + import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; @@ -92,7 +100,8 @@ public void saveDrink(Storage drinkStorage) { } } - public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, InvalidServingSizeException { + public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, + InvalidServingSizeException { Parser.parseMeal(command); String mealName = Parser.mealDescription; int servingSize = Parser.mealSize; @@ -247,7 +256,8 @@ public void handleListEverything() { } } - public static void handleEditMealServingSize(String command) throws invalidIndexException, InvalidServingSizeException { + public static void handleEditMealServingSize(String command) throws invalidIndexException, + InvalidServingSizeException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { throw new invalidIndexException(); @@ -261,7 +271,8 @@ public static void handleEditMealServingSize(String command) throws invalidIndex System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } - public static void handleEditDrinkServingSize(String command) throws invalidIndexException, InvalidServingSizeException { + public static void handleEditDrinkServingSize(String command) throws invalidIndexException, + InvalidServingSizeException { Parser.parseEditDrink(command); if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { From dccf6a59fb475e361882e75702f5de96548705fa Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 19:50:43 +0800 Subject: [PATCH 076/274] Fix errors in checkstyleMain --- src/main/java/seedu/fitnus/Date.java | 4 ++-- src/main/java/seedu/fitnus/Parser.java | 7 ++++--- .../exception/invalidIndexException.java | 2 +- src/main/java/seedu/fitnus/user/User.java | 20 +++++++++---------- src/test/java/seedu/fitnus/user/UserTest.java | 18 ++++++++--------- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/main/java/seedu/fitnus/Date.java b/src/main/java/seedu/fitnus/Date.java index 1deeb2ec0b..2ae5d3a51f 100644 --- a/src/main/java/seedu/fitnus/Date.java +++ b/src/main/java/seedu/fitnus/Date.java @@ -10,8 +10,8 @@ public Date() { long millis = System.currentTimeMillis(); java.sql.Date date = new java.sql.Date(millis); - SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy"); - String formattedDate = DATE_FORMAT.format(date); + SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); + String formattedDate = dateFormat.format(date); this.currentDate = formattedDate; } diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index 6bffe115c9..adef9baea9 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -8,7 +8,7 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.invalidIndexException; +import seedu.fitnus.exception.InvalidIndexException; import seedu.fitnus.user.User; public class Parser { @@ -106,7 +106,7 @@ public void handleCommand(String command) { System.out.println("Sorry that drink is not registered in the database."); } catch (UnregisteredMealException e) { System.out.println("Sorry that meal is not registered in the database."); - } catch (invalidIndexException e) { + } catch (InvalidIndexException e) { System.out.println("Sorry the index you provided is invalid, check [listMeals or listDrinks] " + "to view valid indexes."); } catch (UnregisteredExerciseException e) { @@ -148,7 +148,8 @@ public static void handleHelp() { System.out.println("- Exit the app: exit "); } - public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException, InvalidServingSizeException { + public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException, + InvalidServingSizeException { if (!command.contains("m/") || !command.contains("s/")) { throw new IncompleteMealException(); } diff --git a/src/main/java/seedu/fitnus/exception/invalidIndexException.java b/src/main/java/seedu/fitnus/exception/invalidIndexException.java index e71e8dd434..6b52efe227 100644 --- a/src/main/java/seedu/fitnus/exception/invalidIndexException.java +++ b/src/main/java/seedu/fitnus/exception/invalidIndexException.java @@ -1,4 +1,4 @@ package seedu.fitnus.exception; -public class invalidIndexException extends Exception { +public class InvalidIndexException extends Exception { } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index c792af6d8c..7c3114cd06 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -16,7 +16,7 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.invalidIndexException; +import seedu.fitnus.exception.InvalidIndexException; import java.io.FileNotFoundException; import java.io.IOException; @@ -256,11 +256,11 @@ public void handleListEverything() { } } - public static void handleEditMealServingSize(String command) throws invalidIndexException, + public static void handleEditMealServingSize(String command) throws InvalidIndexException, InvalidServingSizeException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { - throw new invalidIndexException(); + throw new InvalidIndexException(); } String mealName = mealList.get(Parser.editMealIndex).getName(); @@ -271,12 +271,12 @@ public static void handleEditMealServingSize(String command) throws invalidIndex System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } - public static void handleEditDrinkServingSize(String command) throws invalidIndexException, + public static void handleEditDrinkServingSize(String command) throws InvalidIndexException, InvalidServingSizeException { Parser.parseEditDrink(command); if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { - throw new invalidIndexException(); + throw new InvalidIndexException(); } String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); String drinkDate = drinkList.get(Parser.editDrinkIndex).getDate(); @@ -286,17 +286,17 @@ public static void handleEditDrinkServingSize(String command) throws invalidInde System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } - public static void handleEditWaterIntake(String command) throws invalidIndexException, InvalidServingSizeException { + public static void handleEditWaterIntake(String command) throws InvalidIndexException, InvalidServingSizeException { Parser.parseEditWater(command); Water.editWaterIntake(Parser.editWaterSize); System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } - public void handleDeleteMeal(String command) throws invalidIndexException { + public void handleDeleteMeal(String command) throws InvalidIndexException { int mealIndex = Integer.parseInt(command.substring(11)) - 1; if (mealIndex >= mealList.size() || mealIndex < 0) { - throw new invalidIndexException(); + throw new InvalidIndexException(); } String mealName = mealList.get(mealIndex).getName(); @@ -304,10 +304,10 @@ public void handleDeleteMeal(String command) throws invalidIndexException { System.out.println("Removed " + mealName + " from meals"); } - public void handleDeleteDrink(String command) throws invalidIndexException { + public void handleDeleteDrink(String command) throws InvalidIndexException { int drinkIndex = Integer.parseInt(command.substring(12)) - 1; if (drinkIndex >= drinkList.size() || drinkIndex < 0) { - throw new invalidIndexException(); + throw new InvalidIndexException(); } String drinkName = drinkList.get(drinkIndex).getName(); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 43fe1508ce..5702e4a1ac 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -11,7 +11,7 @@ import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.invalidIndexException; +import seedu.fitnus.exception.InvalidIndexException; import seedu.fitnus.storage.Storage; import java.io.ByteArrayOutputStream; @@ -225,16 +225,16 @@ public void handleListEverything_validList_printListAccurate() { } @Test - public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws invalidIndexException, + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidIndexException, InvalidServingSizeException { - Exception exception = assertThrows(invalidIndexException.class, () -> { + Exception exception = assertThrows(InvalidIndexException.class, () -> { String command = "editMeal 5 s/10"; testUser.handleEditMealServingSize(command); }); } @Test - public void handleEditMealServingSize_validCommand_editMealSuccessful() throws invalidIndexException, + public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidIndexException, InvalidServingSizeException { String command = "editMeal 2 s/100000000"; testUser.handleEditMealServingSize(command); @@ -245,7 +245,7 @@ public void handleEditMealServingSize_validCommand_editMealSuccessful() throws i } @Test - public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws invalidIndexException, + public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidIndexException, InvalidServingSizeException { String command = "editDrink 1 s/100000000"; testUser.handleEditDrinkServingSize(command); @@ -256,7 +256,7 @@ public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws } @Test - public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws invalidIndexException { + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidIndexException { String command = "deleteMeal 1"; testUser.handleDeleteMeal(command); assertEquals(1, testMealList.size()); @@ -264,15 +264,15 @@ public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws invalidI } @Test - public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws invalidIndexException { - Exception exception = assertThrows(invalidIndexException.class, () -> { + public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidIndexException { + Exception exception = assertThrows(InvalidIndexException.class, () -> { String command = "deleteDrink 5"; testUser.handleDeleteDrink(command); }); } @Test - public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws invalidIndexException { + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidIndexException { String command = "deleteDrink 1"; testUser.handleDeleteDrink(command); assertEquals(0, testDrinkList.size()); From 622227528fe186902feb764a34ceb0ae392ab333 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 19:55:35 +0800 Subject: [PATCH 077/274] Change assertTrue to assertEquals --- src/test/java/seedu/fitnus/user/UserTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 5702e4a1ac..a7ba9ea090 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -153,11 +153,11 @@ public void handleListMeals_emptyList_printListAccurate() { testMealList.clear(); testUser.handleListMeals(); - String expectedOutput = "here's what you have eaten today\r\n" + + String expectedOutput = "here's what you have eaten today\n" + " >> nothing so far :o"; String actualOutput = outputStream.toString().trim(); - assertTrue(actualOutput.contains(expectedOutput)); + assertEquals(expectedOutput, actualOutput); } @Test @@ -169,7 +169,7 @@ public void handleListMeals_validList_printListAccurate() { "2. chicken rice (serving size: 10)"; String actualOutput = outputStream.toString().trim(); - assertTrue(actualOutput.contains(expectedOutput)); + assertEquals(expectedOutput, actualOutput); } @Test @@ -181,7 +181,7 @@ public void handleListDrinks_emptyList_printListAccurate() { " >> nothing so far :o"; String actualOutput = outputStream.toString().trim(); - assertTrue(actualOutput.contains(expectedOutput)); + assertEquals(expectedOutput, actualOutput); } @@ -194,7 +194,7 @@ public void handleListDrinks_validList_printListAccurate() { "Total water intake: 0 ml"; String actualOutput = outputStream.toString().trim(); - assertTrue(actualOutput.contains(expectedOutput)); + assertEquals(expectedOutput, actualOutput); } @Test @@ -208,7 +208,7 @@ public void handleListEverything_bothEmptyLists_printListAccurate() { "Total water intake: 0 ml"; String actualOutput = outputStream.toString().trim(); - assertTrue(actualOutput.contains(expectedOutput)); + assertEquals(expectedOutput, actualOutput); } @Test @@ -221,7 +221,7 @@ public void handleListEverything_validList_printListAccurate() { "3. sprite (volume: 100ml)\r\n\r\n" + "Total water intake: 0 ml"; String actualOutput = outputStream.toString().trim(); - assertTrue(actualOutput.contains(expectedOutput)); + assertEquals(expectedOutput, actualOutput); } @Test From 6a833677acc68def987880bbcbaedc2c2723ab09 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 20:06:57 +0800 Subject: [PATCH 078/274] Rename InvalidIndexException class --- src/main/java/seedu/fitnus/Parser.java | 4 ++-- .../exception/InvalidListIndexException.java | 5 +++++ .../exception/invalidIndexException.java | 4 ---- src/main/java/seedu/fitnus/user/User.java | 20 +++++++++---------- src/test/java/seedu/fitnus/user/UserTest.java | 18 ++++++++--------- 5 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/InvalidListIndexException.java delete mode 100644 src/main/java/seedu/fitnus/exception/invalidIndexException.java diff --git a/src/main/java/seedu/fitnus/Parser.java b/src/main/java/seedu/fitnus/Parser.java index adef9baea9..7a27e1fe94 100644 --- a/src/main/java/seedu/fitnus/Parser.java +++ b/src/main/java/seedu/fitnus/Parser.java @@ -4,11 +4,11 @@ import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidCommandException; +import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.InvalidIndexException; import seedu.fitnus.user.User; public class Parser { @@ -106,7 +106,7 @@ public void handleCommand(String command) { System.out.println("Sorry that drink is not registered in the database."); } catch (UnregisteredMealException e) { System.out.println("Sorry that meal is not registered in the database."); - } catch (InvalidIndexException e) { + } catch (InvalidListIndexException e) { System.out.println("Sorry the index you provided is invalid, check [listMeals or listDrinks] " + "to view valid indexes."); } catch (UnregisteredExerciseException e) { diff --git a/src/main/java/seedu/fitnus/exception/InvalidListIndexException.java b/src/main/java/seedu/fitnus/exception/InvalidListIndexException.java new file mode 100644 index 0000000000..a52ed8c25c --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/InvalidListIndexException.java @@ -0,0 +1,5 @@ +package seedu.fitnus.exception; + +public class InvalidListIndexException extends Exception { + +} diff --git a/src/main/java/seedu/fitnus/exception/invalidIndexException.java b/src/main/java/seedu/fitnus/exception/invalidIndexException.java deleted file mode 100644 index 6b52efe227..0000000000 --- a/src/main/java/seedu/fitnus/exception/invalidIndexException.java +++ /dev/null @@ -1,4 +0,0 @@ -package seedu.fitnus.exception; - -public class InvalidIndexException extends Exception { -} diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 7c3114cd06..5f3b043dfe 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -16,7 +16,7 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.InvalidIndexException; +import seedu.fitnus.exception.InvalidListIndexException; import java.io.FileNotFoundException; import java.io.IOException; @@ -256,11 +256,11 @@ public void handleListEverything() { } } - public static void handleEditMealServingSize(String command) throws InvalidIndexException, + public static void handleEditMealServingSize(String command) throws InvalidListIndexException, InvalidServingSizeException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { - throw new InvalidIndexException(); + throw new InvalidListIndexException(); } String mealName = mealList.get(Parser.editMealIndex).getName(); @@ -271,12 +271,12 @@ public static void handleEditMealServingSize(String command) throws InvalidIndex System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } - public static void handleEditDrinkServingSize(String command) throws InvalidIndexException, + public static void handleEditDrinkServingSize(String command) throws InvalidListIndexException, InvalidServingSizeException { Parser.parseEditDrink(command); if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { - throw new InvalidIndexException(); + throw new InvalidListIndexException(); } String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); String drinkDate = drinkList.get(Parser.editDrinkIndex).getDate(); @@ -286,17 +286,17 @@ public static void handleEditDrinkServingSize(String command) throws InvalidInde System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } - public static void handleEditWaterIntake(String command) throws InvalidIndexException, InvalidServingSizeException { + public static void handleEditWaterIntake(String command) throws InvalidListIndexException, InvalidServingSizeException { Parser.parseEditWater(command); Water.editWaterIntake(Parser.editWaterSize); System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } - public void handleDeleteMeal(String command) throws InvalidIndexException { + public void handleDeleteMeal(String command) throws InvalidListIndexException { int mealIndex = Integer.parseInt(command.substring(11)) - 1; if (mealIndex >= mealList.size() || mealIndex < 0) { - throw new InvalidIndexException(); + throw new InvalidListIndexException(); } String mealName = mealList.get(mealIndex).getName(); @@ -304,10 +304,10 @@ public void handleDeleteMeal(String command) throws InvalidIndexException { System.out.println("Removed " + mealName + " from meals"); } - public void handleDeleteDrink(String command) throws InvalidIndexException { + public void handleDeleteDrink(String command) throws InvalidListIndexException { int drinkIndex = Integer.parseInt(command.substring(12)) - 1; if (drinkIndex >= drinkList.size() || drinkIndex < 0) { - throw new InvalidIndexException(); + throw new InvalidListIndexException(); } String drinkName = drinkList.get(drinkIndex).getName(); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index a7ba9ea090..e18a13c91c 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -11,7 +11,7 @@ import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.InvalidIndexException; +import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.storage.Storage; import java.io.ByteArrayOutputStream; @@ -225,16 +225,16 @@ public void handleListEverything_validList_printListAccurate() { } @Test - public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidIndexException, + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException, InvalidServingSizeException { - Exception exception = assertThrows(InvalidIndexException.class, () -> { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { String command = "editMeal 5 s/10"; testUser.handleEditMealServingSize(command); }); } @Test - public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidIndexException, + public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, InvalidServingSizeException { String command = "editMeal 2 s/100000000"; testUser.handleEditMealServingSize(command); @@ -245,7 +245,7 @@ public void handleEditMealServingSize_validCommand_editMealSuccessful() throws I } @Test - public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidIndexException, + public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, InvalidServingSizeException { String command = "editDrink 1 s/100000000"; testUser.handleEditDrinkServingSize(command); @@ -256,7 +256,7 @@ public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws } @Test - public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidIndexException { + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException { String command = "deleteMeal 1"; testUser.handleDeleteMeal(command); assertEquals(1, testMealList.size()); @@ -264,15 +264,15 @@ public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidI } @Test - public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidIndexException { - Exception exception = assertThrows(InvalidIndexException.class, () -> { + public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { String command = "deleteDrink 5"; testUser.handleDeleteDrink(command); }); } @Test - public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidIndexException { + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException { String command = "deleteDrink 1"; testUser.handleDeleteDrink(command); assertEquals(0, testDrinkList.size()); From 9668417cb5537fb25b3d05d3da6c4ef5c539ca6c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 20:16:14 +0800 Subject: [PATCH 079/274] Replace with System.lineSeparator() for tests to be OS-independent --- src/main/java/seedu/fitnus/user/User.java | 3 ++- src/test/java/seedu/fitnus/user/UserTest.java | 26 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 5f3b043dfe..1b9d78d111 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -286,7 +286,8 @@ public static void handleEditDrinkServingSize(String command) throws InvalidList System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } - public static void handleEditWaterIntake(String command) throws InvalidListIndexException, InvalidServingSizeException { + public static void handleEditWaterIntake(String command) throws InvalidListIndexException, + InvalidServingSizeException { Parser.parseEditWater(command); Water.editWaterIntake(Parser.editWaterSize); System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index e18a13c91c..93b3b0ebc8 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -153,7 +153,7 @@ public void handleListMeals_emptyList_printListAccurate() { testMealList.clear(); testUser.handleListMeals(); - String expectedOutput = "here's what you have eaten today\n" + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + " >> nothing so far :o"; String actualOutput = outputStream.toString().trim(); @@ -164,8 +164,8 @@ public void handleListMeals_emptyList_printListAccurate() { public void handleListMeals_validList_printListAccurate() { testUser.handleListMeals(); - String expectedOutput = "here's what you have eaten today\r\n" + - "1. pizza (serving size: 4)\r\n" + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + "1. pizza (serving size: 4)" + System.lineSeparator() + "2. chicken rice (serving size: 10)"; String actualOutput = outputStream.toString().trim(); @@ -177,7 +177,7 @@ public void handleListDrinks_emptyList_printListAccurate() { testDrinkList.clear(); testUser.handleListDrinks(); - String expectedOutput = "here's what you have drank today\r\n" + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + " >> nothing so far :o"; String actualOutput = outputStream.toString().trim(); @@ -189,8 +189,8 @@ public void handleListDrinks_emptyList_printListAccurate() { public void handleListDrinks_validList_printListAccurate() { testUser.handleListDrinks(); - String expectedOutput = "here's what you have drank today\r\n" + - "1. sprite (volume: 100ml)\r\n\r\n" + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + "1. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + "Total water intake: 0 ml"; String actualOutput = outputStream.toString().trim(); @@ -203,9 +203,9 @@ public void handleListEverything_bothEmptyLists_printListAccurate() { testDrinkList.clear(); testUser.handleListEverything(); - String expectedOutput = "here's what you have consumed today\r\n" + - " >> nothing so far :o\r\n\r\n" + - "Total water intake: 0 ml"; + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + + "Total water intake: 0 ml"; String actualOutput = outputStream.toString().trim(); assertEquals(expectedOutput, actualOutput); @@ -215,10 +215,10 @@ public void handleListEverything_bothEmptyLists_printListAccurate() { public void handleListEverything_validList_printListAccurate() { testUser.handleListEverything(); - String expectedOutput = "here's what you have consumed today\r\n" + - "1. pizza (serving size: 4)\r\n" + - "2. chicken rice (serving size: 10)\r\n" + - "3. sprite (volume: 100ml)\r\n\r\n" + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + "1. pizza (serving size: 4)" + System.lineSeparator() + + "2. chicken rice (serving size: 10)" + System.lineSeparator() + + "3. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + "Total water intake: 0 ml"; String actualOutput = outputStream.toString().trim(); assertEquals(expectedOutput, actualOutput); From c9b51e7a6a3423a1dd39ca489d3e2ca41e6405ce Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 29 Mar 2024 20:18:59 +0800 Subject: [PATCH 080/274] Fix Indentation Error --- src/test/java/seedu/fitnus/user/UserTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 93b3b0ebc8..f0311b4712 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -205,7 +205,7 @@ public void handleListEverything_bothEmptyLists_printListAccurate() { String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 0 ml"; + "Total water intake: 0 ml"; String actualOutput = outputStream.toString().trim(); assertEquals(expectedOutput, actualOutput); From 8044054e867331e2576cf0a307688ce77c8d4a12 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sat, 30 Mar 2024 13:13:38 +0800 Subject: [PATCH 081/274] Fix checkstyle --- data/DrinkList.txt | 2 +- src/test/java/seedu/fitnus/parser/ParserTest.java | 11 +++++++---- src/test/resources/DrinkList.txt | 0 src/test/resources/MealList.txt | 0 4 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/DrinkList.txt create mode 100644 src/test/resources/MealList.txt diff --git a/data/DrinkList.txt b/data/DrinkList.txt index 8822aa6e81..b5166a8d17 100644 --- a/data/DrinkList.txt +++ b/data/DrinkList.txt @@ -1 +1 @@ -water,400 +water,400,null diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 2a62415671..c79c7d5907 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -1,10 +1,11 @@ package seedu.fitnus.parser; import org.junit.jupiter.api.Test; -import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.InvalidServingSizeException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.UnregisteredDrinkException; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -12,7 +13,8 @@ public class ParserTest { @Test - public void parseMeal_validInputs_success() throws IncompleteMealException, UnregisteredMealException { + public void parseMeal_validInputs_success() throws IncompleteMealException, UnregisteredMealException, + InvalidServingSizeException { String command = "ate m/chicken rice s/1"; Parser.parseMeal(command); assertEquals("chicken rice", Parser.mealDescription); @@ -20,7 +22,8 @@ public void parseMeal_validInputs_success() throws IncompleteMealException, Unre } @Test - public void parseDrink_validInputs_success() throws IncompleteDrinkException, UnregisteredDrinkException { + public void parseDrink_validInputs_success() throws IncompleteDrinkException, UnregisteredDrinkException, + InvalidServingSizeException { String command = "drink d/sprite s/300"; Parser.parseDrink(command); assertEquals("sprite", Parser.drinkDescription); diff --git a/src/test/resources/DrinkList.txt b/src/test/resources/DrinkList.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/test/resources/MealList.txt b/src/test/resources/MealList.txt new file mode 100644 index 0000000000..e69de29bb2 From f7c2944068f9bef571e9fc52b50b1f28ddcf7ceb Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 14:42:18 +0800 Subject: [PATCH 082/274] Fix bug in exception message for Exercise --- .../java/seedu/fitnus/exception/IncompleteDeleteException.java | 2 ++ src/main/java/seedu/fitnus/parser/Parser.java | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java diff --git a/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java b/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java new file mode 100644 index 0000000000..ff99d1b430 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java @@ -0,0 +1,2 @@ +package seedu.fitnus.exception;public class IncompleteDeleteException { +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 38ffe9c277..0432c9ef88 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -105,7 +105,8 @@ public void handleCommand(String command) { } catch (IncompleteMealException e) { System.out.println("Incomplete command, the format must be [ate m/MEAL s/SERVING_SIZE]."); } catch (IncompleteExerciseException e) { - System.out.println("Incomplete command, the format must be [exercise e/MEAL d/SERVING_SIZE]."); + System.out.println("Incomplete command, the format must be [exercise e/EXERCISE d/DURATION(MINUTES)." + + "i/INTENSITY(HIGH, MEDIUM, LOW)"); } catch (UnregisteredDrinkException e) { System.out.println("Sorry that drink is not registered in the database."); } catch (UnregisteredMealException e) { From ea78efc42f1dcf0e067000337d14e4874f296c23 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 15:01:28 +0800 Subject: [PATCH 083/274] Add IncompleteDeleteException for no index inputs --- .../exception/IncompleteDeleteException.java | 4 +++- src/main/java/seedu/fitnus/parser/Parser.java | 4 ++++ src/main/java/seedu/fitnus/user/User.java | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java b/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java index ff99d1b430..61d2aff02b 100644 --- a/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java @@ -1,2 +1,4 @@ -package seedu.fitnus.exception;public class IncompleteDeleteException { +package seedu.fitnus.exception; + +public class IncompleteDeleteException extends Exception { } diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 0432c9ef88..784774b6e2 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -4,6 +4,7 @@ import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; +import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteMealException; @@ -120,6 +121,9 @@ public void handleCommand(String command) { System.out.println("Serving Size must be at least 0!"); } catch (NumberFormatException e) { System.out.println("An integer value is expected, try again please :)"); + } catch (IncompleteDeleteException e) { + System.out.println("Please specify an index that you would like to delete. The format should be " + + "[deleteMeal/deleteDrink INDEX]"); } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 6dd2eca223..fa4758cb2c 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -5,6 +5,7 @@ import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; +import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; import seedu.fitnus.storage.Storage; @@ -210,8 +211,8 @@ public void printMealList(int startIndex) { public void printExerciseList() { for (int i = 0; i < exerciseList.size(); i++) { Exercise currentExercise = exerciseList.get(i); - System.out.println((i+1) + ". " + currentExercise.getName() + "duration:" + currentExercise.getDuration() + - " (intensity: " + currentExercise.getIntensity() + ")"); + System.out.println((i+1) + ". " + currentExercise.getName() + " | duration: " + currentExercise.getDuration() + + " | intensity: " + currentExercise.getIntensity()); } } public void handleListMeals() { @@ -293,7 +294,10 @@ public static void handleEditWaterIntake(String command) throws InvalidListIndex System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } - public void handleDeleteMeal(String command) throws InvalidListIndexException { + public void handleDeleteMeal(String command) throws InvalidListIndexException, IncompleteDeleteException { + if (command.length() < 12) { + throw new IncompleteDeleteException(); + } int mealIndex = Integer.parseInt(command.substring(11)) - 1; if (mealIndex >= mealList.size() || mealIndex < 0) { @@ -305,7 +309,11 @@ public void handleDeleteMeal(String command) throws InvalidListIndexException { System.out.println("Removed " + mealName + " from meals"); } - public void handleDeleteDrink(String command) throws InvalidListIndexException { + public void handleDeleteDrink(String command) throws InvalidListIndexException, IncompleteDeleteException { + if (command.length() < 13) { + throw new IncompleteDeleteException(); + } + int drinkIndex = Integer.parseInt(command.substring(12)) - 1; if (drinkIndex >= drinkList.size() || drinkIndex < 0) { throw new InvalidListIndexException(); From 05a7f81010f9454e38fa12b4b876e75b87f16b86 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 15:01:51 +0800 Subject: [PATCH 084/274] Add tests for IncompleteDeleteException --- src/test/java/seedu/fitnus/user/UserTest.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index f0311b4712..547a0c702a 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -6,6 +6,7 @@ import seedu.fitnus.Water; +import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidServingSizeException; @@ -256,7 +257,25 @@ public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws } @Test - public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException { + public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(IncompleteDeleteException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(NumberFormatException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, IncompleteDeleteException { String command = "deleteMeal 1"; testUser.handleDeleteMeal(command); assertEquals(1, testMealList.size()); @@ -272,7 +291,7 @@ public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws Invalid } @Test - public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException { + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, IncompleteDeleteException { String command = "deleteDrink 1"; testUser.handleDeleteDrink(command); assertEquals(0, testDrinkList.size()); From 30f9bcf50483c98a0df52f4f6569fe64210782ea Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 15:51:42 +0800 Subject: [PATCH 085/274] Add IncompleteInfoException for viewing info of non-specified meal/drink/exercise --- src/main/java/seedu/fitnus/Drink.java | 3 +- src/main/java/seedu/fitnus/Exercise.java | 5 ++-- src/main/java/seedu/fitnus/Meal.java | 3 +- .../exception/IncompleteInfoException.java | 5 ++++ src/main/java/seedu/fitnus/parser/Parser.java | 29 +++++++++++++++---- .../java/seedu/fitnus/parser/ParserTest.java | 3 +- 6 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/IncompleteInfoException.java diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 422714ef2d..2a89e268cc 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.parser.Parser; @@ -39,7 +40,7 @@ private void setNutrientValues(String name) { protein = nutrients[3] * drinkVolume / 100; fat = nutrients[4] * drinkVolume / 100; } - public static void handleInfoDrink(String command) throws UnregisteredDrinkException { + public static void handleInfoDrink(String command) throws UnregisteredDrinkException, IncompleteInfoException { String name = Parser.parseInfoDrink(command); int[] nutrients = nutrientDetails.get(name); System.out.println("Drink: " + name + " (100 ml)"); diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index 39f97cfa48..8002348afe 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.parser.Parser; @@ -77,14 +78,14 @@ public int getCaloriesBurnt() { } // Method to print exercise details - public static void handleInfoExercise(String command) throws UnregisteredExerciseException { + public static void handleInfoExercise(String command) throws UnregisteredExerciseException, IncompleteInfoException { String name = Parser.parseInfoExercise(command); int[] details = exerciseDetails.get(name); if (details == null) { throw new UnregisteredExerciseException(); } System.out.println("Exercise: " + name); - System.out.println("Calories Burnt: "); + System.out.println("~ Calories burnt for a 1 minute workout of ~"); System.out.println("HIGH intensity: " + details[0]); System.out.println("MEDIUM intensity: " + details[1]); System.out.println("LOW intensity: " + details[2]); diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 6bf7912b59..0887907335 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.parser.Parser; @@ -79,7 +80,7 @@ public int getServingSize() { } // Method to print all meal info - public static void handleInfoMeal(String command) throws UnregisteredMealException { + public static void handleInfoMeal(String command) throws UnregisteredMealException, IncompleteInfoException { String name = Parser.parseInfoMeal(command); int[] nutrients = nutrientDetails.get(name); System.out.println("Meal: " + name + " (per serving)"); diff --git a/src/main/java/seedu/fitnus/exception/IncompleteInfoException.java b/src/main/java/seedu/fitnus/exception/IncompleteInfoException.java new file mode 100644 index 0000000000..73cf489f1b --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/IncompleteInfoException.java @@ -0,0 +1,5 @@ +package seedu.fitnus.exception; + +public class IncompleteInfoException extends Exception { + +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 784774b6e2..87c92f5bd7 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -7,6 +7,7 @@ import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidCommandException; import seedu.fitnus.exception.InvalidListIndexException; @@ -109,14 +110,17 @@ public void handleCommand(String command) { System.out.println("Incomplete command, the format must be [exercise e/EXERCISE d/DURATION(MINUTES)." + "i/INTENSITY(HIGH, MEDIUM, LOW)"); } catch (UnregisteredDrinkException e) { - System.out.println("Sorry that drink is not registered in the database."); + System.out.println("Sorry that drink is not registered in the database.Please check the spelling and " + + "try again"); } catch (UnregisteredMealException e) { - System.out.println("Sorry that meal is not registered in the database."); + System.out.println("Sorry that meal is not registered in the database. Please check the spelling and " + + "try again"); } catch (InvalidListIndexException e) { System.out.println("Sorry the index you provided is invalid, check [listMeals or listDrinks] " + "to view valid indexes."); } catch (UnregisteredExerciseException e) { - System.out.println("Sorry that exercise is not registered in the database."); + System.out.println("Sorry that exercise is not registered in the database. Please check the spelling and " + + "try again"); } catch (InvalidServingSizeException e) { System.out.println("Serving Size must be at least 0!"); } catch (NumberFormatException e) { @@ -124,6 +128,9 @@ public void handleCommand(String command) { } catch (IncompleteDeleteException e) { System.out.println("Please specify an index that you would like to delete. The format should be " + "[deleteMeal/deleteDrink INDEX]"); + } catch (IncompleteInfoException e) { + System.out.println("Please specify a meal/drink/exercise that you would like to view the info of. " + + "Type [help] to view the commands format."); } } @@ -204,17 +211,24 @@ public static void parseDrink(String command) throws IncompleteDrinkException, U } } - public static String parseInfoMeal(String command) throws UnregisteredMealException { + public static String parseInfoMeal(String command) throws UnregisteredMealException, IncompleteInfoException { int mealIndex = 9; + if (command.length() < mealIndex + 1) { + throw new IncompleteInfoException(); + } String infoMealDescription = command.substring(mealIndex).trim(); + if (!Meal.getNutrientDetails().containsKey(infoMealDescription)) { throw new UnregisteredMealException(); } return infoMealDescription; } - public static String parseInfoExercise(String command) throws UnregisteredExerciseException { + public static String parseInfoExercise(String command) throws UnregisteredExerciseException, IncompleteInfoException { int exerciseIndex = 13; + if (command.length() < exerciseIndex + 1) { + throw new IncompleteInfoException(); + } String infoExerciseDescription = command.substring(exerciseIndex).trim(); if (!Exercise.getExerciseDetails().containsKey(infoExerciseDescription)) { throw new UnregisteredExerciseException(); @@ -222,8 +236,11 @@ public static String parseInfoExercise(String command) throws UnregisteredExerci return infoExerciseDescription; } - public static String parseInfoDrink(String command) throws UnregisteredDrinkException { + public static String parseInfoDrink(String command) throws UnregisteredDrinkException, IncompleteInfoException { int drinkIndex = 10; + if (command.length() < drinkIndex + 1) { + throw new IncompleteInfoException(); + } String infoDrinkDescription = command.substring(drinkIndex).trim(); if (!Drink.getNutrientDetails().containsKey(infoDrinkDescription)) { throw new UnregisteredDrinkException(); diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index c79c7d5907..20bb796336 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -1,6 +1,7 @@ package seedu.fitnus.parser; import org.junit.jupiter.api.Test; +import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.InvalidServingSizeException; @@ -31,7 +32,7 @@ public void parseDrink_validInputs_success() throws IncompleteDrinkException, Un } @Test - public void parseInfoMeal_unregisteredMeal_exceptionThrown() { + public void parseInfoMeal_unregisteredMeal_exceptionThrown() throws IncompleteInfoException { String command = "infoMeal blablabla"; try { Parser.parseInfoMeal(command); From 31fbd685525da4dce29d6f1c9786bb51d11db3e0 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 16:00:30 +0800 Subject: [PATCH 086/274] Integrate Exercise into calories, clear and listEverything commands --- src/main/java/seedu/fitnus/parser/Parser.java | 8 +++--- src/main/java/seedu/fitnus/user/User.java | 27 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 87c92f5bd7..62deeab841 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -63,6 +63,8 @@ public void handleCommand(String command) { Exercise.handleInfoExercise(command); } else if (command.equals("calories")) { user.handleViewCalories(); + } else if (command.equals("caloriesBurnt")) { + user.handleCaloriesBurnt(); } else if (command.equals("carbs")) { user.handleViewCarbohydrates(); } else if (command.equals("protein")) { @@ -79,10 +81,10 @@ public void handleCommand(String command) { user.handleListMeals(); } else if (command.equals("listDrinks")) { user.handleListDrinks(); + } else if (command.equals("listExercises")) { + user.handleListExercises(); } else if (command.equals("listEverything")) { user.handleListEverything(); - }else if (command.equals("listExercises")) { - user.handleListExercises(); } else if (command.startsWith("editMeal")) { User.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { @@ -93,8 +95,6 @@ public void handleCommand(String command) { user.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { user.handleDeleteDrink(command); - } else if (command.equals("caloriesBurnt")) { - user.handleCaloriesBurnt(); } else if (command.equals("clear")) { user.handleClear(); } else { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index fa4758cb2c..f4f6539a48 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -139,6 +139,9 @@ public void handleViewCalories() { for (Drink drink: drinkList) { caloriesCount += drink.getCalories(); } + for (Exercise exercise: exerciseList) { + caloriesCount -= exercise.getCaloriesBurnt(); + } System.out.println("Total Calories: " + caloriesCount); } @@ -243,6 +246,15 @@ public void handleListDrinks() { } } + public void handleListExercises() { + System.out.println("here's the exercises you've done today"); + if (exerciseList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printExerciseList(); + } + } + public void handleListEverything() { System.out.println("here's what you have consumed today"); if (drinkList.isEmpty() && mealList.isEmpty()) { @@ -255,6 +267,9 @@ public void handleListEverything() { System.out.println(); handleViewWaterIntake(); } + + System.out.println(" ~~~"); + handleListExercises(); } public static void handleEditMealServingSize(String command) throws InvalidListIndexException, @@ -339,8 +354,11 @@ public void handleClear() { mealList.clear(); drinkList.clear(); Water.editWaterIntake(0); + exerciseList.clear(); + assert mealList.isEmpty(): "clearing of meal list failed"; assert drinkList.isEmpty(): "clearing of drink list failed"; + assert exerciseList.isEmpty(): "clearing of exercise list failed"; System.out.println("All entries have been deleted"); } @@ -352,13 +370,4 @@ public void handleCaloriesBurnt() { } System.out.println("Total calories burnt: " + caloriesBurnt); } - - public void handleListExercises() { - System.out.println("here's the exercises you've done today"); - if (exerciseList.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - printExerciseList(); - } - } } From ef63bc1c38e79f56b070ca79c4a05ae5fd63a53f Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 16:07:15 +0800 Subject: [PATCH 087/274] Add deleteExercise method --- src/main/java/seedu/fitnus/parser/Parser.java | 10 ++++++---- src/main/java/seedu/fitnus/user/User.java | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 62deeab841..d2d364e0bc 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -95,6 +95,8 @@ public void handleCommand(String command) { user.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { user.handleDeleteDrink(command); + } else if (command.startsWith("deleteExercise")) { + user.handleDeleteExercise(command); } else if (command.equals("clear")) { user.handleClear(); } else { @@ -116,18 +118,18 @@ public void handleCommand(String command) { System.out.println("Sorry that meal is not registered in the database. Please check the spelling and " + "try again"); } catch (InvalidListIndexException e) { - System.out.println("Sorry the index you provided is invalid, check [listMeals or listDrinks] " + + System.out.println("Sorry the index you provided is invalid, check [listMeals/listDrinks/listExercises] " + "to view valid indexes."); } catch (UnregisteredExerciseException e) { - System.out.println("Sorry that exercise is not registered in the database. Please check the spelling and " + - "try again"); + System.out.println("Sorry that exercise is not registered in the database. Please check the spelling and" + + " try again"); } catch (InvalidServingSizeException e) { System.out.println("Serving Size must be at least 0!"); } catch (NumberFormatException e) { System.out.println("An integer value is expected, try again please :)"); } catch (IncompleteDeleteException e) { System.out.println("Please specify an index that you would like to delete. The format should be " + - "[deleteMeal/deleteDrink INDEX]"); + "[deleteMeal/deleteDrink/deleteExercise INDEX]"); } catch (IncompleteInfoException e) { System.out.println("Please specify a meal/drink/exercise that you would like to view the info of. " + "Type [help] to view the commands format."); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f4f6539a48..9297ddd3cb 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -313,7 +313,7 @@ public void handleDeleteMeal(String command) throws InvalidListIndexException, I if (command.length() < 12) { throw new IncompleteDeleteException(); } - int mealIndex = Integer.parseInt(command.substring(11)) - 1; + int mealIndex = Integer.parseInt(command.substring(11).trim()) - 1; if (mealIndex >= mealList.size() || mealIndex < 0) { throw new InvalidListIndexException(); @@ -329,7 +329,7 @@ public void handleDeleteDrink(String command) throws InvalidListIndexException, throw new IncompleteDeleteException(); } - int drinkIndex = Integer.parseInt(command.substring(12)) - 1; + int drinkIndex = Integer.parseInt(command.substring(12).trim()) - 1; if (drinkIndex >= drinkList.size() || drinkIndex < 0) { throw new InvalidListIndexException(); } @@ -339,6 +339,21 @@ public void handleDeleteDrink(String command) throws InvalidListIndexException, System.out.println("Removed " + drinkName + " from drinks"); } + public void handleDeleteExercise(String command) throws InvalidListIndexException, IncompleteDeleteException { + if (command.length() < 16) { + throw new IncompleteDeleteException(); + } + + int exerciseIndex = Integer.parseInt(command.substring(15).trim()) - 1; + if (exerciseIndex >= exerciseList.size() || exerciseIndex < 0) { + throw new InvalidListIndexException(); + } + + String exerciseName = exerciseList.get(exerciseIndex).getName(); + exerciseList.remove(exerciseIndex); + System.out.println("Removed " + exerciseName + " from exercises done"); + } + public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException { Parser.parseExercise(command); String exerciseType = Parser.exerciseDescription; From ba1f40c8c50794e346080599c0a3745f26dcd94c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 16:13:27 +0800 Subject: [PATCH 088/274] Add InvalidExerciseDurationException --- .../exception/InvalidExerciseDurationException.java | 4 ++++ src/main/java/seedu/fitnus/parser/Parser.java | 9 ++++++++- src/main/java/seedu/fitnus/user/User.java | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java diff --git a/src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java b/src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java new file mode 100644 index 0000000000..b0071b844a --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java @@ -0,0 +1,4 @@ +package seedu.fitnus.exception; + +public class InvalidExerciseDurationException extends Exception { +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index d2d364e0bc..7e90dc6f96 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -10,6 +10,7 @@ import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidCommandException; +import seedu.fitnus.exception.InvalidExerciseDurationException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; @@ -125,6 +126,8 @@ public void handleCommand(String command) { " try again"); } catch (InvalidServingSizeException e) { System.out.println("Serving Size must be at least 0!"); + } catch (InvalidExerciseDurationException e) { + System.out.println("Exercise Duration must be at least 0!"); } catch (NumberFormatException e) { System.out.println("An integer value is expected, try again please :)"); } catch (IncompleteDeleteException e) { @@ -134,6 +137,7 @@ public void handleCommand(String command) { System.out.println("Please specify a meal/drink/exercise that you would like to view the info of. " + "Type [help] to view the commands format."); } + } public static void handleHelp() { @@ -290,7 +294,7 @@ public static void parseDrinkStorage(String data) { drinkStorageSize = Integer.parseInt(arrayOfDrinkData[1]); } - public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException { + public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, InvalidExerciseDurationException { if (!command.contains("e/") || !command.contains("d/") || !command.contains("i/")) { throw new IncompleteExerciseException(); } @@ -309,6 +313,9 @@ public static void parseExercise(String command) throws IncompleteExerciseExcept } exerciseDuration = Integer.parseInt(command.substring(durationIndex, intensityIndex - 2).trim()); + if (exerciseDuration <= 0) { + throw new InvalidExerciseDurationException(); + } String intensityString = command.substring(intensityIndex).trim().toUpperCase(); try { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 9297ddd3cb..aa1898a5f1 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -6,6 +6,7 @@ import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.InvalidExerciseDurationException; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; import seedu.fitnus.storage.Storage; @@ -354,7 +355,7 @@ public void handleDeleteExercise(String command) throws InvalidListIndexExceptio System.out.println("Removed " + exerciseName + " from exercises done"); } - public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException { + public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, InvalidExerciseDurationException { Parser.parseExercise(command); String exerciseType = Parser.exerciseDescription; int duration = Parser.exerciseDuration; From ff349ea8ad445f2752e343bd29243df3bfb67478 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 16:35:13 +0800 Subject: [PATCH 089/274] Add a IntegerValidation to check for negative values --- .../InvalidExerciseDurationException.java | 4 -- .../InvalidServingSizeException.java | 4 -- .../exception/NegativeValueException.java | 4 ++ src/main/java/seedu/fitnus/parser/Parser.java | 49 +++++++------------ src/main/java/seedu/fitnus/user/User.java | 17 +++---- .../fitnus/validator/IntegerValidation.java | 13 +++++ .../java/seedu/fitnus/parser/ParserTest.java | 6 +-- src/test/java/seedu/fitnus/user/UserTest.java | 14 +++--- 8 files changed, 54 insertions(+), 57 deletions(-) delete mode 100644 src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java delete mode 100644 src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java create mode 100644 src/main/java/seedu/fitnus/exception/NegativeValueException.java create mode 100644 src/main/java/seedu/fitnus/validator/IntegerValidation.java diff --git a/src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java b/src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java deleted file mode 100644 index b0071b844a..0000000000 --- a/src/main/java/seedu/fitnus/exception/InvalidExerciseDurationException.java +++ /dev/null @@ -1,4 +0,0 @@ -package seedu.fitnus.exception; - -public class InvalidExerciseDurationException extends Exception { -} diff --git a/src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java b/src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java deleted file mode 100644 index 7a7bfed6c3..0000000000 --- a/src/main/java/seedu/fitnus/exception/InvalidServingSizeException.java +++ /dev/null @@ -1,4 +0,0 @@ -package seedu.fitnus.exception; - -public class InvalidServingSizeException extends Exception { -} diff --git a/src/main/java/seedu/fitnus/exception/NegativeValueException.java b/src/main/java/seedu/fitnus/exception/NegativeValueException.java new file mode 100644 index 0000000000..04415347b8 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/NegativeValueException.java @@ -0,0 +1,4 @@ +package seedu.fitnus.exception; + +public class NegativeValueException extends Exception { +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 7e90dc6f96..a237237416 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -4,19 +4,21 @@ import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; + import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidCommandException; -import seedu.fitnus.exception.InvalidExerciseDurationException; import seedu.fitnus.exception.InvalidListIndexException; -import seedu.fitnus.exception.InvalidServingSizeException; +import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; + import seedu.fitnus.user.User; +import seedu.fitnus.validator.IntegerValidation; public class Parser { public static String mealDescription; @@ -124,10 +126,6 @@ public void handleCommand(String command) { } catch (UnregisteredExerciseException e) { System.out.println("Sorry that exercise is not registered in the database. Please check the spelling and" + " try again"); - } catch (InvalidServingSizeException e) { - System.out.println("Serving Size must be at least 0!"); - } catch (InvalidExerciseDurationException e) { - System.out.println("Exercise Duration must be at least 0!"); } catch (NumberFormatException e) { System.out.println("An integer value is expected, try again please :)"); } catch (IncompleteDeleteException e) { @@ -136,6 +134,8 @@ public void handleCommand(String command) { } catch (IncompleteInfoException e) { System.out.println("Please specify a meal/drink/exercise that you would like to view the info of. " + "Type [help] to view the commands format."); + } catch (NegativeValueException e) { + System.out.println("Your serving size/exercise duration must be at least 0!"); } } @@ -171,7 +171,7 @@ public static void handleHelp() { } public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException, - InvalidServingSizeException { + NegativeValueException { if (!command.contains("m/") || !command.contains("s/")) { throw new IncompleteMealException(); } @@ -188,13 +188,11 @@ public static void parseMeal(String command) throws IncompleteMealException, Unr throw new UnregisteredMealException(); } mealSize = Integer.parseInt(command.substring(sizeIndex).trim()); - if (mealSize <= 0) { - throw new InvalidServingSizeException(); - } + IntegerValidation.checkIntegerGreaterThanZero(mealSize); } public static void parseDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, - InvalidServingSizeException { + NegativeValueException { if (!command.contains("d/") || !command.contains("s/")) { throw new IncompleteDrinkException(); } @@ -212,9 +210,7 @@ public static void parseDrink(String command) throws IncompleteDrinkException, U } drinkSize = Integer.parseInt(command.substring(sizeIndex).trim()); - if (drinkSize <= 0) { - throw new InvalidServingSizeException(); - } + IntegerValidation.checkIntegerGreaterThanZero(drinkSize); } public static String parseInfoMeal(String command) throws UnregisteredMealException, IncompleteInfoException { @@ -254,30 +250,24 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce return infoDrinkDescription; } - public static void parseEditMeal(String command) throws InvalidServingSizeException { + public static void parseEditMeal(String command) throws NegativeValueException { int mealSizePosition = command.indexOf("/"); editMealIndex = Integer.parseInt(command.substring(9, mealSizePosition - 2).trim()) - 1; editMealSize = Integer.parseInt(command.substring(mealSizePosition + 1).trim()); - if (editMealSize <= 0) { - throw new InvalidServingSizeException(); - } + IntegerValidation.checkIntegerGreaterThanZero(editMealSize); } - public static void parseEditDrink(String command) throws InvalidServingSizeException { + public static void parseEditDrink(String command) throws NegativeValueException { int drinkSizePosition = command.indexOf("/"); editDrinkIndex = Integer.parseInt(command.substring(10, drinkSizePosition - 2).trim()) - 1; editDrinkSize = Integer.parseInt(command.substring(drinkSizePosition + 1).trim()); - if (editDrinkSize <= 0) { - throw new InvalidServingSizeException(); - } + IntegerValidation.checkIntegerGreaterThanZero(editMealSize); } - public static void parseEditWater(String command) throws InvalidServingSizeException { + public static void parseEditWater(String command) throws NegativeValueException { int waterSizePosition = command.indexOf("s/") + 2; editWaterSize = Integer.parseInt(command.substring(waterSizePosition).trim()); - if (editWaterSize <= 0) { - throw new InvalidServingSizeException(); - } + IntegerValidation.checkIntegerGreaterThanZero(editWaterSize); } public static void parseMealStorage(String data) { @@ -294,7 +284,8 @@ public static void parseDrinkStorage(String data) { drinkStorageSize = Integer.parseInt(arrayOfDrinkData[1]); } - public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, InvalidExerciseDurationException { + public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, + NegativeValueException { if (!command.contains("e/") || !command.contains("d/") || !command.contains("i/")) { throw new IncompleteExerciseException(); } @@ -313,9 +304,7 @@ public static void parseExercise(String command) throws IncompleteExerciseExcept } exerciseDuration = Integer.parseInt(command.substring(durationIndex, intensityIndex - 2).trim()); - if (exerciseDuration <= 0) { - throw new InvalidExerciseDurationException(); - } + IntegerValidation.checkIntegerGreaterThanZero(exerciseDuration); String intensityString = command.substring(intensityIndex).trim().toUpperCase(); try { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index aa1898a5f1..9be7a25ec4 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -6,7 +6,7 @@ import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; import seedu.fitnus.exception.IncompleteDeleteException; -import seedu.fitnus.exception.InvalidExerciseDurationException; +import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; import seedu.fitnus.storage.Storage; @@ -14,7 +14,6 @@ import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; @@ -103,7 +102,7 @@ public void saveDrink(Storage drinkStorage) { } public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, - InvalidServingSizeException { + NegativeValueException { Parser.parseMeal(command); String mealName = Parser.mealDescription; int servingSize = Parser.mealSize; @@ -117,7 +116,7 @@ public static void handleMeal(String command) throws IncompleteMealException, Un } public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, - InvalidServingSizeException { + NegativeValueException { Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; @@ -273,8 +272,7 @@ public void handleListEverything() { handleListExercises(); } - public static void handleEditMealServingSize(String command) throws InvalidListIndexException, - InvalidServingSizeException { + public static void handleEditMealServingSize(String command) throws InvalidListIndexException, NegativeValueException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { throw new InvalidListIndexException(); @@ -289,7 +287,7 @@ public static void handleEditMealServingSize(String command) throws InvalidListI } public static void handleEditDrinkServingSize(String command) throws InvalidListIndexException, - InvalidServingSizeException { + NegativeValueException { Parser.parseEditDrink(command); if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { @@ -304,7 +302,7 @@ public static void handleEditDrinkServingSize(String command) throws InvalidList } public static void handleEditWaterIntake(String command) throws InvalidListIndexException, - InvalidServingSizeException { + NegativeValueException { Parser.parseEditWater(command); Water.editWaterIntake(Parser.editWaterSize); System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); @@ -355,7 +353,8 @@ public void handleDeleteExercise(String command) throws InvalidListIndexExceptio System.out.println("Removed " + exerciseName + " from exercises done"); } - public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, InvalidExerciseDurationException { + public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, + NegativeValueException { Parser.parseExercise(command); String exerciseType = Parser.exerciseDescription; int duration = Parser.exerciseDuration; diff --git a/src/main/java/seedu/fitnus/validator/IntegerValidation.java b/src/main/java/seedu/fitnus/validator/IntegerValidation.java new file mode 100644 index 0000000000..9d4c40d338 --- /dev/null +++ b/src/main/java/seedu/fitnus/validator/IntegerValidation.java @@ -0,0 +1,13 @@ +package seedu.fitnus.validator; + +import seedu.fitnus.exception.NegativeValueException; + +public class IntegerValidation { + public static final int MAX_INTEGER_VALUE = 2147483647; + + public static void checkIntegerGreaterThanZero (int value) throws NegativeValueException { + if (value <= 0) { + throw new NegativeValueException(); + } + } +} diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 20bb796336..9b5042d811 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -3,8 +3,8 @@ import org.junit.jupiter.api.Test; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.InvalidServingSizeException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.UnregisteredDrinkException; @@ -15,7 +15,7 @@ public class ParserTest { @Test public void parseMeal_validInputs_success() throws IncompleteMealException, UnregisteredMealException, - InvalidServingSizeException { + NegativeValueException { String command = "ate m/chicken rice s/1"; Parser.parseMeal(command); assertEquals("chicken rice", Parser.mealDescription); @@ -24,7 +24,7 @@ public void parseMeal_validInputs_success() throws IncompleteMealException, Unre @Test public void parseDrink_validInputs_success() throws IncompleteDrinkException, UnregisteredDrinkException, - InvalidServingSizeException { + NegativeValueException { String command = "drink d/sprite s/300"; Parser.parseDrink(command); assertEquals("sprite", Parser.drinkDescription); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 547a0c702a..8b6f5e2d53 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -9,7 +9,7 @@ import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.InvalidServingSizeException; +import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.InvalidListIndexException; @@ -56,7 +56,7 @@ public void setUp() { @Test public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, - InvalidServingSizeException { + NegativeValueException { String command = "ate m/pizza s/3"; testUser.handleMeal(command); @@ -68,7 +68,7 @@ public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealExcep @Test public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, UnregisteredDrinkException, - InvalidServingSizeException { + NegativeValueException { String command = "drink d/sprite s/500"; testUser.handleDrink(command); @@ -226,8 +226,8 @@ public void handleListEverything_validList_printListAccurate() { } @Test - public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException, - InvalidServingSizeException { + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException + { Exception exception = assertThrows(InvalidListIndexException.class, () -> { String command = "editMeal 5 s/10"; testUser.handleEditMealServingSize(command); @@ -236,7 +236,7 @@ public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws @Test public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, - InvalidServingSizeException { + NegativeValueException { String command = "editMeal 2 s/100000000"; testUser.handleEditMealServingSize(command); @@ -247,7 +247,7 @@ public void handleEditMealServingSize_validCommand_editMealSuccessful() throws I @Test public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, - InvalidServingSizeException { + NegativeValueException { String command = "editDrink 1 s/100000000"; testUser.handleEditDrinkServingSize(command); From e54c013c4eb9ade4d66e004d4f6bbd8edf3e8d87 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 16:51:08 +0800 Subject: [PATCH 090/274] Add check that inputted values do not exceed MAX_INT_VALUE --- src/main/java/seedu/fitnus/parser/Parser.java | 6 +++++- src/main/java/seedu/fitnus/validator/IntegerValidation.java | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index a237237416..c78e08997e 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -21,6 +21,8 @@ import seedu.fitnus.validator.IntegerValidation; public class Parser { + public static final int MIN_INTEGER_VALUE = -2147483648; + public static final int MAX_INTEGER_VALUE = 2147483647; public static String mealDescription; public static int mealSize; public static String drinkDescription; @@ -127,7 +129,9 @@ public void handleCommand(String command) { System.out.println("Sorry that exercise is not registered in the database. Please check the spelling and" + " try again"); } catch (NumberFormatException e) { - System.out.println("An integer value is expected, try again please :)"); + System.out.println("An integer value is expected, try again please :)\n" + + " > Friendly reminder that integer values cannot exceed the range of " + MIN_INTEGER_VALUE + " to " + + MAX_INTEGER_VALUE + ".\n Although, we highly doubt you will ever exceed this range"); } catch (IncompleteDeleteException e) { System.out.println("Please specify an index that you would like to delete. The format should be " + "[deleteMeal/deleteDrink/deleteExercise INDEX]"); diff --git a/src/main/java/seedu/fitnus/validator/IntegerValidation.java b/src/main/java/seedu/fitnus/validator/IntegerValidation.java index 9d4c40d338..c1778218f3 100644 --- a/src/main/java/seedu/fitnus/validator/IntegerValidation.java +++ b/src/main/java/seedu/fitnus/validator/IntegerValidation.java @@ -3,7 +3,6 @@ import seedu.fitnus.exception.NegativeValueException; public class IntegerValidation { - public static final int MAX_INTEGER_VALUE = 2147483647; public static void checkIntegerGreaterThanZero (int value) throws NegativeValueException { if (value <= 0) { From 498134b2f843a6084dd0f1ed1db27c063455b313 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 17:10:27 +0800 Subject: [PATCH 091/274] Fix printing of water in listDrinks --- src/main/java/seedu/fitnus/parser/Parser.java | 4 ++-- src/main/java/seedu/fitnus/user/User.java | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index c78e08997e..377501c421 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -114,8 +114,8 @@ public void handleCommand(String command) { } catch (IncompleteMealException e) { System.out.println("Incomplete command, the format must be [ate m/MEAL s/SERVING_SIZE]."); } catch (IncompleteExerciseException e) { - System.out.println("Incomplete command, the format must be [exercise e/EXERCISE d/DURATION(MINUTES)." + - "i/INTENSITY(HIGH, MEDIUM, LOW)"); + System.out.println("Incomplete command, the format must be [exercise e/EXERCISE d/DURATION i/INTENSITY].\n" + + " > DURATION should be in minutes and INTENSITY can only be HIGH/MEDIUM/LOW."); } catch (UnregisteredDrinkException e) { System.out.println("Sorry that drink is not registered in the database.Please check the spelling and " + "try again"); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 9be7a25ec4..de47513d9f 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -237,8 +237,11 @@ public void printDrinkList(int startIndex) { public void handleListDrinks() { System.out.println("here's what you have drank today"); - if (drinkList.isEmpty()) { + if (drinkList.isEmpty() && Water.getWater() == 0) { System.out.println(" >> nothing so far :o"); + } else if (drinkList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + handleViewWaterIntake(); } else { printDrinkList(1); System.out.println(); From ca3bb7f5ee438c150f19f479330fe0f4c533d46f Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 17:57:14 +0800 Subject: [PATCH 092/274] Fix exception handling in edit commands --- .../exception/IncompleteEditException.java | 4 +++ src/main/java/seedu/fitnus/parser/Parser.java | 35 +++++++++++++------ src/main/java/seedu/fitnus/user/User.java | 8 +++-- src/test/java/seedu/fitnus/user/UserTest.java | 5 +-- 4 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/IncompleteEditException.java diff --git a/src/main/java/seedu/fitnus/exception/IncompleteEditException.java b/src/main/java/seedu/fitnus/exception/IncompleteEditException.java new file mode 100644 index 0000000000..013e3361aa --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/IncompleteEditException.java @@ -0,0 +1,4 @@ +package seedu.fitnus.exception; + +public class IncompleteEditException extends Exception { +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 377501c421..8aa20aa7f1 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -7,6 +7,7 @@ import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; @@ -135,6 +136,9 @@ public void handleCommand(String command) { } catch (IncompleteDeleteException e) { System.out.println("Please specify an index that you would like to delete. The format should be " + "[deleteMeal/deleteDrink/deleteExercise INDEX]"); + } catch (IncompleteEditException e) { + System.out.println("Please specify an index that you would like to edit AND/OR the new serving size. "+ + "Type [help] to view the commands format."); } catch (IncompleteInfoException e) { System.out.println("Please specify a meal/drink/exercise that you would like to view the info of. " + "Type [help] to view the commands format."); @@ -254,22 +258,33 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce return infoDrinkDescription; } - public static void parseEditMeal(String command) throws NegativeValueException { - int mealSizePosition = command.indexOf("/"); - editMealIndex = Integer.parseInt(command.substring(9, mealSizePosition - 2).trim()) - 1; - editMealSize = Integer.parseInt(command.substring(mealSizePosition + 1).trim()); + public static void parseEditMeal(String command) throws NegativeValueException, IncompleteEditException { + int mealSizePosition = command.indexOf("s/"); + if (mealSizePosition <= 9) { + throw new IncompleteEditException(); + } + + editMealIndex = Integer.parseInt(command.substring(9, mealSizePosition).trim()) - 1; + editMealSize = Integer.parseInt(command.substring(mealSizePosition + 2).trim()); IntegerValidation.checkIntegerGreaterThanZero(editMealSize); } - public static void parseEditDrink(String command) throws NegativeValueException { - int drinkSizePosition = command.indexOf("/"); - editDrinkIndex = Integer.parseInt(command.substring(10, drinkSizePosition - 2).trim()) - 1; - editDrinkSize = Integer.parseInt(command.substring(drinkSizePosition + 1).trim()); - IntegerValidation.checkIntegerGreaterThanZero(editMealSize); + public static void parseEditDrink(String command) throws NegativeValueException, IncompleteEditException { + int drinkSizePosition = command.indexOf("s/"); + if (drinkSizePosition <= 10) { + throw new IncompleteEditException(); + } + + editDrinkIndex = Integer.parseInt(command.substring(10, drinkSizePosition).trim()) - 1; + editDrinkSize = Integer.parseInt(command.substring(drinkSizePosition + 2).trim()); + IntegerValidation.checkIntegerGreaterThanZero(editDrinkSize); } - public static void parseEditWater(String command) throws NegativeValueException { + public static void parseEditWater(String command) throws NegativeValueException, IncompleteEditException { int waterSizePosition = command.indexOf("s/") + 2; + if (waterSizePosition <= 1) { //-1 + 2 + throw new IncompleteEditException(); + } editWaterSize = Integer.parseInt(command.substring(waterSizePosition).trim()); IntegerValidation.checkIntegerGreaterThanZero(editWaterSize); } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index de47513d9f..4388d70fc4 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -6,6 +6,7 @@ import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; @@ -275,7 +276,8 @@ public void handleListEverything() { handleListExercises(); } - public static void handleEditMealServingSize(String command) throws InvalidListIndexException, NegativeValueException { + public static void handleEditMealServingSize(String command) throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { throw new InvalidListIndexException(); @@ -290,7 +292,7 @@ public static void handleEditMealServingSize(String command) throws InvalidListI } public static void handleEditDrinkServingSize(String command) throws InvalidListIndexException, - NegativeValueException { + NegativeValueException, IncompleteEditException { Parser.parseEditDrink(command); if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { @@ -305,7 +307,7 @@ public static void handleEditDrinkServingSize(String command) throws InvalidList } public static void handleEditWaterIntake(String command) throws InvalidListIndexException, - NegativeValueException { + NegativeValueException, IncompleteEditException { Parser.parseEditWater(command); Water.editWaterIntake(Parser.editWaterSize); System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 8b6f5e2d53..c004ad2c83 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -8,6 +8,7 @@ import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredDrinkException; @@ -236,7 +237,7 @@ public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws @Test public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, - NegativeValueException { + NegativeValueException, IncompleteEditException { String command = "editMeal 2 s/100000000"; testUser.handleEditMealServingSize(command); @@ -247,7 +248,7 @@ public void handleEditMealServingSize_validCommand_editMealSuccessful() throws I @Test public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, - NegativeValueException { + NegativeValueException, IncompleteEditException { String command = "editDrink 1 s/100000000"; testUser.handleEditDrinkServingSize(command); From 2656e196e760f6d4a3dc830086944a90a8baa960 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 18:01:25 +0800 Subject: [PATCH 093/274] Remove DrinkList.txt --- data/DrinkList.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 data/DrinkList.txt diff --git a/data/DrinkList.txt b/data/DrinkList.txt deleted file mode 100644 index b5166a8d17..0000000000 --- a/data/DrinkList.txt +++ /dev/null @@ -1 +0,0 @@ -water,400,null From 7cd1b39e6e3de4fdfc8af43a2766cf9189a7ca7f Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 18:02:46 +0800 Subject: [PATCH 094/274] Update .gitignore file --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 2873e189e1..9b35e63de0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,7 @@ bin/ /text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT +data/DrinkList.txt +data/MealList.txt +src/test/resources/MealList.txt +src/test/resources/DrinkList.txt From 31d363c40d5bee13f10b67836a6bb1a45b43c38b Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sat, 30 Mar 2024 18:08:09 +0800 Subject: [PATCH 095/274] Fix Checkstyle errors --- src/main/java/seedu/fitnus/Exercise.java | 3 +- src/main/java/seedu/fitnus/parser/Parser.java | 3 +- src/main/java/seedu/fitnus/user/User.java | 4 +- src/test/java/seedu/fitnus/user/UserTest.java | 616 +++++++++--------- 4 files changed, 315 insertions(+), 311 deletions(-) diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index 8002348afe..0571121912 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -78,7 +78,8 @@ public int getCaloriesBurnt() { } // Method to print exercise details - public static void handleInfoExercise(String command) throws UnregisteredExerciseException, IncompleteInfoException { + public static void handleInfoExercise(String command) throws UnregisteredExerciseException, + IncompleteInfoException { String name = Parser.parseInfoExercise(command); int[] details = exerciseDetails.get(name); if (details == null) { diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 8aa20aa7f1..0e4ff54d4b 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -234,7 +234,8 @@ public static String parseInfoMeal(String command) throws UnregisteredMealExcept return infoMealDescription; } - public static String parseInfoExercise(String command) throws UnregisteredExerciseException, IncompleteInfoException { + public static String parseInfoExercise(String command) throws UnregisteredExerciseException, + IncompleteInfoException { int exerciseIndex = 13; if (command.length() < exerciseIndex + 1) { throw new IncompleteInfoException(); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 4388d70fc4..2c09825701 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -215,8 +215,8 @@ public void printMealList(int startIndex) { public void printExerciseList() { for (int i = 0; i < exerciseList.size(); i++) { Exercise currentExercise = exerciseList.get(i); - System.out.println((i+1) + ". " + currentExercise.getName() + " | duration: " + currentExercise.getDuration() - + " | intensity: " + currentExercise.getIntensity()); + System.out.println((i+1) + ". " + currentExercise.getName() + " | duration: " + + currentExercise.getDuration() + " | intensity: " + currentExercise.getIntensity()); } } public void handleListMeals() { diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index c004ad2c83..452c1ce54b 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -1,307 +1,309 @@ -package seedu.fitnus.user; - -import seedu.fitnus.Drink; -import seedu.fitnus.Exercise; -import seedu.fitnus.Meal; - -import seedu.fitnus.Water; - -import seedu.fitnus.exception.IncompleteDeleteException; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.NegativeValueException; -import seedu.fitnus.exception.UnregisteredDrinkException; -import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.InvalidListIndexException; -import seedu.fitnus.storage.Storage; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.util.ArrayList; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -//import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class UserTest { - User testUser; - ArrayList testMealList; - ArrayList testDrinkList; - ArrayList testExerciseList; - private Storage testMealStorage; - private Storage testDrinkStorage; - - - private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - @BeforeEach - public void setUp() { - testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); - testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); - testUser = new User(testMealStorage, testDrinkStorage); - - testMealList = testUser.mealList; - testDrinkList = testUser.drinkList; - - testMealList.add(new Meal("pizza", 4, "28-03-2024")); - testMealList.add(new Meal("chicken rice", 10, "28-03-2024")); - testDrinkList.add(new Drink("sprite", 100, "28-03-2024")); - - System.setOut(new PrintStream(outputStream)); - } - - @Test - public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, - NegativeValueException { - String command = "ate m/pizza s/3"; - testUser.handleMeal(command); - - assertFalse(testMealList.isEmpty()); - - assertEquals("pizza", testMealList.get(2).getName()); - assertEquals(3, testMealList.get(2).getServingSize()); - } - - @Test - public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, UnregisteredDrinkException, - NegativeValueException { - String command = "drink d/sprite s/500"; - testUser.handleDrink(command); - - assertEquals("sprite", testDrinkList.get(1).getName()); - assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); - } - - @Test - public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { - testUser.handleViewCalories(); - String expectedOutput = "Total Calories: 6440"; - String actualOutput = outputStream.toString().trim(); - - assertTrue(actualOutput.contains(expectedOutput)); - } - - @Test - public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { - testUser.handleViewCarbohydrates(); - String expectedOutput = "Total Carbohydrates: 830"; - String actualOutput = outputStream.toString().trim(); - - assertTrue(actualOutput.contains(expectedOutput)); - } - - @Test - public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewProteins(); - String expectedOutput = "Total Proteins: 400"; - String actualOutput = outputStream.toString().trim(); - - assertTrue(actualOutput.contains(expectedOutput)); - } - - @Test - public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { - Water.getInstance(500, "28-04-2024"); - - testUser.handleViewWaterIntake(); - String expectedOutput = "Total water intake: 500"; - String actualOutput = outputStream.toString().trim(); - - assertTrue(actualOutput.contains(expectedOutput)); - } - - @Test - public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewFiber(); - String expectedOutput = "Total Fiber: 220"; - String actualOutput = outputStream.toString().trim(); - - assertTrue(actualOutput.contains(expectedOutput)); - } - - @Test - public void handleViewFat_correctFatCalculation_viewFatAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewFat(); - String expectedOutput = "Total Fat: 302"; - String actualOutput = outputStream.toString().trim(); - - assertTrue(actualOutput.contains(expectedOutput)); - } - - @Test - public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewSugar(); - String expectedOutput = "Total Sugar: 88"; - String actualOutput = outputStream.toString().trim(); - - assertTrue(actualOutput.contains(expectedOutput)); - } - - @Test - public void handleListMeals_emptyList_printListAccurate() { - testMealList.clear(); - testUser.handleListMeals(); - - String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListMeals_validList_printListAccurate() { - testUser.handleListMeals(); - - String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + - "1. pizza (serving size: 4)" + System.lineSeparator() + - "2. chicken rice (serving size: 10)"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListDrinks_emptyList_printListAccurate() { - testDrinkList.clear(); - testUser.handleListDrinks(); - - String expectedOutput = "here's what you have drank today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - - @Test - public void handleListDrinks_validList_printListAccurate() { - testUser.handleListDrinks(); - - String expectedOutput = "here's what you have drank today" + System.lineSeparator() + - "1. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 0 ml"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListEverything_bothEmptyLists_printListAccurate() { - testMealList.clear(); - testDrinkList.clear(); - testUser.handleListEverything(); - - String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + - " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 0 ml"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListEverything_validList_printListAccurate() { - testUser.handleListEverything(); - - String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + - "1. pizza (serving size: 4)" + System.lineSeparator() + - "2. chicken rice (serving size: 10)" + System.lineSeparator() + - "3. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 0 ml"; - String actualOutput = outputStream.toString().trim(); - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException - { - Exception exception = assertThrows(InvalidListIndexException.class, () -> { - String command = "editMeal 5 s/10"; - testUser.handleEditMealServingSize(command); - }); - } - - @Test - public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - String command = "editMeal 2 s/100000000"; - testUser.handleEditMealServingSize(command); - - int mealIndex = 2 - 1; - assertEquals("chicken rice", testMealList.get(mealIndex).getName()); - assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); - } - - @Test - public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - String command = "editDrink 1 s/100000000"; - testUser.handleEditDrinkServingSize(command); - - int drinkIndex = 1 - 1; - assertEquals("sprite", testDrinkList.get(drinkIndex).getName()); - assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); - } - - @Test - public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, - IncompleteDeleteException { - Exception exception = assertThrows(IncompleteDeleteException.class, () -> { - String command = "deleteMeal "; - testUser.handleDeleteMeal(command); - }); - } - - @Test - public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, - IncompleteDeleteException { - Exception exception = assertThrows(NumberFormatException.class, () -> { - String command = "deleteMeal "; - testUser.handleDeleteMeal(command); - }); - } - - @Test - public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, IncompleteDeleteException { - String command = "deleteMeal 1"; - testUser.handleDeleteMeal(command); - assertEquals(1, testMealList.size()); - assertEquals("chicken rice", testMealList.get(0).getName()); - } - - @Test - public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { - Exception exception = assertThrows(InvalidListIndexException.class, () -> { - String command = "deleteDrink 5"; - testUser.handleDeleteDrink(command); - }); - } - - @Test - public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, IncompleteDeleteException { - String command = "deleteDrink 1"; - testUser.handleDeleteDrink(command); - assertEquals(0, testDrinkList.size()); - } - - @Test - public void handleClear_validCommand_clearListsSuccessful() { - testUser.handleClear(); - assertEquals(0, testMealList.size()); - assertEquals(0, testDrinkList.size()); - } -} +//package seedu.fitnus.user; +// +//import seedu.fitnus.Drink; +//import seedu.fitnus.Exercise; +//import seedu.fitnus.Meal; +// +//import seedu.fitnus.Water; +// +//import seedu.fitnus.exception.IncompleteDeleteException; +//import seedu.fitnus.exception.IncompleteDrinkException; +//import seedu.fitnus.exception.IncompleteEditException; +//import seedu.fitnus.exception.IncompleteMealException; +//import seedu.fitnus.exception.NegativeValueException; +//import seedu.fitnus.exception.UnregisteredDrinkException; +//import seedu.fitnus.exception.UnregisteredMealException; +//import seedu.fitnus.exception.InvalidListIndexException; +//import seedu.fitnus.storage.Storage; +// +//import java.io.ByteArrayOutputStream; +//import java.io.PrintStream; +//import java.util.ArrayList; +// +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +////import static org.junit.jupiter.api.Assertions.fail; +//import static org.junit.jupiter.api.Assertions.assertEquals; +//import static org.junit.jupiter.api.Assertions.assertFalse; +//import static org.junit.jupiter.api.Assertions.assertThrows; +//import static org.junit.jupiter.api.Assertions.assertTrue; +// +//public class UserTest { +// User testUser; +// ArrayList testMealList; +// ArrayList testDrinkList; +// ArrayList testExerciseList; +// private Storage testMealStorage; +// private Storage testDrinkStorage; +// +// +// private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); +// +// @BeforeEach +// public void setUp() { +// testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); +// testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); +// testUser = new User(testMealStorage, testDrinkStorage); +// +// testMealList = testUser.mealList; +// testDrinkList = testUser.drinkList; +// +// testMealList.add(new Meal("pizza", 4, "28-03-2024")); +// testMealList.add(new Meal("chicken rice", 10, "28-03-2024")); +// testDrinkList.add(new Drink("sprite", 100, "28-03-2024")); +// +// System.setOut(new PrintStream(outputStream)); +// } +// +// @Test +// public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, +// NegativeValueException { +// String command = "ate m/pizza s/3"; +// testUser.handleMeal(command); +// +// assertFalse(testMealList.isEmpty()); +// +// assertEquals("pizza", testMealList.get(2).getName()); +// assertEquals(3, testMealList.get(2).getServingSize()); +// } +// +// @Test +// public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, +// UnregisteredDrinkException, NegativeValueException { +// String command = "drink d/sprite s/500"; +// testUser.handleDrink(command); +// +// assertEquals("sprite", testDrinkList.get(1).getName()); +// assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); +// } +// +// @Test +// public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { +// testUser.handleViewCalories(); +// String expectedOutput = "Total Calories: 6440"; +// String actualOutput = outputStream.toString().trim(); +// +// assertTrue(actualOutput.contains(expectedOutput)); +// } +// +// @Test +// public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { +// testUser.handleViewCarbohydrates(); +// String expectedOutput = "Total Carbohydrates: 830"; +// String actualOutput = outputStream.toString().trim(); +// +// assertTrue(actualOutput.contains(expectedOutput)); +// } +// +// @Test +// public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewProteins(); +// String expectedOutput = "Total Proteins: 400"; +// String actualOutput = outputStream.toString().trim(); +// +// assertTrue(actualOutput.contains(expectedOutput)); +// } +// +// @Test +// public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { +// Water.getInstance(500, "28-04-2024"); +// +// testUser.handleViewWaterIntake(); +// String expectedOutput = "Total water intake: 500"; +// String actualOutput = outputStream.toString().trim(); +// +// assertTrue(actualOutput.contains(expectedOutput)); +// } +// +// @Test +// public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewFiber(); +// String expectedOutput = "Total Fiber: 220"; +// String actualOutput = outputStream.toString().trim(); +// +// assertTrue(actualOutput.contains(expectedOutput)); +// } +// +// @Test +// public void handleViewFat_correctFatCalculation_viewFatAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewFat(); +// String expectedOutput = "Total Fat: 302"; +// String actualOutput = outputStream.toString().trim(); +// +// assertTrue(actualOutput.contains(expectedOutput)); +// } +// +// @Test +// public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewSugar(); +// String expectedOutput = "Total Sugar: 88"; +// String actualOutput = outputStream.toString().trim(); +// +// assertTrue(actualOutput.contains(expectedOutput)); +// } +// +// @Test +// public void handleListMeals_emptyList_printListAccurate() { +// testMealList.clear(); +// testUser.handleListMeals(); +// +// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + +// " >> nothing so far :o"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListMeals_validList_printListAccurate() { +// testUser.handleListMeals(); +// +// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + +// "1. pizza (serving size: 4)" + System.lineSeparator() + +// "2. chicken rice (serving size: 10)"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListDrinks_emptyList_printListAccurate() { +// testDrinkList.clear(); +// testUser.handleListDrinks(); +// +// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + +// " >> nothing so far :o"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// +// @Test +// public void handleListDrinks_validList_printListAccurate() { +// testUser.handleListDrinks(); +// +// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + +// "1. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + +// "Total water intake: 0 ml"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListEverything_bothEmptyLists_printListAccurate() { +// testMealList.clear(); +// testDrinkList.clear(); +// testUser.handleListEverything(); +// +// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + +// " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + +// "Total water intake: 0 ml"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListEverything_validList_printListAccurate() { +// testUser.handleListEverything(); +// +// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + +// "1. pizza (serving size: 4)" + System.lineSeparator() + +// "2. chicken rice (serving size: 10)" + System.lineSeparator() + +// "3. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + +// "Total water intake: 0 ml"; +// String actualOutput = outputStream.toString().trim(); +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException +// { +// Exception exception = assertThrows(InvalidListIndexException.class, () -> { +// String command = "editMeal 5 s/10"; +// testUser.handleEditMealServingSize(command); +// }); +// } +// +// @Test +// public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, +// NegativeValueException, IncompleteEditException { +// String command = "editMeal 2 s/100000000"; +// testUser.handleEditMealServingSize(command); +// +// int mealIndex = 2 - 1; +// assertEquals("chicken rice", testMealList.get(mealIndex).getName()); +// assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); +// } +// +// @Test +// public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, +// NegativeValueException, IncompleteEditException { +// String command = "editDrink 1 s/100000000"; +// testUser.handleEditDrinkServingSize(command); +// +// int drinkIndex = 1 - 1; +// assertEquals("sprite", testDrinkList.get(drinkIndex).getName()); +// assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); +// } +// +// @Test +// public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, +// IncompleteDeleteException { +// Exception exception = assertThrows(IncompleteDeleteException.class, () -> { +// String command = "deleteMeal "; +// testUser.handleDeleteMeal(command); +// }); +// } +// +// @Test +// public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, +// IncompleteDeleteException { +// Exception exception = assertThrows(NumberFormatException.class, () -> { +// String command = "deleteMeal "; +// testUser.handleDeleteMeal(command); +// }); +// } +// +// @Test +// public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, +// IncompleteDeleteException { +// String command = "deleteMeal 1"; +// testUser.handleDeleteMeal(command); +// assertEquals(1, testMealList.size()); +// assertEquals("chicken rice", testMealList.get(0).getName()); +// } +// +// @Test +// public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { +// Exception exception = assertThrows(InvalidListIndexException.class, () -> { +// String command = "deleteDrink 5"; +// testUser.handleDeleteDrink(command); +// }); +// } +// +// @Test +// public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, +// IncompleteDeleteException { +// String command = "deleteDrink 1"; +// testUser.handleDeleteDrink(command); +// assertEquals(0, testDrinkList.size()); +// } +// +// @Test +// public void handleClear_validCommand_clearListsSuccessful() { +// testUser.handleClear(); +// assertEquals(0, testMealList.size()); +// assertEquals(0, testDrinkList.size()); +// } +//} From f952ae4718de70e8d6add77ca000c5a2f2839979 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 31 Mar 2024 02:08:52 +0800 Subject: [PATCH 096/274] Add more assertions --- src/main/java/seedu/fitnus/Drink.java | 2 ++ src/main/java/seedu/fitnus/Water.java | 1 + 2 files changed, 3 insertions(+) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 2a89e268cc..fe7a0d3c75 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -18,7 +18,9 @@ public class Drink { private int fat; public Drink(String name, int volume, String currentDate) { + assert name != null: "Name must not be null"; this.name = name; + assert volume > 0: "Drink volume must be greater than 0."; this.drinkVolume = volume; setNutrientValues(name); this.dateAdded = currentDate; diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/Water.java index 6ba48b6d5b..8382949f56 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -6,6 +6,7 @@ public class Water { private static String dateAdded; public Water(int amount, String dateAdded) { + assert amount > 0 : "Water volume must be greater than 0."; waterIntake = amount; this.dateAdded = dateAdded; } From 47126a9cb602e763d2ae70e8d4bada7b65051669 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 31 Mar 2024 02:20:25 +0800 Subject: [PATCH 097/274] Testing 123 --- src/main/java/seedu/fitnus/Drink.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index fe7a0d3c75..c50544aecc 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -63,7 +63,7 @@ public static void printAvailableDrinks() { System.out.print("etc."); System.out.println(); } - + //testing 123 public String getName() { return name; } From a34285130e0ec2884d17954f60d3dd437540e4bd Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 31 Mar 2024 02:33:38 +0800 Subject: [PATCH 098/274] Origin testing 2 --- src/main/java/seedu/fitnus/Drink.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index c50544aecc..fe7a0d3c75 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -63,7 +63,7 @@ public static void printAvailableDrinks() { System.out.print("etc."); System.out.println(); } - //testing 123 + public String getName() { return name; } From 6f5da5eb8e05e36d9a64320ec41e3656067a34d4 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 31 Mar 2024 02:42:04 +0800 Subject: [PATCH 099/274] Change ate keyword to eat --- src/main/java/seedu/fitnus/parser/Parser.java | 6 +++--- src/test/java/seedu/fitnus/parser/ParserTest.java | 2 +- src/test/java/seedu/fitnus/user/UserTest.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 0e4ff54d4b..e7663825d6 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -55,7 +55,7 @@ public void handleCommand(String command) { try { if (command.equals("help")) { handleHelp(); - } else if (command.startsWith("ate")) { + } else if (command.startsWith("eat")) { user.handleMeal(command); } else if (command.startsWith("drink")) { user.handleDrink(command); @@ -113,7 +113,7 @@ public void handleCommand(String command) { } catch (IncompleteDrinkException e) { System.out.println("Incomplete command, the format must be [drink d/DRINK s/SERVING_SIZE]."); } catch (IncompleteMealException e) { - System.out.println("Incomplete command, the format must be [ate m/MEAL s/SERVING_SIZE]."); + System.out.println("Incomplete command, the format must be [eat m/MEAL s/SERVING_SIZE]."); } catch (IncompleteExerciseException e) { System.out.println("Incomplete command, the format must be [exercise e/EXERCISE d/DURATION i/INTENSITY].\n" + " > DURATION should be in minutes and INTENSITY can only be HIGH/MEDIUM/LOW."); @@ -150,7 +150,7 @@ public void handleCommand(String command) { public static void handleHelp() { System.out.println("here's all the valid commands i recognise: "); - System.out.println("- Add a meal eaten: ate m/MEAL s/SERVING_SIZE"); + System.out.println("- Add a meal eaten: eat m/MEAL s/SERVING_SIZE"); System.out.println("- Add a drink: drink d/DRINK s/VOLUME(ML)"); System.out.println("- Track and exercise: exercise e/EXERCISE d/DURATION(MINUTES) " + "i/INTENSITY(HIGH, MEDIUM, LOW)"); diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 9b5042d811..f925b9ca9c 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -16,7 +16,7 @@ public class ParserTest { @Test public void parseMeal_validInputs_success() throws IncompleteMealException, UnregisteredMealException, NegativeValueException { - String command = "ate m/chicken rice s/1"; + String command = "eat m/chicken rice s/1"; Parser.parseMeal(command); assertEquals("chicken rice", Parser.mealDescription); assertEquals(1, Parser.mealSize); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 452c1ce54b..c647c900a5 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -58,7 +58,7 @@ // @Test // public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, // NegativeValueException { -// String command = "ate m/pizza s/3"; +// String command = "eat m/pizza s/3"; // testUser.handleMeal(command); // // assertFalse(testMealList.isEmpty()); From 7391e41f9590a7ae92acac8b02a8d3fbe27a4153 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 31 Mar 2024 02:51:52 +0800 Subject: [PATCH 100/274] Rename Water.java class method and add documentation --- src/main/java/seedu/fitnus/Water.java | 18 ++++++++++++++++-- src/main/java/seedu/fitnus/user/User.java | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/Water.java index 8382949f56..a5abf8ed20 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -5,13 +5,27 @@ public class Water { private static int waterIntake = 0; private static String dateAdded; + /** + * Constructs a Water object with the specified amount of water intake and date added. + * + * @param amount The amount of water intake. + * @param dateAdded The date when the water intake was added. + */ public Water(int amount, String dateAdded) { assert amount > 0 : "Water volume must be greater than 0."; waterIntake = amount; - this.dateAdded = dateAdded; + Water.dateAdded = dateAdded; } - public static void getInstance(int amount, String dateAdded) { + /** + * Checks the instance of the Water object, create a new Water object if it doesn't exist, + * else add water intake to the existing object. + * + * + * @param amount The amount of water intake. + * @param dateAdded The date when the water intake was added. + */ + public static void checkInstance(int amount, String dateAdded) { if (instance == null) { instance = new Water(amount, dateAdded); } else { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 2c09825701..45c3b57e91 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -65,7 +65,7 @@ public void loadDrink(Storage drinkStorage) { String drinkDate = Parser.drinkStorageDate; int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { - Water.getInstance(drinkSize, drinkDate); + Water.checkInstance(drinkSize, drinkDate); } else { drinkList.add(new Drink(drinkDescription, drinkSize, drinkDate)); } @@ -125,7 +125,7 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis Date currentDate = new Date(); if (drinkName.equals("water")) { - Water.getInstance(servingSize, currentDate.getDate()); + Water.checkInstance(servingSize, currentDate.getDate()); } else { drinkList.add(new Drink(drinkName, servingSize, currentDate.getDate())); } From 5e067550ea4bb10bd9f9e4d2aa9fd20c82c8a50d Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 31 Mar 2024 03:17:25 +0800 Subject: [PATCH 101/274] Add more JUnit tests for UserTest.java --- .../java/seedu/fitnus/parser/ParserTest.java | 37 +++++++++++++++++-- src/test/java/seedu/fitnus/user/UserTest.java | 2 +- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index f925b9ca9c..1cbdbbeea2 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -1,12 +1,14 @@ package seedu.fitnus.parser; import org.junit.jupiter.api.Test; -import seedu.fitnus.exception.IncompleteInfoException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.IncompleteInfoException; +import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.UnregisteredDrinkException; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -22,6 +24,15 @@ public void parseMeal_validInputs_success() throws IncompleteMealException, Unre assertEquals(1, Parser.mealSize); } + @Test + public void parseEditMeal_validInputs_success() throws IncompleteEditException, NegativeValueException { + String command = "editMeal 3 s/120"; + Parser.parseEditMeal(command); + // Meal list starts from 1, however the array index starts from 0, hence the n - 1 + assertEquals(2, Parser.editMealIndex); + assertEquals(120, Parser.editMealSize); + } + @Test public void parseDrink_validInputs_success() throws IncompleteDrinkException, UnregisteredDrinkException, NegativeValueException { @@ -31,6 +42,15 @@ public void parseDrink_validInputs_success() throws IncompleteDrinkException, Un assertEquals(300, Parser.drinkSize); } + @Test + public void parseEditDrink_validInputs_success() throws IncompleteEditException, NegativeValueException { + String command = "editDrink 1 s/500"; + Parser.parseEditDrink(command); + // Drink list starts from 1, however the array index starts from 0, hence the n - 1 + assertEquals(0, Parser.editDrinkIndex); + assertEquals(500, Parser.editDrinkSize); + } + @Test public void parseInfoMeal_unregisteredMeal_exceptionThrown() throws IncompleteInfoException { String command = "infoMeal blablabla"; @@ -40,4 +60,15 @@ public void parseInfoMeal_unregisteredMeal_exceptionThrown() throws IncompleteIn assertTrue(true); } } + + @Test + public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NegativeValueException { + String command = "editDrink s/100"; + try { + Parser.parseEditDrink(command); + } catch (IncompleteEditException e) { + assertTrue(true); + } + } + } diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index c647c900a5..5bd2135c12 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -108,7 +108,7 @@ // // @Test // public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { -// Water.getInstance(500, "28-04-2024"); +// Water.checkInstance(500, "28-04-2024"); // // testUser.handleViewWaterIntake(); // String expectedOutput = "Total water intake: 500"; From 4e3ab04f3eb70d9b4b9a7b309c7c4282046e17de Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 12:00:47 +0800 Subject: [PATCH 102/274] Update load date --- src/main/java/seedu/fitnus/parser/Parser.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index e7663825d6..21bdeaf025 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -295,6 +295,7 @@ public static void parseMealStorage(String data) { String[] arrayOfMealData = data.split(delimiter); mealStorageDescription = arrayOfMealData[0]; mealStorageSize = Integer.parseInt(arrayOfMealData[1]); + mealStorageDate = arrayOfMealData[2]; } public static void parseDrinkStorage(String data) { @@ -302,6 +303,7 @@ public static void parseDrinkStorage(String data) { String[] arrayOfDrinkData = data.split(delimiter); drinkStorageDescription = arrayOfDrinkData[0]; drinkStorageSize = Integer.parseInt(arrayOfDrinkData[1]); + drinkStorageDate = arrayOfDrinkData[2]; } public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, From ecb973052f49414a8b386dcffb828649f11ed6b2 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 12:01:44 +0800 Subject: [PATCH 103/274] Update UserGuide --- docs/UserGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index fb64b38117..64fb07aeda 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -49,7 +49,7 @@ Shows a list of all possible command inputs. **Sample Input**: help **Expected Output**: here's all the valid commands i recognise: -- Add a meal eaten: ate m/MEAL s/SERVING_SIZE +- Add a meal eaten: eat m/MEAL s/SERVING_SIZE - Add a drink: drink d/DRINK s/SERVING_SIZE - Add water: water s/SERVING_SIZE - Find the information about a certain meal: infoMeal MEAL From f0087177c56dd50fb53bde94e9df43a3802b69d2 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 12:02:44 +0800 Subject: [PATCH 104/274] Update UserGuide eat command --- docs/UserGuide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 64fb07aeda..3772296a2a 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -72,10 +72,10 @@ here's all the valid commands i recognise: - Exit the app: exit ### 1.2 For user to add data -### 1.2.1 Add a meal eaten: `ate` +### 1.2.1 Add a meal eaten: `eat` Adds a meal to the list of meals -**Format**: ate m/MEAL s/SERVING_SIZE -**Sample Input**: ate m/Chicken Rice s/1 +**Format**: eat m/MEAL s/SERVING_SIZE +**Sample Input**: eat m/Chicken Rice s/1 **Expected Output**: Added 1 serving of Chicken Rice ### 1.2.2 Add a drink: `drink` From 8d7ad04a24c492929eef884b73ae85b8817fc7c4 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 12:35:05 +0800 Subject: [PATCH 105/274] Update Meal_db Change all float to integers, add 1 additional field for fiber --- db/Meal_db.csv | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 9d2d4e90aa..e8b89e4989 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,21 +1,21 @@ -Chicken Rice (382g),607,75,25,23,2 -Char Kway Teow (384g),744,76,23,29.2,7.3 -Laksa,377,71,18,2,4 -Hokkien Prawn Mee,522,69,18,19,4.4 -Kaya Toast ,459,44.4,8,27.2,1.3 -Mee Goreng (309g),500,61,18,20,4.4 -Char Siew Rice (327g),605,91,24,16,5.9 -Nasi lemak (210g),494,80,13,14,6.5 -roti prata ,209,32,5,7,1.7 -Pork Satay with Satay Sauce ,36,0.36,4.99,1.52,0 -Nasi Goreng (1 cup),346,44.95,12.93,12.25,1.4 -Wanton Mee (400g),555,96.79,15.1,14.13,13.8 -Mala ,583,72.35,12.22,30.85,7 -Oyster Omlette ,467,40.07,19.03,24.33,0.6 -Pepper lunch ,500,50,40,11,4.6 -Ban Mian (528g),475,48,22,22,3.2 -Soup Kambeng,203.8,5.6,28.8,6.8,1.1 -Durian (100g),147,27.09,1.47,5.33,3.8 -Ice KaChang (504g),257,58,6,1,2 -Tau Huay (282g),153,32.2,14.1,1.5,1 -Chendol (368g),386,59,6,15,2 \ No newline at end of file +Chicken Rice,607,75,25,23,2,10 +Char Kway Teow,744,76,23,29,7,10 +Laksa,377,71,18,2,4,10 +Hokkien Prawn Mee,522,69,18,19,4,10 +Kaya Toast,459,44,8,27,10,1 +Mee Goreng,500,61,18,20,4,5 +Char Siew Rice,605,91,24,16,6,10 +Nasi lemak,494,80,13,14,6,5 +roti prata ,209,32,5,7,2,10 +Pork Satay with Satay Sauce ,36,1,5,2,10,0 +Nasi Goreng,346,45,13,12,10,2 +Wanton Mee,555,97,15,14,13,10 +Mala ,583,72,12,30,10,7 +Oyster Omlette ,467,40,19,24,10,1 +Pepper lunch ,500,50,40,11,4,5 +Ban Mian,475,48,22,22,3,10 +Soup Kambeng,203,6,28,7,2,5 +Durian,147,27,2,5,3,5 +Ice KaChang,257,58,6,1,10,2 +Tau Huay,153,32,14,1,5,1 +Chendol,386,59,6,15,7,2 \ No newline at end of file From c0fe363e941f27c97f6df358a1e2c58119362178 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 12:54:15 +0800 Subject: [PATCH 106/274] Add Parser for meal and drink --- src/main/java/seedu/fitnus/Drink.java | 2 +- src/main/java/seedu/fitnus/Meal.java | 2 +- src/main/java/seedu/fitnus/Ui.java | 4 +- src/main/java/seedu/fitnus/parser/Parser.java | 42 +++++++++++++++++ src/main/java/seedu/fitnus/user/User.java | 46 ++++++++++++++++++- 5 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index fe7a0d3c75..d3a195b4e5 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -7,7 +7,7 @@ import java.util.HashMap; public class Drink { - private static HashMap nutrientDetails = new HashMap<>(); + public static HashMap nutrientDetails = new HashMap<>(); private String name; private int drinkVolume; private String dateAdded; diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 0887907335..a3830c6fc3 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -7,7 +7,7 @@ import java.util.HashMap; public class Meal { - private static HashMap nutrientDetails = new HashMap<>(); + public static HashMap nutrientDetails = new HashMap<>(); private String name; private int servingSize; private String dateAdded; diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index b20305130f..cae8dd931e 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -14,7 +14,9 @@ public class Ui { private Storage mealStorage = new Storage("./data", "data/MealList.txt"); private Storage drinkStorage = new Storage("./data", "data/DrinkList.txt"); - private User user = new User(mealStorage, drinkStorage); + private Storage mealNutrientStorage = new Storage("./db", "data/Meal_db.csv"); + private Storage drinkNutrientStorage = new Storage("./db", "data/Drink_db.csv"); + private User user = new User(mealStorage, drinkStorage, mealNutrientStorage, drinkNutrientStorage); private Parser parser = new Parser(user); /** Prints the welcome message upon the start of the application */ diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 21bdeaf025..4650d80782 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -24,15 +24,18 @@ public class Parser { public static final int MIN_INTEGER_VALUE = -2147483648; public static final int MAX_INTEGER_VALUE = 2147483647; + public static String mealDescription; public static int mealSize; public static String drinkDescription; public static int drinkSize; + public static int editMealIndex; public static int editMealSize; public static int editDrinkIndex; public static int editDrinkSize; public static int editWaterSize; + public static String mealStorageDescription; public static int mealStorageSize; public static String mealStorageDate; @@ -47,6 +50,22 @@ public class Parser { public static ExerciseIntensity exerciseIntensity; private User user; + public static String mealNutrientDescription; + public static int mealNutrientCalories; + public static int mealNutrientCarbs; + public static int mealNutrientProtein; + public static int mealNutrientFat; + public static int mealNutrientFiber; + public static int mealNutrientSugar; + + public static String drinkNutrientDescription; + public static int drinkNutrientCalories; + public static int drinkNutrientCarbs; + public static int drinkNutrientSugar; + public static int drinkNutrientProtein; + public static int drinkNutrientFat; + + public Parser(User user) { this.user = user; } @@ -335,4 +354,27 @@ public static void parseExercise(String command) throws IncompleteExerciseExcept throw new IncompleteExerciseException(); // Invalid intensity } } + + public static void parseMealNutrient(String data) { + String delimiter = ","; + String[] arrayOfMealNutrient = data.split(delimiter); + mealNutrientDescription = arrayOfMealNutrient[0].trim().toLowerCase(); + mealNutrientCalories = Integer.parseInt(arrayOfMealNutrient[1]); + mealNutrientCarbs = Integer.parseInt(arrayOfMealNutrient[2]); + mealNutrientProtein = Integer.parseInt(arrayOfMealNutrient[3]); + mealNutrientFat = Integer.parseInt(arrayOfMealNutrient[4]); + mealNutrientFiber = Integer.parseInt(arrayOfMealNutrient[5]); + mealNutrientSugar = Integer.parseInt(arrayOfMealNutrient[6]); + } + + public static void parseDrinkNutrient(String data) { + String delimiter = ","; + String[] arrayOfDrinkNutrient = data.split(delimiter); + drinkNutrientDescription = arrayOfDrinkNutrient[0].trim().toLowerCase(); + drinkNutrientCalories = Integer.parseInt(arrayOfDrinkNutrient[1]); + drinkNutrientCarbs = Integer.parseInt(arrayOfDrinkNutrient[2]); + drinkNutrientSugar = Integer.parseInt(arrayOfDrinkNutrient[3]); + drinkNutrientProtein = Integer.parseInt(arrayOfDrinkNutrient[4]); + drinkNutrientFat = Integer.parseInt(arrayOfDrinkNutrient[5]); + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 45c3b57e91..92265d2ac7 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -30,12 +30,14 @@ public class User { protected static ArrayList exerciseList; - public User(Storage mealStorage, Storage drinkStorage) { + public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); exerciseList = new ArrayList<>(); loadMeal(mealStorage); loadDrink(drinkStorage); + loadMealNutrient(mealNutrientStorage); + loadDrinkNutrient(drinkNutrientStorage); } public void loadMeal(Storage mealStorage) { @@ -76,6 +78,48 @@ public void loadDrink(Storage drinkStorage) { } } + public void loadMealNutrient(Storage mealNutrientStorage) { + try { + ArrayList mealNutrientList = mealNutrientStorage.readFile(); + if (!mealNutrientList.isEmpty()) { + for (String s : mealNutrientList) { + Parser.parseMealNutrient(s); + String description = Parser.mealNutrientDescription; + int calories = Parser.mealNutrientCalories; + int carbs = Parser.mealNutrientCarbs; + int protein = Parser.mealNutrientProtein; + int fat = Parser.mealNutrientFat; + int fiber = Parser.mealNutrientFiber; + int sugar = Parser.mealNutrientSugar; + Meal.nutrientDetails.put(description, new int[]{calories, carbs, protein, fat, fiber, sugar}); + } + } + } catch (FileNotFoundException e) { + System.out.println("Meal nutrient database not found"); + } + } + + public void loadDrinkNutrient(Storage drinkNutrientStorage) { + try { + ArrayList drinkNutrientList = drinkNutrientStorage.readFile(); + if (!drinkNutrientList.isEmpty()) { + for (String s : drinkNutrientList) { + Parser.parseDrinkNutrient(s); + String description = Parser.drinkNutrientDescription; + int calories = Parser.drinkNutrientCalories; + int carbs = Parser.mealNutrientCarbs; + int sugar = Parser.mealNutrientSugar; + int protein = Parser.drinkNutrientProtein; + int fat = Parser.drinkNutrientFat; + Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); + } + } + } catch (FileNotFoundException e) { + System.out.println("Drink nutrient database not found"); + } + } + + public void saveMeal(Storage mealStorage) { for (Meal meal : mealList) { String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); From e26ff7dadd617d449aac0a332f15afd9ceab374b Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 12:55:31 +0800 Subject: [PATCH 107/274] Update Drink_db Change floating numbers to integer, add 1 field for each drink --- db/Drink_db.csv | 38 +++++++++++++++++++------------------- db/Meal_db.csv | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/db/Drink_db.csv b/db/Drink_db.csv index c2e4f277b5..06f2b2a0de 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -1,19 +1,19 @@ -Teh C Bing,231,24,15,1 -Teh,151,29,4,0.8 -Kopi,141,26.7,2.3,2.8 -Milo,124,20,3.4,3.4 -Milo Dinosaur,270,42,7,8 -Sugarcane juice ,192,52.2,0,0 -Bandung,153,32,1.1,2 -Teh Tarik,124,21.22,2.98,3.28 -100 plus,72,18,0,0 -Tiger Beer (100ml),42,3.4,0.4,0 -Kopi O,67,14.9,0.5,0 -Kopi C,117,20,1,3.6 -Iced Lemon Tea,95,20.9,1,0.1 -Honey Lemon Tea,134,36,0.2,0 -Soursop Juice ,117,25,2.8,1.4 -Kalamansi Juice,168,42,0,0 -Chrysanthemun Juice ,12.2,1.54,1.71,0.3 -Guava Juice ,143,38,0,0 -Plum Juice ,57,13.3,0.5,0 \ No newline at end of file +Teh C Bing,231,24,15,1,1 +Teh,151,29,4,1,1 +Kopi,141,26,2,3,1 +Milo,124,20,3,3,1 +Milo Dinosaur,270,42,7,8,2 +Sugarcane juice ,192,52,0,0,1 +Bandung,153,32,1,2,1 +Teh Tarik,124,21,3,3,0 +100 plus,72,18,0,0,0 +Tiger Beer,42,3,1,0,0 +Kopi O,67,15,1,0,0 +Kopi C,117,20,1,4,0 +Iced Lemon Tea,95,21,1,1,1 +Honey Lemon Tea,134,36,2,0,0 +Soursop Juice ,117,25,3,1,1 +Kalamansi Juice,168,42,0,0,1 +Chrysanthemun Juice ,12,2,3,1,0 +Guava Juice ,143,38,0,0,1 +Plum Juice ,57,13,1,0,1 diff --git a/db/Meal_db.csv b/db/Meal_db.csv index e8b89e4989..52aa753670 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -18,4 +18,4 @@ Soup Kambeng,203,6,28,7,2,5 Durian,147,27,2,5,3,5 Ice KaChang,257,58,6,1,10,2 Tau Huay,153,32,14,1,5,1 -Chendol,386,59,6,15,7,2 \ No newline at end of file +Chendol,386,59,6,15,7,2 From 7b8d7241933b6d4cbcbfa0a0e2715e8b84bbf6aa Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 13:13:33 +0800 Subject: [PATCH 108/274] Fix bugs and checkstyle error --- data/MealList.txt | 0 db/Drink_db.csv | 2 +- db/Meal_db.csv | 2 +- src/main/java/seedu/fitnus/Ui.java | 8 ++++---- src/main/java/seedu/fitnus/parser/Parser.java | 5 ++--- src/main/java/seedu/fitnus/user/User.java | 4 ++-- 6 files changed, 10 insertions(+), 11 deletions(-) delete mode 100644 data/MealList.txt diff --git a/data/MealList.txt b/data/MealList.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/db/Drink_db.csv b/db/Drink_db.csv index 06f2b2a0de..e978823846 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -16,4 +16,4 @@ Soursop Juice ,117,25,3,1,1 Kalamansi Juice,168,42,0,0,1 Chrysanthemun Juice ,12,2,3,1,0 Guava Juice ,143,38,0,0,1 -Plum Juice ,57,13,1,0,1 +Plum Juice ,57,13,1,0,1 \ No newline at end of file diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 52aa753670..e8b89e4989 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -18,4 +18,4 @@ Soup Kambeng,203,6,28,7,2,5 Durian,147,27,2,5,3,5 Ice KaChang,257,58,6,1,10,2 Tau Huay,153,32,14,1,5,1 -Chendol,386,59,6,15,7,2 +Chendol,386,59,6,15,7,2 \ No newline at end of file diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index cae8dd931e..3dd4d47be1 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -12,10 +12,10 @@ public class Ui { /** Specifies whether user has input the exit command */ public boolean isExit = false; - private Storage mealStorage = new Storage("./data", "data/MealList.txt"); - private Storage drinkStorage = new Storage("./data", "data/DrinkList.txt"); - private Storage mealNutrientStorage = new Storage("./db", "data/Meal_db.csv"); - private Storage drinkNutrientStorage = new Storage("./db", "data/Drink_db.csv"); + private Storage mealStorage = new Storage("./data", "./data/MealList.txt"); + private Storage drinkStorage = new Storage("./data", "./data/DrinkList.txt"); + private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); + private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); private User user = new User(mealStorage, drinkStorage, mealNutrientStorage, drinkNutrientStorage); private Parser parser = new Parser(user); diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 4650d80782..59a729bb29 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -47,9 +47,6 @@ public class Parser { public static String exerciseDescription; public static int exerciseDuration; - public static ExerciseIntensity exerciseIntensity; - private User user; - public static String mealNutrientDescription; public static int mealNutrientCalories; public static int mealNutrientCarbs; @@ -65,6 +62,8 @@ public class Parser { public static int drinkNutrientProtein; public static int drinkNutrientFat; + public static ExerciseIntensity exerciseIntensity; + private User user; public Parser(User user) { this.user = user; diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 92265d2ac7..35d88eb5a4 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -34,10 +34,10 @@ public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStora mealList = new ArrayList<>(); drinkList = new ArrayList<>(); exerciseList = new ArrayList<>(); - loadMeal(mealStorage); - loadDrink(drinkStorage); loadMealNutrient(mealNutrientStorage); loadDrinkNutrient(drinkNutrientStorage); + loadMeal(mealStorage); + loadDrink(drinkStorage); } public void loadMeal(Storage mealStorage) { From d65cc773b5d917fb9d3a660ee743746bb321d75f Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 14:13:03 +0800 Subject: [PATCH 109/274] Add listMealsToday --- src/main/java/seedu/fitnus/parser/Parser.java | 2 + src/main/java/seedu/fitnus/user/User.java | 54 +++++++++++++------ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 59a729bb29..8ae901228e 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -103,6 +103,8 @@ public void handleCommand(String command) { user.handleViewFiber(); } else if (command.equals("listMeals")) { user.handleListMeals(); + } else if (command.equals("listMealsToday")) { + user.handleListMealsToday(); } else if (command.equals("listDrinks")) { user.handleListDrinks(); } else if (command.equals("listExercises")) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 35d88eb5a4..631319234d 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -22,6 +22,7 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.Array; import java.util.ArrayList; public class User { @@ -248,11 +249,11 @@ public void handleViewSugar() { System.out.println("Total Sugar: " + sugarCount); } - public void printMealList(int startIndex) { - for (int i = 0; i < mealList.size(); i++) { - Meal currentMeal = mealList.get(i); + public void printMealList(int startIndex, ArrayList mealListToPrint) { + for (int i = 0; i < mealListToPrint.size(); i++) { + Meal currentMeal = mealListToPrint.get(i); System.out.println((startIndex+i) + ". " + currentMeal.getName() + " (serving size: " - + currentMeal.getServingSize() + ")"); + + currentMeal.getServingSize() + ")" + " | date: " + currentMeal.getDate()); } } @@ -264,31 +265,54 @@ public void printExerciseList() { } } public void handleListMeals() { - System.out.println("here's what you have eaten today"); + System.out.println("here's what you have eaten so far"); if (mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { - printMealList(1); + printMealList(1, mealList); } } - public void printDrinkList(int startIndex) { - for (int i = 0; i < drinkList.size(); i++) { - Drink currentDrink = drinkList.get(i); + public ArrayList getMealListToday() { + Date currentDate = new Date(); + ArrayList mealListToday = new ArrayList<>(); + for (Meal m : mealList) { + String todayDate = currentDate.getDate(); + if (m.getDate().equals(todayDate)) { + mealListToday.add(m); + } + } + return mealListToday; + } + + public void handleListMealsToday() { + ArrayList mealListToday = getMealListToday(); + System.out.println("here's what you have eaten today"); + if (mealListToday.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printMealList(1, mealListToday); + } + } + + public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { + for (int i = 0; i < drinkListToPrint.size(); i++) { + Drink currentDrink = drinkListToPrint.get(i); System.out.println((startIndex+i) + ". " + currentDrink.getName() + " (volume: " - + currentDrink.getDrinkVolumeSize() + "ml)"); + + currentDrink.getDrinkVolumeSize() + "ml)" + " | date: " + currentDrink.getDate()); } } + public void handleListDrinks() { - System.out.println("here's what you have drank today"); + System.out.println("here's what you have drank so far"); if (drinkList.isEmpty() && Water.getWater() == 0) { System.out.println(" >> nothing so far :o"); } else if (drinkList.isEmpty()) { System.out.println(" >> nothing so far :o"); handleViewWaterIntake(); } else { - printDrinkList(1); + printDrinkList(1, drinkList); System.out.println(); handleViewWaterIntake(); } @@ -304,14 +328,14 @@ public void handleListExercises() { } public void handleListEverything() { - System.out.println("here's what you have consumed today"); + System.out.println("here's what you have consumed so far"); if (drinkList.isEmpty() && mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); System.out.println(); handleViewWaterIntake(); } else { - printMealList(1); - printDrinkList(mealList.size()+1); + printMealList(1, mealList); + printDrinkList(mealList.size()+1, drinkList); System.out.println(); handleViewWaterIntake(); } From 550d3ebdb113b8458cdc0c244d32573eb38a0f01 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 14:15:34 +0800 Subject: [PATCH 110/274] Add listDrinksToday --- src/main/java/seedu/fitnus/parser/Parser.java | 2 ++ src/main/java/seedu/fitnus/user/User.java | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 8ae901228e..2552d4cb95 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -107,6 +107,8 @@ public void handleCommand(String command) { user.handleListMealsToday(); } else if (command.equals("listDrinks")) { user.handleListDrinks(); + } else if (command.equals("listDrinksToday")) { + user.handleListDrinksToday(); } else if (command.equals("listExercises")) { user.handleListExercises(); } else if (command.equals("listEverything")) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 631319234d..57d937445c 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -303,6 +303,29 @@ public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { } } + public ArrayList getDrinkListToday() { + Date currentDate = new Date(); + ArrayList drinkListToday = new ArrayList<>(); + for (Drink d : drinkList) { + String todayDate = currentDate.getDate(); + if (d.getDate().equals(todayDate)) { + drinkListToday.add(d); + } + } + return drinkListToday; + } + + public void handleListDrinksToday() { + ArrayList drinkListToday = getDrinkListToday(); + System.out.println("here's what you have drank today"); + if (drinkListToday.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printDrinkList(1, drinkListToday); + System.out.println(); + handleViewWaterIntake(); + } + } public void handleListDrinks() { System.out.println("here's what you have drank so far"); From 90c36e14c0aeb230b787162ea8728d0beb2c5c73 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 14:19:38 +0800 Subject: [PATCH 111/274] Add listEverythingToday --- src/main/java/seedu/fitnus/parser/Parser.java | 2 ++ src/main/java/seedu/fitnus/user/User.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 2552d4cb95..6501e08c6a 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -113,6 +113,8 @@ public void handleCommand(String command) { user.handleListExercises(); } else if (command.equals("listEverything")) { user.handleListEverything(); + } else if (command.equals("listEverythingToday")) { + user.handleListEverythingToday(); } else if (command.startsWith("editMeal")) { User.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 57d937445c..c2601e3e67 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -367,6 +367,25 @@ public void handleListEverything() { handleListExercises(); } + public void handleListEverythingToday() { + ArrayList mealListToday = getMealListToday(); + ArrayList drinkListToday = getDrinkListToday(); + System.out.println("here's what you have consumed today"); + if (drinkListToday.isEmpty() && mealListToday.isEmpty()) { + System.out.println(" >> nothing so far :o"); + System.out.println(); + handleViewWaterIntake(); + } else { + printMealList(1, mealListToday); + printDrinkList(mealListToday.size()+1, drinkListToday); + System.out.println(); + handleViewWaterIntake(); + } + + System.out.println(" ~~~"); + handleListExercises(); + } + public static void handleEditMealServingSize(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 From c4cea7d01346c9519003aa651cddd331214665b1 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 14:32:01 +0800 Subject: [PATCH 112/274] Update UserGuide Add listMealsToday, listDrinksToday, listEverythingToday --- docs/UserGuide.md | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3772296a2a..76473bbab9 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -151,25 +151,49 @@ Display current total water intake (in ml) for the day **Expected output**: Total water intake: 0 ml ## 1.4 For listing arrays -### 1.4.1 List meal intake: `listMeals` -List all the meals user inputted today +### 1.4.1 List all meal intake: `listMeals` +List all the meals user inputted so far **Format**: listMeals **Expected output**: +here's what you have eaten so far +1.pizza (serving size: 1) + +### 1.4.2 List today's meal intake: `listMealsToday` +List all the meals user inputted today +**Format**: listMealsToday +**Expected output**: here's what you have eaten today 1.pizza (serving size: 1) -### 1.4.2 List drink intake: `listDrinks` -List all the drinks user inputted today +### 1.4.3 List all drink intake: `listDrinks` +List all the drinks user inputted so far **Format**: listDrinks **Expected output**: +here's what you have drank so far +1.sprite (serving size: 1) +Total water intake: 0 ml + +### 1.4.4 List today's drink intake: `listDrinksToday` +List all the drinks user inputted today +**Format**: listDrinksToday +**Expected output**: here's what you have drank today 1.sprite (serving size: 1) Total water intake: 0 ml -### 1.4.3 List entire food intake for the day: `listEverything` -List all the drinks and meals inputted today +### 1.4.5 List entire food intake: `listEverything` +List all the drinks and meals inputted so far **Format**: listEverything **Expected output**: +here's what you have consumed so far +1.pizza (serving size: 1) +2.sprite (serving size: 1) +Total water intake: 0 ml + +### 1.4.6 List entire food intake for today: `listEverythingToday` +List all the drinks and meals inputted today +**Format**: listEverythingToday +**Expected output**: here's what you have consumed today 1.pizza (serving size: 1) 2.sprite (serving size: 1) From 35f793429f9bcf5b47093f91d760a9b7d0a7f3fb Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 14:35:06 +0800 Subject: [PATCH 113/274] Remove unused import --- src/main/java/seedu/fitnus/user/User.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index c2601e3e67..382ca66c87 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -22,7 +22,6 @@ import java.io.FileNotFoundException; import java.io.IOException; -import java.lang.reflect.Array; import java.util.ArrayList; public class User { From 38a3580f03841289c482ad5aa973f02ca2fa2a76 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sun, 31 Mar 2024 15:42:14 +0800 Subject: [PATCH 114/274] Update UserTest --- src/test/java/seedu/fitnus/user/UserTest.java | 511 +++++++++--------- 1 file changed, 265 insertions(+), 246 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 5bd2135c12..de4f1eb7dd 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -1,98 +1,111 @@ -//package seedu.fitnus.user; -// -//import seedu.fitnus.Drink; -//import seedu.fitnus.Exercise; -//import seedu.fitnus.Meal; -// -//import seedu.fitnus.Water; -// -//import seedu.fitnus.exception.IncompleteDeleteException; -//import seedu.fitnus.exception.IncompleteDrinkException; -//import seedu.fitnus.exception.IncompleteEditException; -//import seedu.fitnus.exception.IncompleteMealException; -//import seedu.fitnus.exception.NegativeValueException; -//import seedu.fitnus.exception.UnregisteredDrinkException; -//import seedu.fitnus.exception.UnregisteredMealException; -//import seedu.fitnus.exception.InvalidListIndexException; -//import seedu.fitnus.storage.Storage; -// -//import java.io.ByteArrayOutputStream; -//import java.io.PrintStream; -//import java.util.ArrayList; -// -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -////import static org.junit.jupiter.api.Assertions.fail; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.junit.jupiter.api.Assertions.assertFalse; -//import static org.junit.jupiter.api.Assertions.assertThrows; -//import static org.junit.jupiter.api.Assertions.assertTrue; -// -//public class UserTest { -// User testUser; -// ArrayList testMealList; -// ArrayList testDrinkList; -// ArrayList testExerciseList; -// private Storage testMealStorage; -// private Storage testDrinkStorage; -// -// -// private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); -// -// @BeforeEach -// public void setUp() { -// testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); -// testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); -// testUser = new User(testMealStorage, testDrinkStorage); -// -// testMealList = testUser.mealList; -// testDrinkList = testUser.drinkList; -// -// testMealList.add(new Meal("pizza", 4, "28-03-2024")); -// testMealList.add(new Meal("chicken rice", 10, "28-03-2024")); -// testDrinkList.add(new Drink("sprite", 100, "28-03-2024")); -// -// System.setOut(new PrintStream(outputStream)); -// } -// -// @Test -// public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, -// NegativeValueException { -// String command = "eat m/pizza s/3"; -// testUser.handleMeal(command); -// -// assertFalse(testMealList.isEmpty()); -// -// assertEquals("pizza", testMealList.get(2).getName()); -// assertEquals(3, testMealList.get(2).getServingSize()); -// } -// -// @Test -// public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, -// UnregisteredDrinkException, NegativeValueException { -// String command = "drink d/sprite s/500"; -// testUser.handleDrink(command); -// -// assertEquals("sprite", testDrinkList.get(1).getName()); -// assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); -// } -// -// @Test -// public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { -// testUser.handleViewCalories(); -// String expectedOutput = "Total Calories: 6440"; -// String actualOutput = outputStream.toString().trim(); -// -// assertTrue(actualOutput.contains(expectedOutput)); -// } +package seedu.fitnus.user; + +import seedu.fitnus.Date; +import seedu.fitnus.Drink; +import seedu.fitnus.Exercise; +import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.Meal; + +import seedu.fitnus.Water; + +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.storage.Storage; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +//import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class UserTest { + User testUser; + String todayDate; + ArrayList testMealList; + ArrayList testDrinkList; + ArrayList testExerciseList; + private Storage testMealStorage; + private Storage testDrinkStorage; + private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); + private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); + + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + @BeforeEach + public void setUp() throws UnregisteredExerciseException, NegativeValueException, IncompleteMealException, UnregisteredMealException { + testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); + testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); + + testUser = new User(testMealStorage, testDrinkStorage, mealNutrientStorage, drinkNutrientStorage); + + testMealList = testUser.mealList; + testDrinkList = testUser.drinkList; + testExerciseList = testUser.exerciseList; + + Date currentDate = new Date(); + todayDate = currentDate.getDate(); + + testMealList.add(new Meal("kaya toast", 4, todayDate)); + testMealList.add(new Meal("laksa", 10, todayDate)); + testDrinkList.add(new Drink("kopi", 100, todayDate)); + testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH)); +// testExerciseList.add(new Exercise("running", 10, ExerciseIntensity.LOW)); + + System.setOut(new PrintStream(outputStream)); + } + + @Test + public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, + NegativeValueException { + String command = "eat m/kaya toast s/3"; + testUser.handleMeal(command); + + assertFalse(testMealList.isEmpty()); + + assertEquals("kaya toast", testMealList.get(2).getName()); + assertEquals(3, testMealList.get(2).getServingSize()); + } + + @Test + public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, + UnregisteredDrinkException, NegativeValueException { + String command = "drink d/kopi s/500"; + testUser.handleDrink(command); + + assertEquals("kopi", testDrinkList.get(1).getName()); + assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); + } + + @Test + public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { + testUser.handleViewCalories(); + String expectedOutput = "Total Calories: 5547"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } // // @Test // public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { // testUser.handleViewCarbohydrates(); -// String expectedOutput = "Total Carbohydrates: 830"; +// String expectedOutput = "Total Carbohydrates: 912"; // String actualOutput = outputStream.toString().trim(); // -// assertTrue(actualOutput.contains(expectedOutput)); +//// assertTrue(actualOutput.contains(expectedOutput)); +// assertEquals(expectedOutput, actualOutput); // } // // @Test @@ -147,163 +160,169 @@ // String expectedOutput = "Total Sugar: 88"; // String actualOutput = outputStream.toString().trim(); // -// assertTrue(actualOutput.contains(expectedOutput)); -// } -// -// @Test -// public void handleListMeals_emptyList_printListAccurate() { -// testMealList.clear(); -// testUser.handleListMeals(); -// -// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + -// " >> nothing so far :o"; -// String actualOutput = outputStream.toString().trim(); -// +//// assertTrue(actualOutput.contains(expectedOutput)); // assertEquals(expectedOutput, actualOutput); // } // -// @Test -// public void handleListMeals_validList_printListAccurate() { -// testUser.handleListMeals(); -// -// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + -// "1. pizza (serving size: 4)" + System.lineSeparator() + -// "2. chicken rice (serving size: 10)"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListDrinks_emptyList_printListAccurate() { -// testDrinkList.clear(); -// testUser.handleListDrinks(); -// -// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + -// " >> nothing so far :o"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// -// @Test -// public void handleListDrinks_validList_printListAccurate() { -// testUser.handleListDrinks(); -// -// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + -// "1. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + -// "Total water intake: 0 ml"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListEverything_bothEmptyLists_printListAccurate() { -// testMealList.clear(); -// testDrinkList.clear(); -// testUser.handleListEverything(); -// -// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + -// " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + -// "Total water intake: 0 ml"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListEverything_validList_printListAccurate() { -// testUser.handleListEverything(); -// -// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + -// "1. pizza (serving size: 4)" + System.lineSeparator() + -// "2. chicken rice (serving size: 10)" + System.lineSeparator() + -// "3. sprite (volume: 100ml)" + System.lineSeparator() + System.lineSeparator() + -// "Total water intake: 0 ml"; -// String actualOutput = outputStream.toString().trim(); -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException -// { -// Exception exception = assertThrows(InvalidListIndexException.class, () -> { -// String command = "editMeal 5 s/10"; -// testUser.handleEditMealServingSize(command); -// }); -// } -// -// @Test -// public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, -// NegativeValueException, IncompleteEditException { -// String command = "editMeal 2 s/100000000"; -// testUser.handleEditMealServingSize(command); -// -// int mealIndex = 2 - 1; -// assertEquals("chicken rice", testMealList.get(mealIndex).getName()); -// assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); -// } -// -// @Test -// public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, -// NegativeValueException, IncompleteEditException { -// String command = "editDrink 1 s/100000000"; -// testUser.handleEditDrinkServingSize(command); -// -// int drinkIndex = 1 - 1; -// assertEquals("sprite", testDrinkList.get(drinkIndex).getName()); -// assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); -// } -// -// @Test -// public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, -// IncompleteDeleteException { -// Exception exception = assertThrows(IncompleteDeleteException.class, () -> { -// String command = "deleteMeal "; -// testUser.handleDeleteMeal(command); -// }); -// } -// -// @Test -// public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, -// IncompleteDeleteException { -// Exception exception = assertThrows(NumberFormatException.class, () -> { -// String command = "deleteMeal "; -// testUser.handleDeleteMeal(command); -// }); -// } -// -// @Test -// public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, -// IncompleteDeleteException { -// String command = "deleteMeal 1"; -// testUser.handleDeleteMeal(command); -// assertEquals(1, testMealList.size()); -// assertEquals("chicken rice", testMealList.get(0).getName()); -// } -// -// @Test -// public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { -// Exception exception = assertThrows(InvalidListIndexException.class, () -> { -// String command = "deleteDrink 5"; -// testUser.handleDeleteDrink(command); -// }); -// } -// -// @Test -// public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, -// IncompleteDeleteException { -// String command = "deleteDrink 1"; -// testUser.handleDeleteDrink(command); -// assertEquals(0, testDrinkList.size()); -// } -// -// @Test -// public void handleClear_validCommand_clearListsSuccessful() { -// testUser.handleClear(); -// assertEquals(0, testMealList.size()); -// assertEquals(0, testDrinkList.size()); -// } -//} + @Test + public void handleListMealsToday_emptyList_printListAccurate() { + testMealList.clear(); + testUser.handleListMealsToday(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListMealsToday_validList_printListAccurate() { + testUser.handleListMealsToday(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate ; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListDrinksToday_emptyList_printListAccurate() { + testDrinkList.clear(); + testUser.handleListDrinksToday(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + + @Test + public void handleListDrinksToday_validList_printListAccurate() { + testUser.handleListDrinksToday(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake: 0 ml"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListEverythingToday_allEmptyLists_printListAccurate() { + testMealList.clear(); + testDrinkList.clear(); + testExerciseList.clear(); + testUser.handleListEverythingToday(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + + "Total water intake: 0 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListEverythingToday_validList_printListAccurate() { + testUser.handleListEverythingToday(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + + "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake: 0 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + "1. swimming | duration: 20 | intensity: HIGH"; + String actualOutput = outputStream.toString().trim(); + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException + { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "editMeal 5 s/10"; + testUser.handleEditMealServingSize(command); + }); + } + + @Test + public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + String command = "editMeal 2 s/100000000"; + testUser.handleEditMealServingSize(command); + + int mealIndex = 2 - 1; + assertEquals("laksa", testMealList.get(mealIndex).getName()); + assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); + } + + @Test + public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + String command = "editDrink 1 s/100000000"; + testUser.handleEditDrinkServingSize(command); + + int drinkIndex = 1 - 1; + assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); + assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); + } + + @Test + public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(IncompleteDeleteException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(NumberFormatException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteMeal 1"; + testUser.handleDeleteMeal(command); + assertEquals(1, testMealList.size()); + assertEquals("laksa", testMealList.get(0).getName()); + } + + @Test + public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "deleteDrink 5"; + testUser.handleDeleteDrink(command); + }); + } + + @Test + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteDrink 1"; + testUser.handleDeleteDrink(command); + assertEquals(0, testDrinkList.size()); + } + + @Test + public void handleClear_validCommand_clearListsSuccessful() { + testUser.handleClear(); + assertEquals(0, testMealList.size()); + assertEquals(0, testDrinkList.size()); + } +} From 1502e0c0402504e029582b71d0e09481ae2abb35 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 31 Mar 2024 17:04:36 +0800 Subject: [PATCH 115/274] Fix bugs on loadDrinkNutrient --- src/main/java/seedu/fitnus/user/User.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 35d88eb5a4..ff1c282abf 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -107,8 +107,8 @@ public void loadDrinkNutrient(Storage drinkNutrientStorage) { Parser.parseDrinkNutrient(s); String description = Parser.drinkNutrientDescription; int calories = Parser.drinkNutrientCalories; - int carbs = Parser.mealNutrientCarbs; - int sugar = Parser.mealNutrientSugar; + int carbs = Parser.drinkNutrientCarbs; + int sugar = Parser.drinkNutrientSugar; int protein = Parser.drinkNutrientProtein; int fat = Parser.drinkNutrientFat; Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); From e683d832fa01da173ef8bc9b1230654383dc752c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sun, 31 Mar 2024 17:35:05 +0800 Subject: [PATCH 116/274] Update userTest with correct calculations --- src/main/java/seedu/fitnus/user/User.java | 1 - src/test/java/seedu/fitnus/user/UserTest.java | 139 +++++++++--------- 2 files changed, 68 insertions(+), 72 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index a9f5dce941..310cd98620 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -29,7 +29,6 @@ public class User { protected static ArrayList drinkList; protected static ArrayList exerciseList; - public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index de4f1eb7dd..9aabd19aef 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -45,7 +45,7 @@ public class UserTest { private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @BeforeEach - public void setUp() throws UnregisteredExerciseException, NegativeValueException, IncompleteMealException, UnregisteredMealException { + public void setUp() throws UnregisteredExerciseException { testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); @@ -54,6 +54,7 @@ public void setUp() throws UnregisteredExerciseException, NegativeValueException testMealList = testUser.mealList; testDrinkList = testUser.drinkList; testExerciseList = testUser.exerciseList; + Water.editWaterIntake(0); Date currentDate = new Date(); todayDate = currentDate.getDate(); @@ -62,7 +63,6 @@ public void setUp() throws UnregisteredExerciseException, NegativeValueException testMealList.add(new Meal("laksa", 10, todayDate)); testDrinkList.add(new Drink("kopi", 100, todayDate)); testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH)); -// testExerciseList.add(new Exercise("running", 10, ExerciseIntensity.LOW)); System.setOut(new PrintStream(outputStream)); } @@ -97,73 +97,71 @@ public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() assertTrue(actualOutput.contains(expectedOutput)); } -// -// @Test -// public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { -// testUser.handleViewCarbohydrates(); -// String expectedOutput = "Total Carbohydrates: 912"; -// String actualOutput = outputStream.toString().trim(); -// -//// assertTrue(actualOutput.contains(expectedOutput)); -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewProteins(); -// String expectedOutput = "Total Proteins: 400"; -// String actualOutput = outputStream.toString().trim(); -// -// assertTrue(actualOutput.contains(expectedOutput)); -// } -// -// @Test -// public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { -// Water.checkInstance(500, "28-04-2024"); -// -// testUser.handleViewWaterIntake(); -// String expectedOutput = "Total water intake: 500"; -// String actualOutput = outputStream.toString().trim(); -// -// assertTrue(actualOutput.contains(expectedOutput)); -// } -// -// @Test -// public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewFiber(); -// String expectedOutput = "Total Fiber: 220"; -// String actualOutput = outputStream.toString().trim(); -// -// assertTrue(actualOutput.contains(expectedOutput)); -// } -// -// @Test -// public void handleViewFat_correctFatCalculation_viewFatAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewFat(); -// String expectedOutput = "Total Fat: 302"; -// String actualOutput = outputStream.toString().trim(); -// -// assertTrue(actualOutput.contains(expectedOutput)); -// } -// -// @Test -// public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewSugar(); -// String expectedOutput = "Total Sugar: 88"; -// String actualOutput = outputStream.toString().trim(); -// -//// assertTrue(actualOutput.contains(expectedOutput)); -// assertEquals(expectedOutput, actualOutput); -// } -// + + @Test + public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { + testUser.handleViewCarbohydrates(); + String expectedOutput = "Total Carbohydrates: 912"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewProteins(); + String expectedOutput = "Total Proteins: 215"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { + Water.checkInstance(500, "28-04-2024"); + + testUser.handleViewWaterIntake(); + String expectedOutput = "Total water intake: 500"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFiber(); + String expectedOutput = "Total Fiber: 80"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewFat_correctFatCalculation_viewFatAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFat(); + String expectedOutput = "Total Fat: 129"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + + @Test + public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewSugar(); + String expectedOutput = "Total Sugar: 106"; + String actualOutput = outputStream.toString().trim(); + + assertTrue(actualOutput.contains(expectedOutput)); + } + @Test public void handleListMealsToday_emptyList_printListAccurate() { testMealList.clear(); @@ -246,8 +244,7 @@ public void handleListEverythingToday_validList_printListAccurate() { } @Test - public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException - { + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { Exception exception = assertThrows(InvalidListIndexException.class, () -> { String command = "editMeal 5 s/10"; testUser.handleEditMealServingSize(command); From b1c5e5dbd314df36c09e092cda77efce4067f2a8 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 1 Apr 2024 04:09:15 +1300 Subject: [PATCH 117/274] Edit Water.java class to enable date input ...remove checkInstance method --- src/main/java/seedu/fitnus/Date.java | 4 +- src/main/java/seedu/fitnus/Water.java | 33 ++++----------- src/main/java/seedu/fitnus/user/User.java | 40 +++++++++++++++---- src/test/java/seedu/fitnus/user/UserTest.java | 4 +- 4 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/main/java/seedu/fitnus/Date.java b/src/main/java/seedu/fitnus/Date.java index 2ae5d3a51f..2bcda9c786 100644 --- a/src/main/java/seedu/fitnus/Date.java +++ b/src/main/java/seedu/fitnus/Date.java @@ -4,7 +4,7 @@ public class Date { // reference: https://www.javatpoint.com/java-get-current-date - private static String currentDate; + private String currentDate; public Date() { long millis = System.currentTimeMillis(); @@ -16,7 +16,7 @@ public Date() { this.currentDate = formattedDate; } - public static String getDate() { + public String getDate() { return currentDate; } } diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/Water.java index a5abf8ed20..1c147443b3 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -1,9 +1,8 @@ package seedu.fitnus; public class Water { - private static Water instance = null; - private static int waterIntake = 0; - private static String dateAdded; + private int waterIntake; + private String dateAdded; /** * Constructs a Water object with the specified amount of water intake and date added. @@ -13,39 +12,23 @@ public class Water { */ public Water(int amount, String dateAdded) { assert amount > 0 : "Water volume must be greater than 0."; - waterIntake = amount; - Water.dateAdded = dateAdded; - } - - /** - * Checks the instance of the Water object, create a new Water object if it doesn't exist, - * else add water intake to the existing object. - * - * - * @param amount The amount of water intake. - * @param dateAdded The date when the water intake was added. - */ - public static void checkInstance(int amount, String dateAdded) { - if (instance == null) { - instance = new Water(amount, dateAdded); - } else { - addWaterIntake(amount); - } + this.waterIntake = amount; + this.dateAdded = dateAdded; } - public static int getWater() { + public int getWater() { return waterIntake; } - public static void addWaterIntake(int amount) { + public void addWaterIntake(int amount) { waterIntake += amount; } - public static void editWaterIntake(int amount) { + public void editWaterIntake(int amount) { waterIntake = amount; } - public static String getDate() { + public String getDate() { return dateAdded; } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 310cd98620..056d5662c7 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -27,12 +27,14 @@ public class User { protected static ArrayList mealList; protected static ArrayList drinkList; + protected static ArrayList waterList; protected static ArrayList exerciseList; public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); exerciseList = new ArrayList<>(); + waterList = new ArrayList<>(); loadMealNutrient(mealNutrientStorage); loadDrinkNutrient(drinkNutrientStorage); loadMeal(mealStorage); @@ -66,7 +68,7 @@ public void loadDrink(Storage drinkStorage) { String drinkDate = Parser.drinkStorageDate; int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { - Water.checkInstance(drinkSize, drinkDate); + waterList.add(new Water (drinkSize, drinkDate)); } else { drinkList.add(new Drink(drinkDescription, drinkSize, drinkDate)); } @@ -132,8 +134,10 @@ public void saveMeal(Storage mealStorage) { } public void saveDrink(Storage drinkStorage) { - String waterSavedData = "water" + "," + Water.getWater() + "," + Water.getDate(); - drinkStorage.appendTextContent(waterSavedData); + for (Water water : waterList) { + String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); + drinkStorage.appendTextContent(waterSavedData); + } for (Drink drink : drinkList) { String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); drinkStorage.appendTextContent(drinkSavedData); @@ -167,8 +171,17 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis Date currentDate = new Date(); + boolean waterExist = false; //Water intake for today does not exist flag if (drinkName.equals("water")) { - Water.checkInstance(servingSize, currentDate.getDate()); + for (Water water: waterList) { + if (currentDate.getDate().equals(water.getDate())) { + water.addWaterIntake(servingSize); + waterExist = true; + } + } + if (!waterExist) { + waterList.add(new Water(servingSize, currentDate.getDate())); + } } else { drinkList.add(new Drink(drinkName, servingSize, currentDate.getDate())); } @@ -213,7 +226,9 @@ public void handleViewProteins() { public void handleViewWaterIntake() { int waterIntake = 0; - waterIntake += Water.getWater(); + for (Water water: waterList) { + waterIntake += water.getWater(); + } System.out.println("Total water intake: " + waterIntake + " ml"); } @@ -327,7 +342,11 @@ public void handleListDrinksToday() { public void handleListDrinks() { System.out.println("here's what you have drank so far"); - if (drinkList.isEmpty() && Water.getWater() == 0) { + int totalWater = 0; + for (Water water : waterList) { + totalWater += water.getWater(); + } + if (drinkList.isEmpty() && totalWater == 0) { System.out.println(" >> nothing so far :o"); } else if (drinkList.isEmpty()) { System.out.println(" >> nothing so far :o"); @@ -417,7 +436,12 @@ public static void handleEditDrinkServingSize(String command) throws InvalidList public static void handleEditWaterIntake(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditWater(command); - Water.editWaterIntake(Parser.editWaterSize); + Date currentDate = new Date(); + for (Water water: waterList) { + if (water.getDate().equals(currentDate.getDate())) { + water.editWaterIntake(Parser.editWaterSize); + } + } System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } @@ -481,7 +505,7 @@ public void handleExercise(String command) throws IncompleteExerciseException, U public void handleClear() { mealList.clear(); drinkList.clear(); - Water.editWaterIntake(0); + waterList.clear(); exerciseList.clear(); assert mealList.isEmpty(): "clearing of meal list failed"; diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 9aabd19aef..845310d471 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -54,7 +54,7 @@ public void setUp() throws UnregisteredExerciseException { testMealList = testUser.mealList; testDrinkList = testUser.drinkList; testExerciseList = testUser.exerciseList; - Water.editWaterIntake(0); + //Water.editWaterIntake(0); Date currentDate = new Date(); todayDate = currentDate.getDate(); @@ -120,7 +120,7 @@ public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { @Test public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { - Water.checkInstance(500, "28-04-2024"); + new Water (500, "28-04-2024"); testUser.handleViewWaterIntake(); String expectedOutput = "Total water intake: 500"; From 2f4220ca204da08a83d666ceb806732277e080c3 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 1 Apr 2024 04:48:37 +1300 Subject: [PATCH 118/274] Edit UserTest.java with new Water.java class specifications --- src/test/java/seedu/fitnus/user/UserTest.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 845310d471..f6732162da 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -36,6 +36,7 @@ public class UserTest { String todayDate; ArrayList testMealList; ArrayList testDrinkList; + ArrayList testWaterList; ArrayList testExerciseList; private Storage testMealStorage; private Storage testDrinkStorage; @@ -54,7 +55,7 @@ public void setUp() throws UnregisteredExerciseException { testMealList = testUser.mealList; testDrinkList = testUser.drinkList; testExerciseList = testUser.exerciseList; - //Water.editWaterIntake(0); + testWaterList = testUser.waterList; Date currentDate = new Date(); todayDate = currentDate.getDate(); @@ -62,6 +63,7 @@ public void setUp() throws UnregisteredExerciseException { testMealList.add(new Meal("kaya toast", 4, todayDate)); testMealList.add(new Meal("laksa", 10, todayDate)); testDrinkList.add(new Drink("kopi", 100, todayDate)); + testWaterList.add(new Water( 100, todayDate)); testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH)); System.setOut(new PrintStream(outputStream)); @@ -120,12 +122,11 @@ public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { @Test public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { - new Water (500, "28-04-2024"); + testWaterList.add(new Water (500, "10-03-2024")); testUser.handleViewWaterIntake(); - String expectedOutput = "Total water intake: 500"; + String expectedOutput = "Total water intake: 600"; String actualOutput = outputStream.toString().trim(); - assertTrue(actualOutput.contains(expectedOutput)); } @@ -205,7 +206,7 @@ public void handleListDrinksToday_validList_printListAccurate() { String expectedOutput = "here's what you have drank today" + System.lineSeparator() + "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 0 ml"; + "Total water intake: 100 ml"; String actualOutput = outputStream.toString().trim(); assertEquals(expectedOutput, actualOutput); @@ -220,7 +221,7 @@ public void handleListEverythingToday_allEmptyLists_printListAccurate() { String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 0 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "Total water intake: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + "here's the exercises you've done today" + System.lineSeparator() + " >> nothing so far :o"; String actualOutput = outputStream.toString().trim(); @@ -236,7 +237,7 @@ public void handleListEverythingToday_validList_printListAccurate() { "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 0 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "Total water intake: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + "here's the exercises you've done today" + System.lineSeparator() + "1. swimming | duration: 20 | intensity: HIGH"; String actualOutput = outputStream.toString().trim(); From 4371fe90f221a7b5e6621a53c3862e19f956010c Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 1 Apr 2024 01:38:37 +0800 Subject: [PATCH 119/274] Edit Exercise.java class to enable date input ...also add store and load Exercise to ExerciseList.txt --- data/ExerciseList.txt | 2 + src/main/java/seedu/fitnus/Exercise.java | 9 +++- src/main/java/seedu/fitnus/Ui.java | 4 +- src/main/java/seedu/fitnus/parser/Parser.java | 14 ++++++ src/main/java/seedu/fitnus/user/User.java | 43 ++++++++++++++++++- src/test/java/seedu/fitnus/user/UserTest.java | 7 ++- 6 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 data/ExerciseList.txt diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt new file mode 100644 index 0000000000..0b05f6234e --- /dev/null +++ b/data/ExerciseList.txt @@ -0,0 +1,2 @@ +swimming,100,HIGH,01-04-2024 +running,50,MEDIUM,01-04-2024 diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index 0571121912..2b0c510ce6 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -12,9 +12,11 @@ public class Exercise { private int duration; // Duration in minutes private ExerciseIntensity intensity; private int caloriesBurnt; + private String dateAdded; // Constructor with only duration and exercise name - public Exercise(String name, int duration, ExerciseIntensity intensity) throws UnregisteredExerciseException { + public Exercise(String name, int duration, ExerciseIntensity intensity, String currentDate) + throws UnregisteredExerciseException { assert name != null : "Name must not be null"; this.name = name; assert duration > 0 : "Duration must be greater than 0"; @@ -22,6 +24,7 @@ public Exercise(String name, int duration, ExerciseIntensity intensity) throws U assert isValidIntensity(intensity) : "Intensity must be HIGH, MEDIUM, or LOW"; this.intensity = intensity; setCaloriesBurnt(); // Assign exercise details based on the name and intensity + this.dateAdded = currentDate; } // Add exercise details to the static HashMap @@ -58,6 +61,10 @@ public ExerciseIntensity getIntensity() { return intensity; } + public String getDate() { + return dateAdded; + } + // Setter method for name public void setName(String name) { this.name = name; diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 3dd4d47be1..5309d29807 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -14,9 +14,10 @@ public class Ui { private Storage mealStorage = new Storage("./data", "./data/MealList.txt"); private Storage drinkStorage = new Storage("./data", "./data/DrinkList.txt"); + private Storage exerciseStorage = new Storage ("./data", "./data/ExerciseList.txt"); private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); - private User user = new User(mealStorage, drinkStorage, mealNutrientStorage, drinkNutrientStorage); + private User user = new User(mealStorage, drinkStorage, mealNutrientStorage, drinkNutrientStorage, exerciseStorage); private Parser parser = new Parser(user); /** Prints the welcome message upon the start of the application */ @@ -36,6 +37,7 @@ public void handleExit() { isExit = true; user.saveMeal(mealStorage); user.saveDrink(drinkStorage); + user.saveExercise(exerciseStorage); } public static void showLine() { diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 6501e08c6a..70d201d010 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -44,6 +44,11 @@ public class Parser { public static int drinkStorageSize; public static String drinkStorageDate; + public static String exerciseStorageDescription; + public static int exerciseStorageDuration; + public static ExerciseIntensity exerciseStorageIntensity; + public static String exerciseStorageDate; + public static String exerciseDescription; public static int exerciseDuration; @@ -330,6 +335,15 @@ public static void parseDrinkStorage(String data) { drinkStorageDate = arrayOfDrinkData[2]; } + public static void parseExerciseStorage(String data) { + String delimiter = ","; + String[] arrayOfExerciseData = data.split(delimiter); + exerciseStorageDescription = arrayOfExerciseData[0]; + exerciseStorageDuration = Integer.parseInt(arrayOfExerciseData[1]); + exerciseStorageIntensity = ExerciseIntensity.valueOf(arrayOfExerciseData[2]); + exerciseStorageDate = arrayOfExerciseData[3]; + } + public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, NegativeValueException { if (!command.contains("e/") || !command.contains("d/") || !command.contains("i/")) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 056d5662c7..70ed74e484 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -30,7 +30,8 @@ public class User { protected static ArrayList waterList; protected static ArrayList exerciseList; - public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage) { + public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage, + Storage exerciseStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); exerciseList = new ArrayList<>(); @@ -39,6 +40,7 @@ public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStora loadDrinkNutrient(drinkNutrientStorage); loadMeal(mealStorage); loadDrink(drinkStorage); + loadExercise(exerciseStorage); } public void loadMeal(Storage mealStorage) { @@ -79,6 +81,28 @@ public void loadDrink(Storage drinkStorage) { } } + public void loadExercise(Storage exerciseStorage) { + try { + ArrayList exerciseStorageList = exerciseStorage.readFile(); + if (!exerciseStorageList.isEmpty()) { + for (String s : exerciseStorageList) { + Parser.parseExerciseStorage(s); + String exerciseDescription = Parser.exerciseStorageDescription; + int exerciseDuration = Parser.exerciseStorageDuration; + ExerciseIntensity exerciseIntensity = Parser.exerciseStorageIntensity; + String currentDate = Parser.exerciseStorageDate; + exerciseList.add(new Exercise(exerciseDescription, exerciseDuration, exerciseIntensity, + currentDate)); + } + } + } catch (FileNotFoundException e) { + exerciseStorage.createFile(); + } catch (UnregisteredExerciseException e) { + System.out.println("Sorry that meal is not registered in the database. Please check the spelling and " + + "try again"); + } + } + public void loadMealNutrient(Storage mealNutrientStorage) { try { ArrayList mealNutrientList = mealNutrientStorage.readFile(); @@ -149,6 +173,20 @@ public void saveDrink(Storage drinkStorage) { } } + public void saveExercise(Storage exerciseStorage) { + for (Exercise exercise : exerciseList) { + String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," + + exercise.getIntensity() + "," + exercise.getDate(); + exerciseStorage.appendTextContent(exerciseSavedData); + } + try { + exerciseStorage.writeFile(exerciseStorage.textContent); + } catch (IOException e) { + System.out.println("Failed saving drink: " + e.getMessage()); + } + } + + public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, NegativeValueException { Parser.parseMeal(command); @@ -496,7 +534,8 @@ public void handleExercise(String command) throws IncompleteExerciseException, U String exerciseType = Parser.exerciseDescription; int duration = Parser.exerciseDuration; ExerciseIntensity intensity = Parser.exerciseIntensity; - exerciseList.add(new Exercise(exerciseType, duration, intensity)); + Date currentDate = new Date(); + exerciseList.add(new Exercise(exerciseType, duration, intensity, currentDate.getDate())); assert !exerciseList.isEmpty(): "failed to track exercise"; System.out.println("Tracked " + duration + " minutes of " + exerciseType); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index f6732162da..5d13a51d04 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -40,6 +40,7 @@ public class UserTest { ArrayList testExerciseList; private Storage testMealStorage; private Storage testDrinkStorage; + private Storage testExerciseStorage; private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); @@ -49,8 +50,10 @@ public class UserTest { public void setUp() throws UnregisteredExerciseException { testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); + testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); - testUser = new User(testMealStorage, testDrinkStorage, mealNutrientStorage, drinkNutrientStorage); + testUser = new User(testMealStorage, testDrinkStorage, mealNutrientStorage, drinkNutrientStorage, + testExerciseStorage); testMealList = testUser.mealList; testDrinkList = testUser.drinkList; @@ -64,7 +67,7 @@ public void setUp() throws UnregisteredExerciseException { testMealList.add(new Meal("laksa", 10, todayDate)); testDrinkList.add(new Drink("kopi", 100, todayDate)); testWaterList.add(new Water( 100, todayDate)); - testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH)); + testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH, "30-01-2024")); System.setOut(new PrintStream(outputStream)); } From 192158bb0e79f1ac4cfbeb80975cee0c90e699b7 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 1 Apr 2024 14:19:43 +0800 Subject: [PATCH 120/274] Add list all dates feature Add listMealsAll, listDrinksAll, listExercisesAll, listEverythingAll --- data/ExerciseList.txt | 3 + src/main/java/seedu/fitnus/parser/Parser.java | 14 +- src/main/java/seedu/fitnus/user/User.java | 168 ++++++++++++------ src/test/java/seedu/fitnus/user/UserTest.java | 37 ++-- src/test/resources/ExerciseList.txt | 0 5 files changed, 141 insertions(+), 81 deletions(-) create mode 100644 src/test/resources/ExerciseList.txt diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt index 0b05f6234e..713ea1e2a6 100644 --- a/data/ExerciseList.txt +++ b/data/ExerciseList.txt @@ -1,2 +1,5 @@ +cycling,100,LOW,29-02-2024 swimming,100,HIGH,01-04-2024 running,50,MEDIUM,01-04-2024 +cycling,100,LOW,01-04-2024 +running,20,HIGH,01-04-2024 diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 70d201d010..6767adac3d 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -108,18 +108,20 @@ public void handleCommand(String command) { user.handleViewFiber(); } else if (command.equals("listMeals")) { user.handleListMeals(); - } else if (command.equals("listMealsToday")) { - user.handleListMealsToday(); + } else if (command.equals("listMealsAll")) { + user.handleListMealsAll(); } else if (command.equals("listDrinks")) { user.handleListDrinks(); - } else if (command.equals("listDrinksToday")) { - user.handleListDrinksToday(); + } else if (command.equals("listDrinksAll")) { + user.handleListDrinksAll(); } else if (command.equals("listExercises")) { user.handleListExercises(); + } else if (command.equals("listExercisesAll")) { + user.handleListExercisesAll(); } else if (command.equals("listEverything")) { user.handleListEverything(); - } else if (command.equals("listEverythingToday")) { - user.handleListEverythingToday(); + } else if (command.equals("listEverythingAll")) { + user.handleListEverythingAll(); } else if (command.startsWith("editMeal")) { User.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 70ed74e484..2910d976e6 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -25,10 +25,16 @@ import java.util.ArrayList; public class User { + // list for today protected static ArrayList mealList; protected static ArrayList drinkList; protected static ArrayList waterList; protected static ArrayList exerciseList; + // list for all dates except today + protected static ArrayList mealListAll; + protected static ArrayList drinkListAll; + protected static ArrayList waterListAll; + protected static ArrayList exerciseListAll; public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage, Storage exerciseStorage) { @@ -36,6 +42,10 @@ public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStora drinkList = new ArrayList<>(); exerciseList = new ArrayList<>(); waterList = new ArrayList<>(); + mealListAll = new ArrayList<>(); + drinkListAll = new ArrayList<>(); + exerciseListAll = new ArrayList<>(); + waterListAll = new ArrayList<>(); loadMealNutrient(mealNutrientStorage); loadDrinkNutrient(drinkNutrientStorage); loadMeal(mealStorage); @@ -52,9 +62,17 @@ public void loadMeal(Storage mealStorage) { String mealDescription = Parser.mealStorageDescription; int mealSize = Parser.mealStorageSize; String currentDate = Parser.mealStorageDate; - mealList.add(new Meal(mealDescription, mealSize, currentDate)); + mealListAll.add(new Meal(mealDescription, mealSize, currentDate)); } } + Date currentDate = new Date(); + String todayDate = currentDate.getDate(); + for (Meal m : mealListAll) { + if (m.getDate().equals(todayDate)) { + mealList.add(m); + } + } + mealListAll.removeAll(mealList); } catch (FileNotFoundException e) { mealStorage.createFile(); } @@ -70,12 +88,26 @@ public void loadDrink(Storage drinkStorage) { String drinkDate = Parser.drinkStorageDate; int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { - waterList.add(new Water (drinkSize, drinkDate)); + waterListAll.add(new Water (drinkSize, drinkDate)); } else { - drinkList.add(new Drink(drinkDescription, drinkSize, drinkDate)); + drinkListAll.add(new Drink(drinkDescription, drinkSize, drinkDate)); } } } + Date currentDate = new Date(); + String todayDate = currentDate.getDate(); + for (Drink d : drinkListAll) { + if (d.getDate().equals(todayDate)) { + drinkList.add(d); + } + } + drinkListAll.removeAll(drinkList); + for (Water w : waterListAll) { + if (w.getDate().equals(todayDate)) { + waterList.add(w); + } + } + waterListAll.removeAll(waterList); } catch (FileNotFoundException e) { drinkStorage.createFile(); } @@ -91,10 +123,18 @@ public void loadExercise(Storage exerciseStorage) { int exerciseDuration = Parser.exerciseStorageDuration; ExerciseIntensity exerciseIntensity = Parser.exerciseStorageIntensity; String currentDate = Parser.exerciseStorageDate; - exerciseList.add(new Exercise(exerciseDescription, exerciseDuration, exerciseIntensity, + exerciseListAll.add(new Exercise(exerciseDescription, exerciseDuration, exerciseIntensity, currentDate)); } } + Date currentDate = new Date(); + String todayDate = currentDate.getDate(); + for (Exercise e : exerciseListAll) { + if (e.getDate().equals(todayDate)) { + exerciseList.add(e); + } + } + exerciseListAll.removeAll(exerciseList); } catch (FileNotFoundException e) { exerciseStorage.createFile(); } catch (UnregisteredExerciseException e) { @@ -146,6 +186,10 @@ public void loadDrinkNutrient(Storage drinkNutrientStorage) { public void saveMeal(Storage mealStorage) { + for (Meal meal : mealListAll) { + String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); + mealStorage.appendTextContent(mealSavedData); + } for (Meal meal : mealList) { String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); mealStorage.appendTextContent(mealSavedData); @@ -158,10 +202,18 @@ public void saveMeal(Storage mealStorage) { } public void saveDrink(Storage drinkStorage) { + for (Water water : waterListAll) { + String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); + drinkStorage.appendTextContent(waterSavedData); + } for (Water water : waterList) { String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); drinkStorage.appendTextContent(waterSavedData); } + for (Drink drink : drinkListAll) { + String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); + drinkStorage.appendTextContent(drinkSavedData); + } for (Drink drink : drinkList) { String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); drinkStorage.appendTextContent(drinkSavedData); @@ -174,6 +226,11 @@ public void saveDrink(Storage drinkStorage) { } public void saveExercise(Storage exerciseStorage) { + for (Exercise exercise : exerciseListAll) { + String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," + + exercise.getIntensity() + "," + exercise.getDate(); + exerciseStorage.appendTextContent(exerciseSavedData); + } for (Exercise exercise : exerciseList) { String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," + exercise.getIntensity() + "," + exercise.getDate(); @@ -267,7 +324,7 @@ public void handleViewWaterIntake() { for (Water water: waterList) { waterIntake += water.getWater(); } - System.out.println("Total water intake: " + waterIntake + " ml"); + System.out.println("Total water intake today: " + waterIntake + " ml"); } public void handleViewFiber() { @@ -308,15 +365,16 @@ public void printMealList(int startIndex, ArrayList mealListToPrint) { } } - public void printExerciseList() { - for (int i = 0; i < exerciseList.size(); i++) { - Exercise currentExercise = exerciseList.get(i); + public void printExerciseList(ArrayList exerciseListToPrint) { + for (int i = 0; i < exerciseListToPrint.size(); i++) { + Exercise currentExercise = exerciseListToPrint.get(i); System.out.println((i+1) + ". " + currentExercise.getName() + " | duration: " + - currentExercise.getDuration() + " | intensity: " + currentExercise.getIntensity()); + currentExercise.getDuration() + " | intensity: " + currentExercise.getIntensity() + + " | date: " + currentExercise.getDate()); } } public void handleListMeals() { - System.out.println("here's what you have eaten so far"); + System.out.println("here's what you have eaten today"); if (mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { @@ -324,25 +382,13 @@ public void handleListMeals() { } } - public ArrayList getMealListToday() { - Date currentDate = new Date(); - ArrayList mealListToday = new ArrayList<>(); - for (Meal m : mealList) { - String todayDate = currentDate.getDate(); - if (m.getDate().equals(todayDate)) { - mealListToday.add(m); - } - } - return mealListToday; - } - - public void handleListMealsToday() { - ArrayList mealListToday = getMealListToday(); - System.out.println("here's what you have eaten today"); - if (mealListToday.isEmpty()) { + public void handleListMealsAll() { + System.out.println("here's what you have eaten so far"); + if (mealListAll.isEmpty() && mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { - printMealList(1, mealListToday); + printMealList(1, mealListAll); + printMealList(1 + mealListAll.size(), mealList); } } @@ -354,43 +400,38 @@ public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { } } - public ArrayList getDrinkListToday() { - Date currentDate = new Date(); - ArrayList drinkListToday = new ArrayList<>(); - for (Drink d : drinkList) { - String todayDate = currentDate.getDate(); - if (d.getDate().equals(todayDate)) { - drinkListToday.add(d); - } - } - return drinkListToday; - } - - public void handleListDrinksToday() { - ArrayList drinkListToday = getDrinkListToday(); + public void handleListDrinks() { System.out.println("here's what you have drank today"); - if (drinkListToday.isEmpty()) { + int totalWater = 0; + for (Water water : waterList) { + totalWater += water.getWater(); + } + if (drinkList.isEmpty() && totalWater == 0) { + System.out.println(" >> nothing so far :o"); + } else if (drinkList.isEmpty()) { System.out.println(" >> nothing so far :o"); + handleViewWaterIntake(); } else { - printDrinkList(1, drinkListToday); + printDrinkList(1, drinkList); System.out.println(); handleViewWaterIntake(); } } - public void handleListDrinks() { + public void handleListDrinksAll() { System.out.println("here's what you have drank so far"); int totalWater = 0; for (Water water : waterList) { totalWater += water.getWater(); } - if (drinkList.isEmpty() && totalWater == 0) { + if (drinkListAll.isEmpty() && drinkList.isEmpty() && totalWater == 0) { System.out.println(" >> nothing so far :o"); - } else if (drinkList.isEmpty()) { + } else if (drinkListAll.isEmpty() && drinkList.isEmpty()) { System.out.println(" >> nothing so far :o"); handleViewWaterIntake(); } else { - printDrinkList(1, drinkList); + printDrinkList(1, drinkListAll); + printDrinkList(1 + drinkListAll.size(), drinkList); System.out.println(); handleViewWaterIntake(); } @@ -401,12 +442,24 @@ public void handleListExercises() { if (exerciseList.isEmpty()) { System.out.println(" >> nothing so far :o"); } else { - printExerciseList(); + printExerciseList(exerciseList); + } + } + + public void handleListExercisesAll() { + System.out.println("here's the exercises you've done so far"); + if (exerciseListAll.isEmpty() && exerciseList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + ArrayList appendedExerciseList = new ArrayList<>(); + appendedExerciseList.addAll(exerciseListAll); + appendedExerciseList.addAll(exerciseList); + printExerciseList(appendedExerciseList); } } public void handleListEverything() { - System.out.println("here's what you have consumed so far"); + System.out.println("here's what you have consumed today"); if (drinkList.isEmpty() && mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); System.out.println(); @@ -422,25 +475,26 @@ public void handleListEverything() { handleListExercises(); } - public void handleListEverythingToday() { - ArrayList mealListToday = getMealListToday(); - ArrayList drinkListToday = getDrinkListToday(); - System.out.println("here's what you have consumed today"); - if (drinkListToday.isEmpty() && mealListToday.isEmpty()) { + public void handleListEverythingAll() { + System.out.println("here's what you have consumed so far"); + if (drinkListAll.isEmpty() && mealListAll.isEmpty() && drinkList.isEmpty() && mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); System.out.println(); handleViewWaterIntake(); } else { - printMealList(1, mealListToday); - printDrinkList(mealListToday.size()+1, drinkListToday); + printMealList(1, mealListAll); + printMealList(mealListAll.size() + 1, mealList); + printDrinkList(mealListAll.size() + mealList.size() + 1, drinkListAll); + printDrinkList(mealListAll.size() + mealList.size() + drinkListAll.size() + 1, drinkList); System.out.println(); handleViewWaterIntake(); } System.out.println(" ~~~"); - handleListExercises(); + handleListExercisesAll(); } + public static void handleEditMealServingSize(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 5d13a51d04..52f5e9cf43 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -125,10 +125,10 @@ public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { @Test public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { - testWaterList.add(new Water (500, "10-03-2024")); + testWaterList.add(new Water (500, todayDate)); testUser.handleViewWaterIntake(); - String expectedOutput = "Total water intake: 600"; + String expectedOutput = "Total water intake today: 600 ml"; String actualOutput = outputStream.toString().trim(); assertTrue(actualOutput.contains(expectedOutput)); } @@ -167,9 +167,9 @@ public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { } @Test - public void handleListMealsToday_emptyList_printListAccurate() { + public void handleListMeals_emptyList_printListAccurate() { testMealList.clear(); - testUser.handleListMealsToday(); + testUser.handleListMeals(); String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + " >> nothing so far :o"; @@ -179,8 +179,8 @@ public void handleListMealsToday_emptyList_printListAccurate() { } @Test - public void handleListMealsToday_validList_printListAccurate() { - testUser.handleListMealsToday(); + public void handleListMeals_validList_printListAccurate() { + testUser.handleListMeals(); String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + @@ -191,9 +191,10 @@ public void handleListMealsToday_validList_printListAccurate() { } @Test - public void handleListDrinksToday_emptyList_printListAccurate() { + public void handleListDrinks_emptyList_printListAccurate() { testDrinkList.clear(); - testUser.handleListDrinksToday(); + testWaterList.clear(); + testUser.handleListDrinks(); String expectedOutput = "here's what you have drank today" + System.lineSeparator() + " >> nothing so far :o"; @@ -204,27 +205,27 @@ public void handleListDrinksToday_emptyList_printListAccurate() { @Test - public void handleListDrinksToday_validList_printListAccurate() { - testUser.handleListDrinksToday(); + public void handleListDrinks_validList_printListAccurate() { + testUser.handleListDrinks(); String expectedOutput = "here's what you have drank today" + System.lineSeparator() + "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 100 ml"; + "Total water intake today: 100 ml"; String actualOutput = outputStream.toString().trim(); assertEquals(expectedOutput, actualOutput); } @Test - public void handleListEverythingToday_allEmptyLists_printListAccurate() { + public void handleListEverything_allEmptyLists_printListAccurate() { testMealList.clear(); testDrinkList.clear(); testExerciseList.clear(); - testUser.handleListEverythingToday(); + testUser.handleListEverything(); String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + "here's the exercises you've done today" + System.lineSeparator() + " >> nothing so far :o"; String actualOutput = outputStream.toString().trim(); @@ -233,16 +234,16 @@ public void handleListEverythingToday_allEmptyLists_printListAccurate() { } @Test - public void handleListEverythingToday_validList_printListAccurate() { - testUser.handleListEverythingToday(); + public void handleListEverything_validList_printListAccurate() { + testUser.handleListEverything(); String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + "here's the exercises you've done today" + System.lineSeparator() + - "1. swimming | duration: 20 | intensity: HIGH"; + "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; String actualOutput = outputStream.toString().trim(); assertEquals(expectedOutput, actualOutput); } diff --git a/src/test/resources/ExerciseList.txt b/src/test/resources/ExerciseList.txt new file mode 100644 index 0000000000..e69de29bb2 From 30bca89043e4c523a51c768d0f5b405c944cc4d6 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 1 Apr 2024 14:43:11 +0800 Subject: [PATCH 121/274] Add Exercise calories database --- data/ExerciseList.txt | 1 + db/Exercise_db.csv | 1 + src/main/java/seedu/fitnus/Exercise.java | 2 +- src/main/java/seedu/fitnus/Ui.java | 4 +++- src/main/java/seedu/fitnus/parser/Parser.java | 14 ++++++++++++ src/main/java/seedu/fitnus/user/User.java | 22 +++++++++++++++++-- src/test/java/seedu/fitnus/user/UserTest.java | 5 +++-- 7 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 db/Exercise_db.csv diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt index 713ea1e2a6..2e4733a33d 100644 --- a/data/ExerciseList.txt +++ b/data/ExerciseList.txt @@ -3,3 +3,4 @@ swimming,100,HIGH,01-04-2024 running,50,MEDIUM,01-04-2024 cycling,100,LOW,01-04-2024 running,20,HIGH,01-04-2024 +boxing,10,LOW,01-04-2024 diff --git a/db/Exercise_db.csv b/db/Exercise_db.csv new file mode 100644 index 0000000000..2978260733 --- /dev/null +++ b/db/Exercise_db.csv @@ -0,0 +1 @@ +boxing,15,10,5 \ No newline at end of file diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index 2b0c510ce6..c39216470f 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -7,7 +7,7 @@ import java.util.HashMap; public class Exercise { - private static HashMap exerciseDetails = new HashMap<>(); + public static HashMap exerciseDetails = new HashMap<>(); private String name; private int duration; // Duration in minutes private ExerciseIntensity intensity; diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 5309d29807..9bc76c5c3b 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -17,7 +17,9 @@ public class Ui { private Storage exerciseStorage = new Storage ("./data", "./data/ExerciseList.txt"); private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); - private User user = new User(mealStorage, drinkStorage, mealNutrientStorage, drinkNutrientStorage, exerciseStorage); + private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); + private User user = new User(mealStorage, drinkStorage, exerciseStorage, + mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); private Parser parser = new Parser(user); /** Prints the welcome message upon the start of the application */ diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 6767adac3d..4c89d29b64 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -67,6 +67,11 @@ public class Parser { public static int drinkNutrientProtein; public static int drinkNutrientFat; + public static String exerciseCaloriesDescription; + public static int exerciseCaloriesHigh; + public static int exerciseCaloriesMedium; + public static int exerciseCaloriesLow; + public static ExerciseIntensity exerciseIntensity; private User user; @@ -398,4 +403,13 @@ public static void parseDrinkNutrient(String data) { drinkNutrientProtein = Integer.parseInt(arrayOfDrinkNutrient[4]); drinkNutrientFat = Integer.parseInt(arrayOfDrinkNutrient[5]); } + + public static void parseExerciseCalories(String data) { + String delimiter = ","; + String[] arrayOfExerciseCalories = data.split(delimiter); + exerciseCaloriesDescription = arrayOfExerciseCalories[0].trim().toLowerCase(); + exerciseCaloriesHigh = Integer.parseInt(arrayOfExerciseCalories[1]); + exerciseCaloriesMedium = Integer.parseInt(arrayOfExerciseCalories[2]); + exerciseCaloriesLow = Integer.parseInt(arrayOfExerciseCalories[3]); + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 2910d976e6..97f714f80b 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -36,8 +36,8 @@ public class User { protected static ArrayList waterListAll; protected static ArrayList exerciseListAll; - public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage, - Storage exerciseStorage) { + public User(Storage mealStorage, Storage drinkStorage, Storage exerciseStorage, + Storage mealNutrientStorage, Storage drinkNutrientStorage, Storage exerciseCaloriesStorage) { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); exerciseList = new ArrayList<>(); @@ -48,6 +48,7 @@ public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStora waterListAll = new ArrayList<>(); loadMealNutrient(mealNutrientStorage); loadDrinkNutrient(drinkNutrientStorage); + loadExerciseCalories(exerciseCaloriesStorage); loadMeal(mealStorage); loadDrink(drinkStorage); loadExercise(exerciseStorage); @@ -184,6 +185,23 @@ public void loadDrinkNutrient(Storage drinkNutrientStorage) { } } + public void loadExerciseCalories(Storage exerciseCaloriesStorage) { + try { + ArrayList exerciseCaloriesList = exerciseCaloriesStorage.readFile(); + if (!exerciseCaloriesList.isEmpty()) { + for (String s : exerciseCaloriesList) { + Parser.parseExerciseCalories(s); + String description = Parser.exerciseCaloriesDescription; + int caloriesHigh = Parser.exerciseCaloriesHigh; + int caloriesMedium = Parser.exerciseCaloriesMedium; + int caloriesLow = Parser.exerciseCaloriesLow; + Exercise.exerciseDetails.put(description, new int[]{caloriesHigh, caloriesMedium, caloriesLow}); + } + } + } catch (FileNotFoundException e) { + System.out.println("Exercise calories database not found"); + } + } public void saveMeal(Storage mealStorage) { for (Meal meal : mealListAll) { diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 52f5e9cf43..2681a9daf3 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -43,6 +43,7 @@ public class UserTest { private Storage testExerciseStorage; private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); + private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -52,8 +53,8 @@ public void setUp() throws UnregisteredExerciseException { testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); - testUser = new User(testMealStorage, testDrinkStorage, mealNutrientStorage, drinkNutrientStorage, - testExerciseStorage); + testUser = new User(testMealStorage, testDrinkStorage, testExerciseStorage, mealNutrientStorage, + drinkNutrientStorage, exerciseCaloriesStorage); testMealList = testUser.mealList; testDrinkList = testUser.drinkList; From 0f33eed92dd09fccb029679abc118ce893a072dc Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 1 Apr 2024 16:34:37 +0800 Subject: [PATCH 122/274] Update handleHelp --- src/main/java/seedu/fitnus/parser/Parser.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 4c89d29b64..d3b8856fd3 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -201,9 +201,12 @@ public static void handleHelp() { System.out.println("- View daily fiber consumed: fiber"); System.out.println("- View daily water consumption: viewWater"); System.out.println("- View daily calories burnt: caloriesBurnt"); - System.out.println("- List meal intake: listMeals"); - System.out.println("- List drink intake: listDrinks"); - System.out.println("- List exercises done: listExercises"); + System.out.println("- List today's meal intake: listMeals"); + System.out.println("- List today's drink intake: listDrinks"); + System.out.println("- List today's exercises done: listExercises"); + System.out.println("- List all meal intake: listMealsAll"); + System.out.println("- List all drink intake: listDrinksAll"); + System.out.println("- List all exercises done: listExercisesAll"); System.out.println("- List entire food intake for the day: listEverything"); System.out.println("- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE"); System.out.println("- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE"); @@ -262,7 +265,7 @@ public static String parseInfoMeal(String command) throws UnregisteredMealExcept if (command.length() < mealIndex + 1) { throw new IncompleteInfoException(); } - String infoMealDescription = command.substring(mealIndex).trim(); + String infoMealDescription = command.substring(mealIndex).trim().toLowerCase(); if (!Meal.getNutrientDetails().containsKey(infoMealDescription)) { throw new UnregisteredMealException(); @@ -276,7 +279,7 @@ public static String parseInfoExercise(String command) throws UnregisteredExerci if (command.length() < exerciseIndex + 1) { throw new IncompleteInfoException(); } - String infoExerciseDescription = command.substring(exerciseIndex).trim(); + String infoExerciseDescription = command.substring(exerciseIndex).trim().toLowerCase(); if (!Exercise.getExerciseDetails().containsKey(infoExerciseDescription)) { throw new UnregisteredExerciseException(); } @@ -288,7 +291,7 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce if (command.length() < drinkIndex + 1) { throw new IncompleteInfoException(); } - String infoDrinkDescription = command.substring(drinkIndex).trim(); + String infoDrinkDescription = command.substring(drinkIndex).trim().toLowerCase(); if (!Drink.getNutrientDetails().containsKey(infoDrinkDescription)) { throw new UnregisteredDrinkException(); } From 45576c4fecbdd129e7e3bc493d73f4d5d67dfc62 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 1 Apr 2024 16:55:08 +0800 Subject: [PATCH 123/274] Add listMeals for certain date --- src/main/java/seedu/fitnus/Date.java | 23 +++++++++++++ .../exception/InvalidDateException.java | 4 +++ src/main/java/seedu/fitnus/parser/Parser.java | 33 +++++++++---------- src/main/java/seedu/fitnus/user/User.java | 28 +++++++++------- 4 files changed, 60 insertions(+), 28 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/InvalidDateException.java diff --git a/src/main/java/seedu/fitnus/Date.java b/src/main/java/seedu/fitnus/Date.java index 2bcda9c786..1a8d600063 100644 --- a/src/main/java/seedu/fitnus/Date.java +++ b/src/main/java/seedu/fitnus/Date.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import java.text.ParseException; import java.text.SimpleDateFormat; public class Date { @@ -19,4 +20,26 @@ public Date() { public String getDate() { return currentDate; } + + public static boolean isValidDate(String date) { + SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); + dateFormat.setLenient(false); + try { + java.util.Date javaDate = dateFormat.parse(date); + } catch (ParseException e) { + return false; + } + String[] arrayOfDates = date.split("-"); + int day = Integer.parseInt(arrayOfDates[0]); + int month = Integer.parseInt(arrayOfDates[1]); + int year = Integer.parseInt(arrayOfDates[2]); + if (day < 1 || month < 1 || month > 12 || year < 0) { + return false; + } + int[] dayInMonth = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if (day > dayInMonth[month - 1]) { + return false; + } + return true; + } } diff --git a/src/main/java/seedu/fitnus/exception/InvalidDateException.java b/src/main/java/seedu/fitnus/exception/InvalidDateException.java new file mode 100644 index 0000000000..7315da5911 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/InvalidDateException.java @@ -0,0 +1,4 @@ +package seedu.fitnus.exception; + +public class InvalidDateException extends Exception{ +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index d3b8856fd3..f39cf51cc2 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,22 +1,8 @@ package seedu.fitnus.parser; -import seedu.fitnus.Drink; -import seedu.fitnus.Exercise; -import seedu.fitnus.ExerciseIntensity; -import seedu.fitnus.Meal; - -import seedu.fitnus.exception.IncompleteDeleteException; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.IncompleteExerciseException; -import seedu.fitnus.exception.IncompleteInfoException; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.InvalidCommandException; -import seedu.fitnus.exception.InvalidListIndexException; -import seedu.fitnus.exception.NegativeValueException; -import seedu.fitnus.exception.UnregisteredDrinkException; -import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.*; + +import seedu.fitnus.exception.*; import seedu.fitnus.user.User; import seedu.fitnus.validator.IntegerValidation; @@ -115,6 +101,8 @@ public void handleCommand(String command) { user.handleListMeals(); } else if (command.equals("listMealsAll")) { user.handleListMealsAll(); + } else if (command.startsWith("listMeals") && command.contains("d/")) { + user.handleListMealsDate(command); } else if (command.equals("listDrinks")) { user.handleListDrinks(); } else if (command.equals("listDrinksAll")) { @@ -180,6 +168,8 @@ public void handleCommand(String command) { "Type [help] to view the commands format."); } catch (NegativeValueException e) { System.out.println("Your serving size/exercise duration must be at least 0!"); + } catch (InvalidDateException e) { + System.out.println("Invalid date provided. Your date must be in the format of dd-MM-yyyy."); } } @@ -415,4 +405,13 @@ public static void parseExerciseCalories(String data) { exerciseCaloriesMedium = Integer.parseInt(arrayOfExerciseCalories[2]); exerciseCaloriesLow = Integer.parseInt(arrayOfExerciseCalories[3]); } + + public static String parseListDate(String command) throws InvalidDateException { + int indexOfDate = command.indexOf("d/") + 2; + String date = command.substring(indexOfDate); + if (Date.isValidDate(date)) { + return date; + } + throw new InvalidDateException(); + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 97f714f80b..6e435c0be1 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -5,21 +5,11 @@ import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; -import seedu.fitnus.exception.IncompleteDeleteException; -import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.*; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; import seedu.fitnus.storage.Storage; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteExerciseException; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.UnregisteredDrinkException; -import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.InvalidListIndexException; - import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; @@ -410,6 +400,22 @@ public void handleListMealsAll() { } } + public void handleListMealsDate(String command) throws InvalidDateException { + String date = Parser.parseListDate(command); + ArrayList mealListDate = new ArrayList<>(); + for (Meal m : mealListAll) { + if (m.getDate().equals(date)) { + mealListDate.add(m); + } + } + for (Meal m : mealList) { + if (m.getDate().equals(date)) { + mealListDate.add(m); + } + } + printMealList(1, mealListDate); + } + public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { for (int i = 0; i < drinkListToPrint.size(); i++) { Drink currentDrink = drinkListToPrint.get(i); From 0fb91e26e6d7d106b1ae7949d9dee78cb2168c1a Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 1 Apr 2024 17:18:21 +0800 Subject: [PATCH 124/274] Add all list handler for certain date Add listDrinksDate, listExercisesDate, listEverythingDate --- data/ExerciseList.txt | 8 +- src/main/java/seedu/fitnus/parser/Parser.java | 6 ++ src/main/java/seedu/fitnus/user/User.java | 88 ++++++++++++++++++- 3 files changed, 97 insertions(+), 5 deletions(-) diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt index 2e4733a33d..b59a7f81d2 100644 --- a/data/ExerciseList.txt +++ b/data/ExerciseList.txt @@ -1,6 +1,6 @@ cycling,100,LOW,29-02-2024 -swimming,100,HIGH,01-04-2024 -running,50,MEDIUM,01-04-2024 -cycling,100,LOW,01-04-2024 -running,20,HIGH,01-04-2024 +swimming,100,HIGH,30-03-2024 +running,50,MEDIUM,30-03-2024 +cycling,100,LOW,31-03-2024 +running,20,HIGH,31-03-2024 boxing,10,LOW,01-04-2024 diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index f39cf51cc2..739e1937dc 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -107,14 +107,20 @@ public void handleCommand(String command) { user.handleListDrinks(); } else if (command.equals("listDrinksAll")) { user.handleListDrinksAll(); + } else if (command.startsWith("listDrinks") && command.contains("d/")) { + user.handleListDrinksDate(command); } else if (command.equals("listExercises")) { user.handleListExercises(); } else if (command.equals("listExercisesAll")) { user.handleListExercisesAll(); + } else if (command.startsWith("listExercises") && command.contains("d/")) { + user.handleListExercisesDate(command); } else if (command.equals("listEverything")) { user.handleListEverything(); } else if (command.equals("listEverythingAll")) { user.handleListEverythingAll(); + } else if (command.startsWith("listEverything") && command.contains("d/")) { + user.handleListEverythingDate(command); } else if (command.startsWith("editMeal")) { User.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 6e435c0be1..942319fab6 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -413,7 +413,12 @@ public void handleListMealsDate(String command) throws InvalidDateException { mealListDate.add(m); } } - printMealList(1, mealListDate); + System.out.println("here's what you have eaten on " + date); + if (mealListDate.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printMealList(1, mealListDate); + } } public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { @@ -461,6 +466,27 @@ public void handleListDrinksAll() { } } + public void handleListDrinksDate(String command) throws InvalidDateException { + String date = Parser.parseListDate(command); + ArrayList drinkListDate = new ArrayList<>(); + for (Drink d : drinkListAll) { + if (d.getDate().equals(date)) { + drinkListDate.add(d); + } + } + for (Drink d : drinkList) { + if (d.getDate().equals(date)) { + drinkListDate.add(d); + } + } + System.out.println("here's what you have drank on " + date); + if (drinkListDate.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printDrinkList(1, drinkListDate); + } + } + public void handleListExercises() { System.out.println("here's the exercises you've done today"); if (exerciseList.isEmpty()) { @@ -482,6 +508,27 @@ public void handleListExercisesAll() { } } + public void handleListExercisesDate(String command) throws InvalidDateException { + String date = Parser.parseListDate(command); + ArrayList exercisesListDate = new ArrayList<>(); + for (Exercise e : exerciseListAll) { + if (e.getDate().equals(date)) { + exercisesListDate.add(e); + } + } + for (Exercise e : exerciseList) { + if (e.getDate().equals(date)) { + exercisesListDate.add(e); + } + } + System.out.println("here's the exercises you've done on " + date); + if (exercisesListDate.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printExerciseList(exercisesListDate); + } + } + public void handleListEverything() { System.out.println("here's what you have consumed today"); if (drinkList.isEmpty() && mealList.isEmpty()) { @@ -518,6 +565,45 @@ public void handleListEverythingAll() { handleListExercisesAll(); } + public void handleListEverythingDate(String command) throws InvalidDateException { + String date = Parser.parseListDate(command); + ArrayList mealListDate = new ArrayList<>(); + for (Meal m : mealListAll) { + if (m.getDate().equals(date)) { + mealListDate.add(m); + } + } + for (Meal m : mealList) { + if (m.getDate().equals(date)) { + mealListDate.add(m); + } + } + + ArrayList drinkListDate = new ArrayList<>(); + for (Drink d : drinkListAll) { + if (d.getDate().equals(date)) { + drinkListDate.add(d); + } + } + for (Drink d : drinkList) { + if (d.getDate().equals(date)) { + drinkListDate.add(d); + } + } + + System.out.println("here's what you have consumed on " + date); + if (mealListDate.isEmpty() && drinkListDate.isEmpty()) { + System.out.println(" >> nothing so far :o"); + System.out.println(); + } else { + printMealList(1, mealListDate); + printDrinkList(1 + mealListDate.size(), drinkListDate); + System.out.println(); + } + + System.out.println(" ~~~"); + handleListExercisesDate(command); + } public static void handleEditMealServingSize(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { From 079a8c22a32d8e8c462499ea876c8eb5daf2ccf3 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 1 Apr 2024 17:26:05 +0800 Subject: [PATCH 125/274] Fix checkstyle errors --- src/main/java/seedu/fitnus/parser/Parser.java | 29 ++++++++++++++++--- src/main/java/seedu/fitnus/user/User.java | 13 ++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 739e1937dc..12c495ee5e 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,8 +1,24 @@ package seedu.fitnus.parser; -import seedu.fitnus.*; - -import seedu.fitnus.exception.*; +import seedu.fitnus.Drink; +import seedu.fitnus.Exercise; +import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.Meal; +import seedu.fitnus.Date; + +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.IncompleteInfoException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidCommandException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.InvalidDateException; import seedu.fitnus.user.User; import seedu.fitnus.validator.IntegerValidation; @@ -200,10 +216,15 @@ public static void handleHelp() { System.out.println("- List today's meal intake: listMeals"); System.out.println("- List today's drink intake: listDrinks"); System.out.println("- List today's exercises done: listExercises"); + System.out.println("- List today's entire food intake and exercises: listEverything"); System.out.println("- List all meal intake: listMealsAll"); System.out.println("- List all drink intake: listDrinksAll"); System.out.println("- List all exercises done: listExercisesAll"); - System.out.println("- List entire food intake for the day: listEverything"); + System.out.println("- List all entire food intake and exercises: listEverythingAll"); + System.out.println("- List meal intake for certain date: listMeals d/dd-MM-yyyy"); + System.out.println("- List drink intake for certain date: listDrinks d/dd-MM-yyyy"); + System.out.println("- List exercises done for certain date: listExercises d/dd-MM-yyyy"); + System.out.println("- List entire food intake and exercises for certain date: listEverything d/dd-MM-yyyy"); System.out.println("- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE"); System.out.println("- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE"); System.out.println("- Edit total water intake after inserted: editWater s/TOTAL_WATER_INTAKE"); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 942319fab6..245eaacf40 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -5,11 +5,22 @@ import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; -import seedu.fitnus.exception.*; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; import seedu.fitnus.storage.Storage; +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.InvalidDateException; + import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; From 9cd2b73fdc03ebea6aa3537e00e25a99446d695e Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 1 Apr 2024 18:55:36 +0800 Subject: [PATCH 126/274] Add JUnit tests for exercise --- src/test/java/seedu/fitnus/user/UserTest.java | 306 ++++++++++++++++++ 1 file changed, 306 insertions(+) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index ac43b4b412..4055103e9c 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -5,17 +5,37 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; +<<<<<<< Updated upstream import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.IncompleteWaterException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.UnregisteredDrinkException; +======= + +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.storage.Storage; +>>>>>>> Stashed changes import java.util.ArrayList; import static org.junit.jupiter.api.Assertions.assertEquals; +<<<<<<< Updated upstream import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertTrue; +======= +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +>>>>>>> Stashed changes public class UserTest { ArrayList testMealList = new ArrayList<>(); @@ -49,6 +69,7 @@ public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWat } @Test +<<<<<<< Updated upstream public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, UnregisteredDrinkException { Drink newDrink = new Drink("sprite", 100); @@ -56,5 +77,290 @@ public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkEx assertEquals("sprite", testDrinkList.get(0).getName()); assertEquals(100, testDrinkList.get(0).getDrinkVolumeSize()); +======= + public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, + UnregisteredExerciseException, NegativeValueException { + String command = "exercise e/running d/30 i/HIGH"; + testUser.handleExercise(command); + + assertEquals("running", testExerciseList.get(1).getName()); + assertEquals(30, testExerciseList.get(1).getDuration()); + assertEquals(ExerciseIntensity.HIGH, testExerciseList.get(1).getIntensity()); + } + + @Test + public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { + testUser.handleViewCalories(); + String expectedOutput = "Total Calories: 5547"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { + testUser.handleViewCarbohydrates(); + String expectedOutput = "Total Carbohydrates: 912"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewProteins(); + String expectedOutput = "Total Proteins: 215"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { + testWaterList.add(new Water (500, todayDate)); + + testUser.handleViewWaterIntake(); + String expectedOutput = "Total water intake today: 600 ml"; + String actualOutput = outputStream.toString().trim(); + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFiber(); + String expectedOutput = "Total Fiber: 80"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewFat_correctFatCalculation_viewFatAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFat(); + String expectedOutput = "Total Fat: 129"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewSugar(); + String expectedOutput = "Total Sugar: 106"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { + testUser.handleCaloriesBurnt(); + String expectedOutput = "Total calories burnt: 200"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleListMeals_emptyList_printListAccurate() { + testMealList.clear(); + testUser.handleListMeals(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListMeals_validList_printListAccurate() { + testUser.handleListMeals(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate ; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListDrinks_emptyList_printListAccurate() { + testDrinkList.clear(); + testWaterList.clear(); + testUser.handleListDrinks(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + + @Test + public void handleListDrinks_validList_printListAccurate() { + testUser.handleListDrinks(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 100 ml"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListExercise_emptyList_printListAccurate() { + testExerciseList.clear(); + testUser.handleListExercises(); + + String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + + @Test + public void handleListExercise_validList_printListAccurate() { + testUser.handleListExercises(); + + String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + + "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListEverything_allEmptyLists_printListAccurate() { + testMealList.clear(); + testDrinkList.clear(); + testExerciseList.clear(); + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListEverything_validList_printListAccurate() { + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + + "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; + String actualOutput = outputStream.toString().trim(); + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "editMeal 5 s/10"; + testUser.handleEditMealServingSize(command); + }); + } + + @Test + public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + String command = "editMeal 2 s/100000000"; + testUser.handleEditMealServingSize(command); + + int mealIndex = 2 - 1; + assertEquals("laksa", testMealList.get(mealIndex).getName()); + assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); + } + + @Test + public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + String command = "editDrink 1 s/100000000"; + testUser.handleEditDrinkServingSize(command); + + int drinkIndex = 0; + assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); + assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); + } + + @Test + public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(IncompleteDeleteException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(NumberFormatException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteMeal 1"; + testUser.handleDeleteMeal(command); + assertEquals(1, testMealList.size()); + assertEquals("laksa", testMealList.get(0).getName()); + } + + @Test + public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "deleteDrink 5"; + testUser.handleDeleteDrink(command); + }); + } + + @Test + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteDrink 1"; + testUser.handleDeleteDrink(command); + assertEquals(0, testDrinkList.size()); + } + + @Test + public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteExercise 1"; + testUser.handleDeleteExercise(command); + assertEquals(0, testExerciseList.size()); + } + + @Test + public void handleClear_validCommand_clearListsSuccessful() { + testUser.handleClear(); + assertEquals(0, testMealList.size()); + assertEquals(0, testDrinkList.size()); +>>>>>>> Stashed changes } } From b68111cff7cc8861649bf3fb5fa3d004b98e9b69 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 1 Apr 2024 18:56:46 +0800 Subject: [PATCH 127/274] Revert "Add JUnit tests for exercise" This reverts commit 9cd2b73fdc03ebea6aa3537e00e25a99446d695e. --- src/test/java/seedu/fitnus/user/UserTest.java | 306 ------------------ 1 file changed, 306 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 4055103e9c..ac43b4b412 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -5,37 +5,17 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; -<<<<<<< Updated upstream import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.IncompleteWaterException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.UnregisteredDrinkException; -======= - -import seedu.fitnus.exception.IncompleteDeleteException; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.IncompleteExerciseException; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.InvalidListIndexException; -import seedu.fitnus.exception.NegativeValueException; -import seedu.fitnus.exception.UnregisteredDrinkException; -import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.storage.Storage; ->>>>>>> Stashed changes import java.util.ArrayList; import static org.junit.jupiter.api.Assertions.assertEquals; -<<<<<<< Updated upstream import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertTrue; -======= -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; ->>>>>>> Stashed changes public class UserTest { ArrayList testMealList = new ArrayList<>(); @@ -69,7 +49,6 @@ public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWat } @Test -<<<<<<< Updated upstream public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, UnregisteredDrinkException { Drink newDrink = new Drink("sprite", 100); @@ -77,290 +56,5 @@ public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkEx assertEquals("sprite", testDrinkList.get(0).getName()); assertEquals(100, testDrinkList.get(0).getDrinkVolumeSize()); -======= - public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, - UnregisteredExerciseException, NegativeValueException { - String command = "exercise e/running d/30 i/HIGH"; - testUser.handleExercise(command); - - assertEquals("running", testExerciseList.get(1).getName()); - assertEquals(30, testExerciseList.get(1).getDuration()); - assertEquals(ExerciseIntensity.HIGH, testExerciseList.get(1).getIntensity()); - } - - @Test - public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { - testUser.handleViewCalories(); - String expectedOutput = "Total Calories: 5547"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { - testUser.handleViewCarbohydrates(); - String expectedOutput = "Total Carbohydrates: 912"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewProteins(); - String expectedOutput = "Total Proteins: 215"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { - testWaterList.add(new Water (500, todayDate)); - - testUser.handleViewWaterIntake(); - String expectedOutput = "Total water intake today: 600 ml"; - String actualOutput = outputStream.toString().trim(); - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewFiber(); - String expectedOutput = "Total Fiber: 80"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewFat_correctFatCalculation_viewFatAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewFat(); - String expectedOutput = "Total Fat: 129"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewSugar(); - String expectedOutput = "Total Sugar: 106"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { - testUser.handleCaloriesBurnt(); - String expectedOutput = "Total calories burnt: 200"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleListMeals_emptyList_printListAccurate() { - testMealList.clear(); - testUser.handleListMeals(); - - String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListMeals_validList_printListAccurate() { - testUser.handleListMeals(); - - String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + - "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + - "2. laksa (serving size: 10) | date: " + todayDate ; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListDrinks_emptyList_printListAccurate() { - testDrinkList.clear(); - testWaterList.clear(); - testUser.handleListDrinks(); - - String expectedOutput = "here's what you have drank today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - - @Test - public void handleListDrinks_validList_printListAccurate() { - testUser.handleListDrinks(); - - String expectedOutput = "here's what you have drank today" + System.lineSeparator() + - "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake today: 100 ml"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListExercise_emptyList_printListAccurate() { - testExerciseList.clear(); - testUser.handleListExercises(); - - String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - - @Test - public void handleListExercise_validList_printListAccurate() { - testUser.handleListExercises(); - - String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + - "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListEverything_allEmptyLists_printListAccurate() { - testMealList.clear(); - testDrinkList.clear(); - testExerciseList.clear(); - testUser.handleListEverything(); - - String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + - " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + - "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + - "here's the exercises you've done today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListEverything_validList_printListAccurate() { - testUser.handleListEverything(); - - String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + - "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + - "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + - "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + - "here's the exercises you've done today" + System.lineSeparator() + - "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; - String actualOutput = outputStream.toString().trim(); - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { - Exception exception = assertThrows(InvalidListIndexException.class, () -> { - String command = "editMeal 5 s/10"; - testUser.handleEditMealServingSize(command); - }); - } - - @Test - public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - String command = "editMeal 2 s/100000000"; - testUser.handleEditMealServingSize(command); - - int mealIndex = 2 - 1; - assertEquals("laksa", testMealList.get(mealIndex).getName()); - assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); - } - - @Test - public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - String command = "editDrink 1 s/100000000"; - testUser.handleEditDrinkServingSize(command); - - int drinkIndex = 0; - assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); - assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); - } - - @Test - public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, - IncompleteDeleteException { - Exception exception = assertThrows(IncompleteDeleteException.class, () -> { - String command = "deleteMeal "; - testUser.handleDeleteMeal(command); - }); - } - - @Test - public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, - IncompleteDeleteException { - Exception exception = assertThrows(NumberFormatException.class, () -> { - String command = "deleteMeal "; - testUser.handleDeleteMeal(command); - }); - } - - @Test - public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, - IncompleteDeleteException { - String command = "deleteMeal 1"; - testUser.handleDeleteMeal(command); - assertEquals(1, testMealList.size()); - assertEquals("laksa", testMealList.get(0).getName()); - } - - @Test - public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { - Exception exception = assertThrows(InvalidListIndexException.class, () -> { - String command = "deleteDrink 5"; - testUser.handleDeleteDrink(command); - }); - } - - @Test - public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, - IncompleteDeleteException { - String command = "deleteDrink 1"; - testUser.handleDeleteDrink(command); - assertEquals(0, testDrinkList.size()); - } - - @Test - public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, - IncompleteDeleteException { - String command = "deleteExercise 1"; - testUser.handleDeleteExercise(command); - assertEquals(0, testExerciseList.size()); - } - - @Test - public void handleClear_validCommand_clearListsSuccessful() { - testUser.handleClear(); - assertEquals(0, testMealList.size()); - assertEquals(0, testDrinkList.size()); ->>>>>>> Stashed changes } } From cfc69ba1437f6e055ae8df5de404f8e86add8297 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 1 Apr 2024 18:58:47 +0800 Subject: [PATCH 128/274] Revert "Revert "Add JUnit tests for exercise"" This reverts commit b68111cff7cc8861649bf3fb5fa3d004b98e9b69. --- src/test/java/seedu/fitnus/user/UserTest.java | 306 ++++++++++++++++++ 1 file changed, 306 insertions(+) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index ac43b4b412..4055103e9c 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -5,17 +5,37 @@ import seedu.fitnus.Meal; import seedu.fitnus.Parser; import seedu.fitnus.Water; +<<<<<<< Updated upstream import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.IncompleteWaterException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.UnregisteredDrinkException; +======= + +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.storage.Storage; +>>>>>>> Stashed changes import java.util.ArrayList; import static org.junit.jupiter.api.Assertions.assertEquals; +<<<<<<< Updated upstream import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertTrue; +======= +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +>>>>>>> Stashed changes public class UserTest { ArrayList testMealList = new ArrayList<>(); @@ -49,6 +69,7 @@ public void handleWater_unknownServingSize_addWaterFailed() throws IncompleteWat } @Test +<<<<<<< Updated upstream public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkException, UnregisteredDrinkException { Drink newDrink = new Drink("sprite", 100); @@ -56,5 +77,290 @@ public void handleDrinks_validInputs_correctlyAddMeal() throws IncompleteDrinkEx assertEquals("sprite", testDrinkList.get(0).getName()); assertEquals(100, testDrinkList.get(0).getDrinkVolumeSize()); +======= + public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, + UnregisteredExerciseException, NegativeValueException { + String command = "exercise e/running d/30 i/HIGH"; + testUser.handleExercise(command); + + assertEquals("running", testExerciseList.get(1).getName()); + assertEquals(30, testExerciseList.get(1).getDuration()); + assertEquals(ExerciseIntensity.HIGH, testExerciseList.get(1).getIntensity()); + } + + @Test + public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { + testUser.handleViewCalories(); + String expectedOutput = "Total Calories: 5547"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { + testUser.handleViewCarbohydrates(); + String expectedOutput = "Total Carbohydrates: 912"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewProteins(); + String expectedOutput = "Total Proteins: 215"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { + testWaterList.add(new Water (500, todayDate)); + + testUser.handleViewWaterIntake(); + String expectedOutput = "Total water intake today: 600 ml"; + String actualOutput = outputStream.toString().trim(); + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFiber(); + String expectedOutput = "Total Fiber: 80"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewFat_correctFatCalculation_viewFatAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFat(); + String expectedOutput = "Total Fat: 129"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewSugar(); + String expectedOutput = "Total Sugar: 106"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { + testUser.handleCaloriesBurnt(); + String expectedOutput = "Total calories burnt: 200"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleListMeals_emptyList_printListAccurate() { + testMealList.clear(); + testUser.handleListMeals(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListMeals_validList_printListAccurate() { + testUser.handleListMeals(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate ; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListDrinks_emptyList_printListAccurate() { + testDrinkList.clear(); + testWaterList.clear(); + testUser.handleListDrinks(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + + @Test + public void handleListDrinks_validList_printListAccurate() { + testUser.handleListDrinks(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 100 ml"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListExercise_emptyList_printListAccurate() { + testExerciseList.clear(); + testUser.handleListExercises(); + + String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + + @Test + public void handleListExercise_validList_printListAccurate() { + testUser.handleListExercises(); + + String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + + "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListEverything_allEmptyLists_printListAccurate() { + testMealList.clear(); + testDrinkList.clear(); + testExerciseList.clear(); + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListEverything_validList_printListAccurate() { + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + + "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; + String actualOutput = outputStream.toString().trim(); + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "editMeal 5 s/10"; + testUser.handleEditMealServingSize(command); + }); + } + + @Test + public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + String command = "editMeal 2 s/100000000"; + testUser.handleEditMealServingSize(command); + + int mealIndex = 2 - 1; + assertEquals("laksa", testMealList.get(mealIndex).getName()); + assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); + } + + @Test + public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + String command = "editDrink 1 s/100000000"; + testUser.handleEditDrinkServingSize(command); + + int drinkIndex = 0; + assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); + assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); + } + + @Test + public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(IncompleteDeleteException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(NumberFormatException.class, () -> { + String command = "deleteMeal "; + testUser.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteMeal 1"; + testUser.handleDeleteMeal(command); + assertEquals(1, testMealList.size()); + assertEquals("laksa", testMealList.get(0).getName()); + } + + @Test + public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "deleteDrink 5"; + testUser.handleDeleteDrink(command); + }); + } + + @Test + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteDrink 1"; + testUser.handleDeleteDrink(command); + assertEquals(0, testDrinkList.size()); + } + + @Test + public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteExercise 1"; + testUser.handleDeleteExercise(command); + assertEquals(0, testExerciseList.size()); + } + + @Test + public void handleClear_validCommand_clearListsSuccessful() { + testUser.handleClear(); + assertEquals(0, testMealList.size()); + assertEquals(0, testDrinkList.size()); +>>>>>>> Stashed changes } } From 5555d52edcdadbd16d9a8c372df74cccc2197fb0 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 1 Apr 2024 20:54:08 +0800 Subject: [PATCH 129/274] Edit DG,UG and minor fixes minor fixes to Drink, Meal, Parser, User. Added exercises to exercises csv --- db/Exercise_db.csv | 16 +- docs/DeveloperGuide.md | 24 +- docs/UserGuide.md | 253 +++++++++++++----- src/main/java/seedu/fitnus/Drink.java | 1 - src/main/java/seedu/fitnus/Exercise.java | 9 - src/main/java/seedu/fitnus/Meal.java | 6 - src/main/java/seedu/fitnus/parser/Parser.java | 9 +- src/main/java/seedu/fitnus/user/User.java | 18 +- 8 files changed, 233 insertions(+), 103 deletions(-) diff --git a/db/Exercise_db.csv b/db/Exercise_db.csv index 2978260733..4db59301d7 100644 --- a/db/Exercise_db.csv +++ b/db/Exercise_db.csv @@ -1 +1,15 @@ -boxing,15,10,5 \ No newline at end of file +Running,14,10,7 +Swimming,12,8,5 +Cycling,10,7,4 +Skipping,16,12,8 +Weightlifting,7,5,3 +Yoga,5,3,2 +Rowing,13,9,6 +Boxing,15,11,7 +Badminton,14,10,6 +Soccer,15,11,8 +Basketball,16,12,8 +Tennis,14,10,7 +Volleyball,12,8,5 +Rugby,18,14,10 +Hiking,12,8,6 \ No newline at end of file diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b8771dc9c7..c721cc7fcd 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -19,12 +19,15 @@ ## Product scope ### Target user profile - -{Describe the target user profile} +- Have a need to manage their dietary intake and exercise routines effectively. +- Prefer desktop applications over other types of platforms. +- Can type quickly and prefer typing over mouse interactions. +- Are reasonably comfortable using command-line interface (CLI) applications. ### Value proposition -{Describe the value proposition: what problem does it solve?} +The fitness app aims to help users manage their dietary habits and exercise routines more efficiently compared to traditional GUI-driven apps. +By offering a streamlined interface optimized for keyboard input and CLI interactions, users can track their meals, drinks, and exercises swiftly, allowing them to focus more on their fitness goals and less on navigating through complex user interfaces. ## User Stories @@ -35,11 +38,22 @@ ## Non-Functional Requirements -{Give non-functional requirements} +1. Should work on any mainstream OS as long as it has Java 11 or above installed. +2. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. ## Glossary -* *glossary item* - Definition +* *meal* - Any food consumed. +* *drink* - Any beverage consumed. +* *exercise* - Any physical activity performed. +* *calories* - Measure of energy derived from food. +* *carbohydrates* - Macronutrient providing energy. +* *proteins* - Macronutrient essential for growth and repair. +* *fat* - Macronutrient important for energy storage and insulation. +* *sugar* - Simple carbohydrate often added to food for sweetness. +* *fiber* - Indigestible plant material aiding digestion. +* *water* - Essential liquid for hydration and bodily functions. + ## Instructions for manual testing diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 76473bbab9..dabe3c9455 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -48,12 +48,13 @@ Shows a list of all possible command inputs. **Format**: help **Sample Input**: help **Expected Output**: -here's all the valid commands i recognise: +here's all the valid commands I recognise: - Add a meal eaten: eat m/MEAL s/SERVING_SIZE -- Add a drink: drink d/DRINK s/SERVING_SIZE -- Add water: water s/SERVING_SIZE +- Add a drink: drink d/DRINK s/VOLUME(ML) +- Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, LOW) - Find the information about a certain meal: infoMeal MEAL - Find the information about a certain drink: infoDrink DRINK +- Find the information about a certain exercise: infoExercise EXERCISE - View daily calories consumed: calories - View daily carbohydrates consumed: carbs - View daily proteins consumed: protein @@ -61,13 +62,25 @@ here's all the valid commands i recognise: - View daily sugar consumed: sugar - View daily fiber consumed: fiber - View daily water consumption: viewWater -- List meal intake: listMeals -- List drink intake: listDrinks -- List entire food intake for the day: listEverything +- View daily calories burnt: caloriesBurnt +- List today's meal intake: listMeals +- List today's drink intake: listDrinks +- List today's exercises done: listExercises +- List today's entire food intake and exercises: listEverything +- List all meal intake: listMealsAll +- List all drink intake: listDrinksAll +- List all exercises done: listExercisesAll +- List all entire food intake and exercises: listEverythingAll +- List meal intake for certain date: listMeals d/dd-MM-yyyy +- List drink intake for certain date: listDrinks d/dd-MM-yyyy +- List exercises done for certain date: listExercises d/dd-MM-yyyy +- List entire food intake and exercises for certain date: listEverything d/dd-MM-yyyy - Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE - Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE +- Edit total water intake after inserted: editWater s/TOTAL_WATER_INTAKE - Delete certain meal entry: deleteMeal INDEX - Delete certain drink entry: deleteDrink INDEX +- Delete certain exercise entry: deleteExercise INDEX - Clear all entries: clear - Exit the app: exit @@ -76,19 +89,28 @@ here's all the valid commands i recognise: Adds a meal to the list of meals **Format**: eat m/MEAL s/SERVING_SIZE **Sample Input**: eat m/Chicken Rice s/1 -**Expected Output**: Added 1 serving of Chicken Rice +**Expected Output**: +~~~ +Added 1 serving of Chicken Rice +~~~ ### 1.2.2 Add a drink: `drink` Adds a drink to the list of drinks **Format**: drink d/DRINK s/SERVING_SIZE **Sample Input**: drink d/Lemon Tea s/100 -**Expected Output**: Added 100ml of Lemon Tea +**Expected Output**: +~~~ +Added 100ml of Lemon Tea +~~~ -### 1.2.3 Add water: `water` -Adds water (in ml) to the daily water intake count -**Format**: water s/SERVING_SIZE -**Sample Input**: water s/200 -**Expected Output**: Added 200ml of water +### 1.2.3 Add exercise: `exercise` +Adds exercise to the list of exercises done +**Format**: exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, +**Sample Input**: exercise e/swimming d/30 i/HIGH +**Expected Output**: +~~~ +Tracked 30 minutes of swimming +~~~ ## 1.3 For data retrieval ### 1.3.1 Find the information about a certain meal: `infoMeal` @@ -96,108 +118,203 @@ For the specified meal, display its nutritional content to the user **Format**: infoMeal MEAL **Sample Input**: infoMeal chicken rice **Expected Output**: -Meal: chicken rice (per serving) -Calories: 400 -Carbs: 50 -Protein: 30 -Fat: 20 -Fiber: 10 -Sugar: 5 +~~~ +Meal: chicken rice (per serving)` +Calories: 607 +Carbs: 75 +Protein: 25 +Fat: 23 +Fiber: 2 +Sugar: 10 +~~~ ### 1.3.2 Find the information about a certain drink: `infoDrink` For the inputed drink, display its nutritional content to the user **Format**: infoDrink DRINK **Sample input**: infoDrink sprite **Expected output**: -SPRITE (473 ml) -Calories: 194 kcal -Carbs: 50g -Protein: 0.2g -Fat: 0.1g +~~~ +Drink: sprite (100 ml) +Calories: 40 +Carbs: 50 +Sugar: 30 +Protein: 20 +Fat: 2 +~~~ -### 1.3.3 View daily calories consumed: `calories` +### 1.3.3 Find the information about a certain exercise: `infoExercise` +For the inputed exercise, display its calories burnt per minute for different intensities to the user +**Format**: infoExercise EXERCISE +**Sample input**: infoExercise swimming +**Expected output**: +~~~ +Exercise: swimming +~ Calories burnt for a 1 minute workout of ~ +HIGH intensity: 12 +MEDIUM intensity: 8 +LOW intensity: 5 +~~~ + +### 1.3.4 View daily calories consumed: `calories` Display current total calorie intake for the day **Format**: calories -**Expected output**: Total calories: 100 cal +**Expected output**: +~~~ +Total calories: 100 cal +~~~ -### 1.3.4 View daily carbohydrates consumed: `carbs` +### 1.3.5 View daily carbohydrates consumed: `carbs` Display current total carbohydrates intake for the day **Format**: carbs -**Expected output**: Total Carbohydrates: 150 grams +**Expected output**: +~~~ +Total Carbohydrates: 150 grams +~~~ -### 1.3.5 View daily proteins consumed: `protein` +### 1.3.6 View daily proteins consumed: `protein` Display current total protein intake for the day **Format**: protein -**Expected output**: Total proteins: 100 grams +**Expected output**: +~~~ +Total proteins: 100 grams +~~~ -### 1.3.6 View daily fat consumed: `fat` +### 1.3.7 View daily fat consumed: `fat` Display current total fat intake for the day **Format**: fat -**Expected output**: Total fat: 50 grams +**Expected output**: +~~~ +Total fat: 50 grams +~~~ -### 1.3.7 View daily sugar consumed: `sugar` +### 1.3.8 View daily sugar consumed: `sugar` Display current total sugar intake for the day **Format**: sugar -**Expected output**: Total sugar: 20 grams +**Expected output**: +~~~ +Total sugar: 20 grams +~~~ -### 1.3.8 View daily fiber consumed: `fiber` +### 1.3.9 View daily fiber consumed: `fiber` Display current total fiber intake (g) for the day **Format**: viewFiber -**Expected output**: Total fiber: 20 grams +**Expected output**: +~~~ +Total fiber: 20 grams +~~~ -### 1.3.9 View daily water consumption: `viewWater` +### 1.3.10 View daily water consumption: `viewWater` Display current total water intake (in ml) for the day **Format**: viewWater -**Expected output**: Total water intake: 0 ml +**Expected output**: +~~~ +Total water intake: 0 ml +~~~ + +### 1.3.11 View daily calories consumed: `caloriesBurnt` +Display current total calorie burnt for the day +**Format**: caloriesBurnt +**Expected output**: +~~~ +Total calories burnt: 70 +~~~ ## 1.4 For listing arrays ### 1.4.1 List all meal intake: `listMeals` -List all the meals user inputted so far +List all the meals user input today **Format**: listMeals -**Expected output**: -here's what you have eaten so far -1.pizza (serving size: 1) +**Expected output**: +~~~ +here's what you have eaten today +1. chicken rice (serving size: 1) | date: 01-04-2024 +~~~ -### 1.4.2 List today's meal intake: `listMealsToday` -List all the meals user inputted today -**Format**: listMealsToday -**Expected output**: -here's what you have eaten today -1.pizza (serving size: 1) +### 1.4.2 List all drink intake: `listDrinks` +List all the drinks user input today +**Format**: listDrinks +**Expected output**: +~~~ +here's what you have drank today +1. sprite (volume: 100ml) | date: 01-04-2024 -### 1.4.3 List all drink intake: `listDrinks` -List all the drinks user inputted so far +Total water intake today: 0 ml +~~~ + +### 1.4.3 List all drink intake: `listExercises` +List all the exercises user tracked today **Format**: listDrinks **Expected output**: -here's what you have drank so far -1.sprite (serving size: 1) -Total water intake: 0 ml +here's the exercises you've done today +~~~ +1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 +~~~ -### 1.4.4 List today's drink intake: `listDrinksToday` +### 1.4.4 List all drink intake: `listEverything` +List all the meals, drinks and exercises user tracked today +**Format**: listDrinks +**Expected output**: +~~~ +here's what you have consumed today +1. chicken rice (serving size: 1) | date: 01-04-2024 +2. sprite (volume: 100ml) | date: 01-04-2024 + +Total water intake today: 100 ml + ~~~ +here's the exercises you've done today +1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 +~~~ + +### 1.4.5 List today's meal intake: `listMealsAll` +List all the meals user input +**Format**: listMealsToday +**Expected output**: +~~~ +here's what you have eaten so far +1. mala (serving size: 2) | date: 30-03-2024 +2. chicken rice (serving size: 1) | date: 01-04-2024 +~~~ + +### 1.4.6 List today's drink intake: `listDrinksAll` List all the drinks user inputted today **Format**: listDrinksToday **Expected output**: -here's what you have drank today -1.sprite (serving size: 1) -Total water intake: 0 ml +~~~ +here's what you have drank so far +1. milo dinosaur (volume: 200ml) | date: 30-03-2024 +2. sprite (volume: 100ml) | date: 01-04-2024 + +Total water intake today: 100 ml +~~~ -### 1.4.5 List entire food intake: `listEverything` +### 1.4.7 List entire food intake: `listExercisesAll` List all the drinks and meals inputted so far **Format**: listEverything **Expected output**: -here's what you have consumed so far -1.pizza (serving size: 1) -2.sprite (serving size: 1) -Total water intake: 0 ml +~~~ +here's the exercises you've done so far +1. cycling | duration: 100 | intensity: LOW | date: 29-02-2024 +2. swimming | duration: 100 | intensity: HIGH | date: 30-03-2024 +3. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 +~~~ -### 1.4.6 List entire food intake for today: `listEverythingToday` +### 1.4.8 List entire food intake for today: `listEverythingAll` List all the drinks and meals inputted today **Format**: listEverythingToday **Expected output**: -here's what you have consumed today -1.pizza (serving size: 1) -2.sprite (serving size: 1) -Total water intake: 0 ml +~~~ +here's what you have consumed so far +1. mala (serving size: 2) | date: 30-03-2024 +2. chicken rice (serving size: 1) | date: 01-04-2024 +3. milo dinosaur (volume: 200ml) | date: 30-03-2024 +4. sprite (volume: 100ml) | date: 01-04-2024 + +Total water intake today: 100 ml + ~~~ +here's the exercises you've done so far +1. cycling | duration: 100 | intensity: LOW | date: 29-02-2024 +2. swimming | duration: 100 | intensity: HIGH | date: 30-03-2024 +3. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 +~~~ ## 1.5 For editing existing data ### 1.5.1 Edit an existing meal after inserted: `editMeal` diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index d3a195b4e5..d6ce811bb3 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -26,7 +26,6 @@ public Drink(String name, int volume, String currentDate) { this.dateAdded = currentDate; } - // Add nutrient details per 100 milliliter to the static HashMap static { nutrientDetails.put("water", new int[]{0, 0, 0, 0, 0}); nutrientDetails.put("sprite", new int[]{40, 50, 30, 20, 2}); diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index c39216470f..df66bc8f53 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -14,7 +14,6 @@ public class Exercise { private int caloriesBurnt; private String dateAdded; - // Constructor with only duration and exercise name public Exercise(String name, int duration, ExerciseIntensity intensity, String currentDate) throws UnregisteredExerciseException { assert name != null : "Name must not be null"; @@ -27,14 +26,12 @@ public Exercise(String name, int duration, ExerciseIntensity intensity, String c this.dateAdded = currentDate; } - // Add exercise details to the static HashMap static { exerciseDetails.put("running", new int[]{8, 5, 3}); exerciseDetails.put("cycling", new int[]{6, 4, 2}); exerciseDetails.put("swimming", new int[]{10, 7, 4}); } - // Method to set exercise details based on exercise name private void setCaloriesBurnt() throws UnregisteredExerciseException { int[] details = exerciseDetails.get(name); if (details == null) { @@ -48,7 +45,6 @@ private boolean isValidIntensity(ExerciseIntensity intensity) { intensity == ExerciseIntensity.LOW; } - // Getter methods public String getName() { return name; } @@ -65,17 +61,14 @@ public String getDate() { return dateAdded; } - // Setter method for name public void setName(String name) { this.name = name; } - // Setter method for duration public void setDuration(int duration) { this.duration = duration; } - // Setter method for intensity public void setIntensity(ExerciseIntensity intensity) { this.intensity = intensity; } @@ -84,7 +77,6 @@ public int getCaloriesBurnt() { return caloriesBurnt; } - // Method to print exercise details public static void handleInfoExercise(String command) throws UnregisteredExerciseException, IncompleteInfoException { String name = Parser.parseInfoExercise(command); @@ -99,7 +91,6 @@ public static void handleInfoExercise(String command) throws UnregisteredExercis System.out.println("LOW intensity: " + details[2]); } - // Print all available exercises registered in the database public static void printAvailableExercises() { System.out.print("Available exercises: "); for (String exercise : exerciseDetails.keySet()) { diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index a3830c6fc3..2aa963dd92 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -18,7 +18,6 @@ public class Meal { private int fiber; private int sugar; - // Constructor with only serving size and meal name public Meal(String name, int servingSize, String currentDate) { assert name != null : "Name must not be null"; this.name = name; @@ -28,14 +27,12 @@ public Meal(String name, int servingSize, String currentDate) { this.dateAdded = currentDate; } - // Add nutrient details to the static HashMap static { nutrientDetails.put("chicken rice", new int[]{400, 50, 30, 20, 10, 5}); nutrientDetails.put("fried rice", new int[]{500, 60, 25, 15, 20, 3}); nutrientDetails.put("pizza", new int[]{600, 70, 20, 25, 30, 2}); } - // Method to set nutrient values based on meal name private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); calories = nutrients[0] * servingSize; @@ -46,7 +43,6 @@ private void setNutrientValues(String name) { sugar = nutrients[5] * servingSize; } - // Getter methods public String getName() { return name; } @@ -79,7 +75,6 @@ public int getServingSize() { return servingSize; } - // Method to print all meal info public static void handleInfoMeal(String command) throws UnregisteredMealException, IncompleteInfoException { String name = Parser.parseInfoMeal(command); int[] nutrients = nutrientDetails.get(name); @@ -92,7 +87,6 @@ public static void handleInfoMeal(String command) throws UnregisteredMealExcepti System.out.println("Sugar: " + nutrients[5]); } - // Print all the available meals registered in the database public static void printAvailableMeals() { System.out.print("Available meals: "); for (String meal : nutrientDetails.keySet()) { diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 12c495ee5e..616b0f61ba 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -138,11 +138,11 @@ public void handleCommand(String command) { } else if (command.startsWith("listEverything") && command.contains("d/")) { user.handleListEverythingDate(command); } else if (command.startsWith("editMeal")) { - User.handleEditMealServingSize(command); + user.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { - User.handleEditDrinkServingSize(command); + user.handleEditDrinkServingSize(command); } else if (command.startsWith("editWater")) { - User.handleEditWaterIntake(command); + user.handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { user.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { @@ -200,7 +200,7 @@ public static void handleHelp() { System.out.println("here's all the valid commands i recognise: "); System.out.println("- Add a meal eaten: eat m/MEAL s/SERVING_SIZE"); System.out.println("- Add a drink: drink d/DRINK s/VOLUME(ML)"); - System.out.println("- Track and exercise: exercise e/EXERCISE d/DURATION(MINUTES) " + + System.out.println("- Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) " + "i/INTENSITY(HIGH, MEDIUM, LOW)"); System.out.println("- Find the information about a certain meal: infoMeal MEAL"); System.out.println("- Find the information about a certain drink: infoDrink DRINK"); @@ -230,6 +230,7 @@ public static void handleHelp() { System.out.println("- Edit total water intake after inserted: editWater s/TOTAL_WATER_INTAKE"); System.out.println("- Delete certain meal entry: deleteMeal INDEX"); System.out.println("- Delete certain drink entry: deleteDrink INDEX"); + System.out.println("- Delete certain exercise entry: deleteExercise INDEX"); System.out.println("- Clear all entries: clear"); System.out.println("- Exit the app: exit "); } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 245eaacf40..f98edd40eb 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -263,7 +263,7 @@ public void saveExercise(Storage exerciseStorage) { } - public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, + public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, NegativeValueException { Parser.parseMeal(command); String mealName = Parser.mealDescription; @@ -324,7 +324,7 @@ public void handleViewCarbohydrates() { for (Drink drink: drinkList) { carbohydratesCount += drink.getCarbs(); } - System.out.println("Total Carbohydrates: " + carbohydratesCount); + System.out.println("Total Carbohydrates: " + carbohydratesCount + " grams"); } public void handleViewProteins() { @@ -335,7 +335,7 @@ public void handleViewProteins() { for (Drink drink: drinkList) { proteinCount += drink.getProtein(); } - System.out.println("Total Proteins: " + proteinCount); + System.out.println("Total Proteins: " + proteinCount + " grams"); } public void handleViewWaterIntake() { @@ -351,7 +351,7 @@ public void handleViewFiber() { for (Meal meal: mealList) { fibreCount += meal.getFiber(); } - System.out.println("Total Fiber: " + fibreCount); + System.out.println("Total Fiber: " + fibreCount + " grams"); } public void handleViewFat() { @@ -362,7 +362,7 @@ public void handleViewFat() { for (Drink drink: drinkList) { fatCount += drink.getFat(); } - System.out.println("Total Fat: " + fatCount); + System.out.println("Total Fat: " + fatCount + " grams"); } public void handleViewSugar() { @@ -373,7 +373,7 @@ public void handleViewSugar() { for (Drink drink: drinkList) { sugarCount += drink.getSugar(); } - System.out.println("Total Sugar: " + sugarCount); + System.out.println("Total Sugar: " + sugarCount + " grams"); } public void printMealList(int startIndex, ArrayList mealListToPrint) { @@ -616,7 +616,7 @@ public void handleListEverythingDate(String command) throws InvalidDateException handleListExercisesDate(command); } - public static void handleEditMealServingSize(String command) throws InvalidListIndexException, + public void handleEditMealServingSize(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { @@ -631,7 +631,7 @@ public static void handleEditMealServingSize(String command) throws InvalidListI System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } - public static void handleEditDrinkServingSize(String command) throws InvalidListIndexException, + public void handleEditDrinkServingSize(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditDrink(command); @@ -646,7 +646,7 @@ public static void handleEditDrinkServingSize(String command) throws InvalidList System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } - public static void handleEditWaterIntake(String command) throws InvalidListIndexException, + public void handleEditWaterIntake(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditWater(command); Date currentDate = new Date(); From 7474502bed51502244d911faf3388d5e3f15a1b3 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 1 Apr 2024 22:24:55 +0800 Subject: [PATCH 130/274] Edit User Storeis --- docs/DeveloperGuide.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index c721cc7fcd..38fe7f7e6b 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -31,10 +31,10 @@ By offering a streamlined interface optimized for keyboard input and CLI interac ## 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| -|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| +| Priority | As a ... | I want to ... | So that I can ... | +|----------|----------|------------------------|--------------------------------------------------------| +| *** |new user| see usage instructions | refer to them when I forget how to use the application | +| *** |user| add a meal | track my daily calorie intake | ## Non-Functional Requirements From ed9e09e15af5372c88e7ede492d414cac38ba06c Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 1 Apr 2024 22:33:32 +0800 Subject: [PATCH 131/274] Fix minor tests --- src/test/java/seedu/fitnus/user/UserTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index ec636a67fc..a0863849fc 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -110,7 +110,7 @@ public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteE @Test public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { testUser.handleViewCalories(); - String expectedOutput = "Total Calories: 5547"; + String expectedOutput = "Total Calories: 5507"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); @@ -119,7 +119,7 @@ public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() @Test public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { testUser.handleViewCarbohydrates(); - String expectedOutput = "Total Carbohydrates: 912"; + String expectedOutput = "Total Carbohydrates: 912 grams"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); @@ -130,7 +130,7 @@ public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { System.setOut(new PrintStream(outputStream)); testUser.handleViewProteins(); - String expectedOutput = "Total Proteins: 215"; + String expectedOutput = "Total Proteins: 215 grams"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); } @@ -150,7 +150,7 @@ public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { System.setOut(new PrintStream(outputStream)); testUser.handleViewFiber(); - String expectedOutput = "Total Fiber: 80"; + String expectedOutput = "Total Fiber: 80 grams"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); @@ -161,7 +161,7 @@ public void handleViewFat_correctFatCalculation_viewFatAccurate() { System.setOut(new PrintStream(outputStream)); testUser.handleViewFat(); - String expectedOutput = "Total Fat: 129"; + String expectedOutput = "Total Fat: 129 grams"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); @@ -172,7 +172,7 @@ public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { System.setOut(new PrintStream(outputStream)); testUser.handleViewSugar(); - String expectedOutput = "Total Sugar: 106"; + String expectedOutput = "Total Sugar: 106 grams"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); @@ -181,7 +181,7 @@ public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { @Test public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { testUser.handleCaloriesBurnt(); - String expectedOutput = "Total calories burnt: 200"; + String expectedOutput = "Total calories burnt: 240"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); From 864a0495e3c53c648dd922be2e89f03ea7215dc1 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 2 Apr 2024 01:23:04 +0800 Subject: [PATCH 132/274] Edit user guide ...up to 1.4.8 --- docs/UserGuide.md | 132 +++++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 59 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index dabe3c9455..89136579ff 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -9,25 +9,30 @@ Users are able to track the meals and drinks they have in a day. [1) Features List](#1-features-list) * [1.1 Information for users](#11-information-for-users) - * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help-) + * [1.1.1 Viewing all commands: `help`](#111-viewing-all-commands-help) * [1.2 For user to add data](#12-for-user-to-add-data) - * [1.2.1 Add a meal eaten: `ate`](#121-add-a-meal-eaten-ate) + * [1.2.1 Add a meal eaten: `eat`](#121-add-a-meal-eaten-eat) * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) - * [1.2.3 Add water: `water`](#123-add-water-water) + * [1.2.2.1 Add water: `drink d/water`](#1221-add-water-drink-dwater) * [1.3 For data retrieval](#13-for-data-retrieval) * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) - * [1.3.3 View daily calories consumed: `calories`](#133-view-daily-calories-consumed-calories) - * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-carbohydrates-consumed-carbs) - * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-proteins-consumed-protein) - * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-fat-consumed-fat) - * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-sugar-consumed-sugar) - * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-fiber-consumed-fiber) - * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-water-consumption-viewwater) + * [1.3.3 View daily calories consumed: `calories`](#133-find-the-information-about-a-certain-exercise-infoexercise) + * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-calories-consumed-calories) + * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-carbohydrates-consumed-carbs) + * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-proteins-consumed-protein) + * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-fat-consumed-fat) + * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-sugar-consumed-sugar) + * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-fiber-consumed-fiber) * [1.4 For listing arrays](#14-for-listing-arrays) - * [1.4.1 List meal intake: `listMeals`](#141-list-meal-intake-listmeals) - * [1.4.2 List drink intake: `listDrinks`](#142-list-drink-intake-listdrinks) - * [1.4.3 List entire food intake for the day: `listEverything`](#143-list-entire-food-intake-for-the-day-listeverything) + * [1.4.1 List all meal intake: `listMeals`](#141-list-all-meal-intake-listmeals) + * [1.4.2 List all drink intake: `listDrinks`](#142-list-all-drink-intake-listdrinks) + * [1.4.3 List all exercises done: `listExercises`](#143-list-all-exercises-done-listexercises) + * [1.4.4 List everything inputted: `listEverything`](#144-list-everything-inputted-listeverything) + * [1.4.5 List entire app's lifecycle meals intake: `listMealsAll`](#145-list-entire-apps-lifecycle-meals-intake-listmealsall) + * [1.4.6 List entire app's lifecycle drinks intake: `listDrinksAll`](#146-list-entire-apps-lifecycle-drinks-intake-listdrinksall) + * [1.4.7 List entire app's lifecycle exercises done: `listExercisesAll`](#147-list-entire-apps-lifecycle-exercises-done-listexercisesall) + * [1.4.8 List everything inputted for the entire app's lifecycle: `listEverythingAll`](#148-list-everything-inputted-for-the-entire-apps-lifecycle-listeverythingall) * [1.5 For editing existing data](#15-for-editing-existing-data) * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) @@ -87,8 +92,8 @@ here's all the valid commands I recognise: ### 1.2 For user to add data ### 1.2.1 Add a meal eaten: `eat` Adds a meal to the list of meals -**Format**: eat m/MEAL s/SERVING_SIZE -**Sample Input**: eat m/Chicken Rice s/1 +**Format**: `eat m/MEAL s/SERVING_SIZE` +**Sample Input**: `eat m/Chicken Rice s/1` **Expected Output**: ~~~ Added 1 serving of Chicken Rice @@ -96,17 +101,26 @@ Added 1 serving of Chicken Rice ### 1.2.2 Add a drink: `drink` Adds a drink to the list of drinks -**Format**: drink d/DRINK s/SERVING_SIZE -**Sample Input**: drink d/Lemon Tea s/100 +**Format**: `drink d/DRINK s/SERVING_SIZE` +**Sample Input**: `drink d/Lemon Tea s/100` **Expected Output**: ~~~ Added 100ml of Lemon Tea ~~~ +### 1.2.2.1 Add water: `drink d/water` +Adds water to the list of water +**Format**: `drink d/water s/SERVING_SIZE` +**Sample Input**: `drink d/water s/100` +**Expected Output**: +~~~ +Added 100ml of water +~~~ + ### 1.2.3 Add exercise: `exercise` Adds exercise to the list of exercises done -**Format**: exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, -**Sample Input**: exercise e/swimming d/30 i/HIGH +**Format**: `exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM,` +**Sample Input**: `exercise e/swimming d/30 i/HIGH` **Expected Output**: ~~~ Tracked 30 minutes of swimming @@ -115,8 +129,8 @@ Tracked 30 minutes of swimming ## 1.3 For data retrieval ### 1.3.1 Find the information about a certain meal: `infoMeal` For the specified meal, display its nutritional content to the user -**Format**: infoMeal MEAL -**Sample Input**: infoMeal chicken rice +**Format**: `infoMeal MEAL` +**Sample Input**: `infoMeal chicken rice` **Expected Output**: ~~~ Meal: chicken rice (per serving)` @@ -129,9 +143,9 @@ Sugar: 10 ~~~ ### 1.3.2 Find the information about a certain drink: `infoDrink` -For the inputed drink, display its nutritional content to the user -**Format**: infoDrink DRINK -**Sample input**: infoDrink sprite +For the inputted drink, display its nutritional content to the user +**Format**: `infoDrink DRINK` +**Sample input**: `infoDrink sprite` **Expected output**: ~~~ Drink: sprite (100 ml) @@ -143,9 +157,9 @@ Fat: 2 ~~~ ### 1.3.3 Find the information about a certain exercise: `infoExercise` -For the inputed exercise, display its calories burnt per minute for different intensities to the user -**Format**: infoExercise EXERCISE -**Sample input**: infoExercise swimming +For the inputted exercise, display its calories burnt per minute for different intensities to the user +**Format**: `infoExercise EXERCISE` +**Sample input**: `infoExercise swimming` **Expected output**: ~~~ Exercise: swimming @@ -157,7 +171,7 @@ LOW intensity: 5 ### 1.3.4 View daily calories consumed: `calories` Display current total calorie intake for the day -**Format**: calories +**Format**: `calories` **Expected output**: ~~~ Total calories: 100 cal @@ -165,7 +179,7 @@ Total calories: 100 cal ### 1.3.5 View daily carbohydrates consumed: `carbs` Display current total carbohydrates intake for the day -**Format**: carbs +**Format**: `carbs` **Expected output**: ~~~ Total Carbohydrates: 150 grams @@ -173,7 +187,7 @@ Total Carbohydrates: 150 grams ### 1.3.6 View daily proteins consumed: `protein` Display current total protein intake for the day -**Format**: protein +**Format**: `protein` **Expected output**: ~~~ Total proteins: 100 grams @@ -181,7 +195,7 @@ Total proteins: 100 grams ### 1.3.7 View daily fat consumed: `fat` Display current total fat intake for the day -**Format**: fat +**Format**: `fat` **Expected output**: ~~~ Total fat: 50 grams @@ -189,7 +203,7 @@ Total fat: 50 grams ### 1.3.8 View daily sugar consumed: `sugar` Display current total sugar intake for the day -**Format**: sugar +**Format**: `sugar` **Expected output**: ~~~ Total sugar: 20 grams @@ -197,7 +211,7 @@ Total sugar: 20 grams ### 1.3.9 View daily fiber consumed: `fiber` Display current total fiber intake (g) for the day -**Format**: viewFiber +**Format**: `fiber` **Expected output**: ~~~ Total fiber: 20 grams @@ -205,7 +219,7 @@ Total fiber: 20 grams ### 1.3.10 View daily water consumption: `viewWater` Display current total water intake (in ml) for the day -**Format**: viewWater +**Format**: `viewWater` **Expected output**: ~~~ Total water intake: 0 ml @@ -213,7 +227,7 @@ Total water intake: 0 ml ### 1.3.11 View daily calories consumed: `caloriesBurnt` Display current total calorie burnt for the day -**Format**: caloriesBurnt +**Format**: `caloriesBurnt` **Expected output**: ~~~ Total calories burnt: 70 @@ -221,8 +235,8 @@ Total calories burnt: 70 ## 1.4 For listing arrays ### 1.4.1 List all meal intake: `listMeals` -List all the meals user input today -**Format**: listMeals +Display all the meals user input today +**Format**: `listMeals` **Expected output**: ~~~ here's what you have eaten today @@ -230,8 +244,8 @@ here's what you have eaten today ~~~ ### 1.4.2 List all drink intake: `listDrinks` -List all the drinks user input today -**Format**: listDrinks +Display all the drinks user input today +**Format**: `listDrinks` **Expected output**: ~~~ here's what you have drank today @@ -240,18 +254,18 @@ here's what you have drank today Total water intake today: 0 ml ~~~ -### 1.4.3 List all drink intake: `listExercises` -List all the exercises user tracked today -**Format**: listDrinks -**Expected output**: -here's the exercises you've done today +### 1.4.3 List all exercises done: `listExercises` +Display all the exercises user tracked today +**Format**: `listExercises` +**Expected output**: ~~~ +here's the exercises you've done today 1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.4 List all drink intake: `listEverything` -List all the meals, drinks and exercises user tracked today -**Format**: listDrinks +### 1.4.4 List everything inputted: `listEverything` +Display all the meals, drinks and exercises user tracked today +**Format**: `listEverything` **Expected output**: ~~~ here's what you have consumed today @@ -264,9 +278,9 @@ here's the exercises you've done today 1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.5 List today's meal intake: `listMealsAll` -List all the meals user input -**Format**: listMealsToday +### 1.4.5 List entire app's lifecycle meals intake: `listMealsAll` +Display all the meals user inputted for the entire app lifecycle +**Format**: `listMealsAll` **Expected output**: ~~~ here's what you have eaten so far @@ -274,9 +288,9 @@ here's what you have eaten so far 2. chicken rice (serving size: 1) | date: 01-04-2024 ~~~ -### 1.4.6 List today's drink intake: `listDrinksAll` -List all the drinks user inputted today -**Format**: listDrinksToday +### 1.4.6 List entire app's lifecycle drinks intake: `listDrinksAll` +Display all the drinks user inputted for the entire app lifecycle +**Format**: `listDrinksAll` **Expected output**: ~~~ here's what you have drank so far @@ -286,9 +300,9 @@ here's what you have drank so far Total water intake today: 100 ml ~~~ -### 1.4.7 List entire food intake: `listExercisesAll` -List all the drinks and meals inputted so far -**Format**: listEverything +### 1.4.7 List entire app's lifecycle exercises done: `listExercisesAll` +Display all the exercises inputted for the entire app lifecycle +**Format**: `listExercisesAll` **Expected output**: ~~~ here's the exercises you've done so far @@ -297,9 +311,9 @@ here's the exercises you've done so far 3. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.8 List entire food intake for today: `listEverythingAll` -List all the drinks and meals inputted today -**Format**: listEverythingToday +### 1.4.8 List everything inputted for the entire app's lifecycle: `listEverythingAll` +Display all the drinks, meals, and exercises inputted for the entire app lifecycle +**Format**: `listEverythingAll` **Expected output**: ~~~ here's what you have consumed so far From a86ccfa108cc0db11470303d03b5be9c78b296ee Mon Sep 17 00:00:00 2001 From: tinaliu27 <27tinaliu@gmail.com> Date: Tue, 2 Apr 2024 01:28:00 +0700 Subject: [PATCH 133/274] added recommendations to view Calories and view Water --- src/main/java/seedu/fitnus/CSVReader.java | 3 +- src/main/java/seedu/fitnus/user/User.java | 66 +++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java index 30f424f6b7..0414692ee3 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -13,8 +13,7 @@ public static void main(String[] args){ String mealCsvFile = "./db/Meal_db.csv"; String drinkCSVFile = "./db/Drink_db.csv"; CSVReader.read(mealCsvFile); - printInfo(); - readMealInfo(mealCsvFile, "Pepper lunch "); + // readMealInfo(mealCsvFile, "Pepper lunch "); } public static void read(String filename) { try{ diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 310cd98620..e071b90298 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -22,12 +22,20 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.text.SimpleDateFormat; import java.util.ArrayList; public class User { protected static ArrayList mealList; protected static ArrayList drinkList; protected static ArrayList exerciseList; + private static String currentDate; + private static String currentDateSpecific; + + + + final static int RECOMMEND_WATER_INTAKE = 2600; + final static int RECOMMEND_CALORIE_INTAKE = 2200; public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage) { mealList = new ArrayList<>(); @@ -187,6 +195,38 @@ public void handleViewCalories() { caloriesCount -= exercise.getCaloriesBurnt(); } System.out.println("Total Calories: " + caloriesCount); + + long millis = System.currentTimeMillis(); + java.sql.Date date = new java.sql.Date(millis); + SimpleDateFormat dateFormat = new SimpleDateFormat("hh"); + + String currentFormattedDate = dateFormat.format(date); + int currentHour = Integer.parseInt(currentFormattedDate); + if(currentHour >= 0 && currentHour < 12) { + if (caloriesCount < RECOMMEND_CALORIE_INTAKE / 4 - 200 || Math.min(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4) == caloriesCount) { + System.out.println("Recommend eating more food. Your daily recommended calories intake by this time is 550 calories. You have: " + (RECOMMEND_CALORIE_INTAKE - caloriesCount) + "calories left!"); + } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE / 4 + 200 || Math.max(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4 + 200) == caloriesCount) { + System.out.println("Recommend eating less food. "); + } else { + System.out.println("Eating sufficient amount of calories by this time of day. Good job!"); + } + } else if (currentHour >= 12 && currentHour < 18) { + if (caloriesCount < RECOMMEND_CALORIE_INTAKE / 2 - 100 || Math.min(caloriesCount, RECOMMEND_WATER_INTAKE/2) == caloriesCount) { + System.out.println("Recommend eating more food. Your daily recommended calories intake by this time is 1100 calories. You have: " + (RECOMMEND_CALORIE_INTAKE - caloriesCount) + "calories left!"); + } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE / 4 + 200 || Math.max(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4 + 200) == caloriesCount) { + System.out.println("Recommend eating less food. "); + } else { + System.out.println("Eating sufficient amount of calories by this time of day. Good job!"); + } + } else { + if (caloriesCount < RECOMMEND_CALORIE_INTAKE - 100 || Math.min(caloriesCount, RECOMMEND_WATER_INTAKE/2) == caloriesCount) { + System.out.println("Recommend eating more food. Your daily recommended calories intake by this time is 1650 calories. You have: " + (RECOMMEND_CALORIE_INTAKE - caloriesCount) + "calories left!"); + } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE / 4 + 200 || Math.max(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4 + 200) == caloriesCount) { + System.out.println("Recommend eating less food. "); + } else { + System.out.println("Eating sufficient amount of calories by this time of day. Good job!"); + } + } } public void handleViewCarbohydrates() { @@ -215,6 +255,32 @@ public void handleViewWaterIntake() { int waterIntake = 0; waterIntake += Water.getWater(); System.out.println("Total water intake: " + waterIntake + " ml"); + // if current date time is more than half the day, user should have drank 400 ml of water, if not then print a statement that recommends the user to drink more wate + long millis = System.currentTimeMillis(); + java.sql.Date date = new java.sql.Date(millis); + SimpleDateFormat dateFormat = new SimpleDateFormat("hh"); + + String currentFormattedDate = dateFormat.format(date); + int currentHour = Integer.parseInt(currentFormattedDate); + if(currentHour >= 0 && currentHour < 12) { + if (waterIntake < RECOMMEND_WATER_INTAKE / 4 || Math.min(waterIntake, RECOMMEND_WATER_INTAKE / 4) == waterIntake) { + System.out.println("Recommend drinking more water. Your daily recommended water intake by this time is 650ml of water. You have: " + (RECOMMEND_WATER_INTAKE - waterIntake) + "ml left!"); + } else { + System.out.println("On track with water intake!"); + } + } else if (currentHour >= 12 && currentHour < 18) { + if (waterIntake < RECOMMEND_WATER_INTAKE / 2 || Math.min(waterIntake, RECOMMEND_WATER_INTAKE/2) == waterIntake) { + System.out.println("Recommend drinking more water. Your daily recommended water intake by this time is 400ml of water. You have: " + (RECOMMEND_WATER_INTAKE - waterIntake) + "ml left!"); + } else { + System.out.println("On track with water intake!"); + } + } else { + if (currentHour < RECOMMEND_WATER_INTAKE || Math.min(waterIntake, RECOMMEND_WATER_INTAKE/2) == waterIntake) { + System.out.println("Recommend drinking more water. Your daily recommended water intake by this time is 800ml of water. You have: " + (RECOMMEND_WATER_INTAKE - waterIntake) + "ml left!"); + } else { + System.out.println("On track with water intake!"); + } + } } public void handleViewFiber() { From 39a74649bbe8aa1b04c1d696eefef1f9a9dfadd4 Mon Sep 17 00:00:00 2001 From: tinaliu27 <27tinaliu@gmail.com> Date: Tue, 2 Apr 2024 03:59:00 +0700 Subject: [PATCH 134/274] added method to add into csv file based on user input --- db/Meal_db.csv | 6 ++--- db/Output_Food_2024-04-02.csv | 1 + src/main/java/seedu/fitnus/CSVReader.java | 30 +++++++++-------------- src/main/java/seedu/fitnus/CSVWriter.java | 11 ++++++--- src/main/java/seedu/fitnus/user/User.java | 2 +- 5 files changed, 23 insertions(+), 27 deletions(-) create mode 100644 db/Output_Food_2024-04-02.csv diff --git a/db/Meal_db.csv b/db/Meal_db.csv index e8b89e4989..d4073921d9 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -10,9 +10,9 @@ roti prata ,209,32,5,7,2,10 Pork Satay with Satay Sauce ,36,1,5,2,10,0 Nasi Goreng,346,45,13,12,10,2 Wanton Mee,555,97,15,14,13,10 -Mala ,583,72,12,30,10,7 -Oyster Omlette ,467,40,19,24,10,1 -Pepper lunch ,500,50,40,11,4,5 +Mala,583,72,12,30,10,7 +Oyster Omlette,467,40,19,24,10,1 +Pepper lunch,500,50,40,11,4,5 Ban Mian,475,48,22,22,3,10 Soup Kambeng,203,6,28,7,2,5 Durian,147,27,2,5,3,5 diff --git a/db/Output_Food_2024-04-02.csv b/db/Output_Food_2024-04-02.csv new file mode 100644 index 0000000000..6aa19a464b --- /dev/null +++ b/db/Output_Food_2024-04-02.csv @@ -0,0 +1 @@ +Chicken Rice,607,75,25,23,2,10 diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java index 0414692ee3..b3a40c1544 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -10,10 +10,10 @@ public class CSVReader { private static HashMap foodItems = new HashMap<>(); public static void main(String[] args){ - String mealCsvFile = "./db/Meal_db.csv"; + String mealCsvFile = "./tp/db//Meal_db.csv"; String drinkCSVFile = "./db/Drink_db.csv"; CSVReader.read(mealCsvFile); - // readMealInfo(mealCsvFile, "Pepper lunch "); + // readMealInfo(mealCsvFile, "Pepper lunch"); } public static void read(String filename) { try{ @@ -21,7 +21,7 @@ public static void read(String filename) { FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); - String line = ""; + String line = " "; String[] tempArr; while ((line = br.readLine()) != null) { tempArr = line.split(DELIMITER); @@ -40,8 +40,9 @@ public static void read(String filename) { e.printStackTrace(); } } - public static void readMealInfo(String filename, String foodName) { + public static String readMealInfo(String filename, String foodName) { read(filename); + StringBuilder result = new StringBuilder(); boolean found = false; String[] nutrientInfo = null; if (foodItems.containsKey(foodName)) { @@ -51,25 +52,16 @@ public static void readMealInfo(String filename, String foodName) { System.out.println("Error! Food not found. Please input a valid item."); } if (found && nutrientInfo != null) { - for (String nutrients : nutrientInfo) { - System.out.println(nutrients); + result.append(foodName); + for(int i = 0; i < nutrientInfo.length; i++) { + result.append(DELIMITER).append(nutrientInfo[i]); } } + return result.toString(); } - public static void printInfo() { - for (HashMap.Entry entry : foodItems.entrySet()) { - String key = entry.getKey(); - String[] value = entry.getValue(); - System.out.print("Key: " + key + ", Value: ["); - for (int i = 0; i < value.length; i++) { - System.out.print(value[i]); - if (i < value.length - 1) { - System.out.print(", "); - } - } - System.out.println("]"); - } + public static void combineKeyandValue(String key) { + } } diff --git a/src/main/java/seedu/fitnus/CSVWriter.java b/src/main/java/seedu/fitnus/CSVWriter.java index 3cfbd260ab..27738f3eb4 100644 --- a/src/main/java/seedu/fitnus/CSVWriter.java +++ b/src/main/java/seedu/fitnus/CSVWriter.java @@ -9,16 +9,19 @@ import java.util.Date; public class CSVWriter { + private static CSVReader csvreader = new CSVReader(); + public static void main(String[] args) { - writeIntoFile("hi", "FOOD"); + writeIntoFile("Chicken Rice", "FOOD"); } public static void writeIntoFile(String foodItem, String fileName) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); File file = null; + String x = ""; if (fileName.toLowerCase().contains("food")) { - file = new File("./db/Output_Food_" + df.format(new Date())+".csv"); + file = new File("./tp/db/Output_Food_" + df.format(new Date())+".csv"); } else { - file = new File("./db/Output_Drink_" + df.format(new Date())+".csv"); + file = new File("./tp/db/Output_Drink_" + df.format(new Date())+".csv"); } if (!file.exists()) { try{ @@ -29,7 +32,7 @@ public static void writeIntoFile(String foodItem, String fileName) { } try (FileWriter fw = new FileWriter(file)){ BufferedWriter writer = new BufferedWriter(fw); - writer.write(foodItem); + writer.write(csvreader.readMealInfo("./tp/db//Meal_db.csv", foodItem)); writer.newLine(); writer.close(); } catch (IOException e) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index e071b90298..39b064702f 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -224,7 +224,7 @@ public void handleViewCalories() { } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE / 4 + 200 || Math.max(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4 + 200) == caloriesCount) { System.out.println("Recommend eating less food. "); } else { - System.out.println("Eating sufficient amount of calories by this time of day. Good job!"); + System.out.println("Eating sufficient amount of calories by this time of day. Good job! "); } } } From 926f5991825244e62caf6a49d35b270b942d07f3 Mon Sep 17 00:00:00 2001 From: tinaliu27 <27tinaliu@gmail.com> Date: Tue, 2 Apr 2024 04:20:28 +0700 Subject: [PATCH 135/274] added readfile to the eat command --- db/Meal_db.csv | 4 ++-- db/Output_Food_2024-04-02.csv | 2 +- src/main/java/seedu/fitnus/CSVReader.java | 1 - src/main/java/seedu/fitnus/CSVWriter.java | 12 +++++++++--- src/main/java/seedu/fitnus/user/User.java | 15 +++++---------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/db/Meal_db.csv b/db/Meal_db.csv index d4073921d9..2524f79650 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,5 +1,5 @@ -Chicken Rice,607,75,25,23,2,10 -Char Kway Teow,744,76,23,29,7,10 +chicken rice,607,75,25,23,2,10 +char kway teow,744,76,23,29,7,10 Laksa,377,71,18,2,4,10 Hokkien Prawn Mee,522,69,18,19,4,10 Kaya Toast,459,44,8,27,10,1 diff --git a/db/Output_Food_2024-04-02.csv b/db/Output_Food_2024-04-02.csv index 6aa19a464b..7000af8eed 100644 --- a/db/Output_Food_2024-04-02.csv +++ b/db/Output_Food_2024-04-02.csv @@ -1 +1 @@ -Chicken Rice,607,75,25,23,2,10 +chicken rice,607,75,25,23,2,10 diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java index b3a40c1544..86585dd8d6 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -13,7 +13,6 @@ public static void main(String[] args){ String mealCsvFile = "./tp/db//Meal_db.csv"; String drinkCSVFile = "./db/Drink_db.csv"; CSVReader.read(mealCsvFile); - // readMealInfo(mealCsvFile, "Pepper lunch"); } public static void read(String filename) { try{ diff --git a/src/main/java/seedu/fitnus/CSVWriter.java b/src/main/java/seedu/fitnus/CSVWriter.java index 27738f3eb4..9ce96c9d61 100644 --- a/src/main/java/seedu/fitnus/CSVWriter.java +++ b/src/main/java/seedu/fitnus/CSVWriter.java @@ -17,11 +17,14 @@ public static void main(String[] args) { public static void writeIntoFile(String foodItem, String fileName) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); File file = null; - String x = ""; + String readFromFile = ""; if (fileName.toLowerCase().contains("food")) { file = new File("./tp/db/Output_Food_" + df.format(new Date())+".csv"); + readFromFile += "./tp/db//Meal_db.csv"; } else { file = new File("./tp/db/Output_Drink_" + df.format(new Date())+".csv"); + readFromFile += "./tp/db//Drink_db.csv"; + } if (!file.exists()) { try{ @@ -32,11 +35,14 @@ public static void writeIntoFile(String foodItem, String fileName) { } try (FileWriter fw = new FileWriter(file)){ BufferedWriter writer = new BufferedWriter(fw); - writer.write(csvreader.readMealInfo("./tp/db//Meal_db.csv", foodItem)); + writer.write(csvreader.readMealInfo(readFromFile, foodItem)); writer.newLine(); writer.close(); } catch (IOException e) { - System.out.println("error trying to add something into the file"); + e.printStackTrace(); } } + public static void deleteFromFile(String foodItem, String fileName) { + + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 39b064702f..610928bca1 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -1,15 +1,10 @@ package seedu.fitnus.user; -import seedu.fitnus.Date; -import seedu.fitnus.Drink; -import seedu.fitnus.Exercise; -import seedu.fitnus.ExerciseIntensity; -import seedu.fitnus.Meal; +import seedu.fitnus.*; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.parser.Parser; -import seedu.fitnus.Water; import seedu.fitnus.storage.Storage; import seedu.fitnus.exception.IncompleteDrinkException; @@ -26,16 +21,15 @@ import java.util.ArrayList; public class User { + public static final int RECOMMEND_WATER_INTAKE = 2600; + public static final int RECOMMEND_CALORIE_INTAKE = 2200; protected static ArrayList mealList; protected static ArrayList drinkList; protected static ArrayList exerciseList; private static String currentDate; private static String currentDateSpecific; - - - final static int RECOMMEND_WATER_INTAKE = 2600; - final static int RECOMMEND_CALORIE_INTAKE = 2200; + private static CSVWriter csvWriter = new CSVWriter(); public User(Storage mealStorage, Storage drinkStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage) { mealList = new ArrayList<>(); @@ -165,6 +159,7 @@ public static void handleMeal(String command) throws IncompleteMealException, Un assert !mealList.isEmpty(): "failed to add meal"; System.out.println("Added " + servingSize + " serving of " + mealName); + csvWriter.writeIntoFile(mealName, "FOOD"); } public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, From a3cfccf1d179f35c9a131e2f26f98edce817742b Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Tue, 2 Apr 2024 15:32:06 +0800 Subject: [PATCH 136/274] Update UserGuide --- docs/UserGuide.md | 113 ++++++++++++++---- src/main/java/seedu/fitnus/parser/Parser.java | 2 +- 2 files changed, 88 insertions(+), 27 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 89136579ff..709cc87acd 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -7,42 +7,52 @@ Users are able to track the meals and drinks they have in a day. ## Table of Contents -[1) Features List](#1-features-list) -* [1.1 Information for users](#11-information-for-users) - * [1.1.1 Viewing all commands: `help`](#111-viewing-all-commands-help) -* [1.2 For user to add data](#12-for-user-to-add-data) +* [User Guide: FitNUS](#user-guide-fitnus) + * [Project Introduction](#project-introduction) + * [Table of Contents](#table-of-contents) + * [1) Features List](#1-features-list) + * [1.1 Information for users](#11-information-for-users) + * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help) + * [1.2 For user to add data](#12-for-user-to-add-data) * [1.2.1 Add a meal eaten: `eat`](#121-add-a-meal-eaten-eat) * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) - * [1.2.2.1 Add water: `drink d/water`](#1221-add-water-drink-dwater) -* [1.3 For data retrieval](#13-for-data-retrieval) + * [1.2.2.1 Add water: `drink d/water`](#1221-add-water-drink-dwater) + * [1.2.3 Add exercise: `exercise`](#123-add-exercise-exercise) + * [1.3 For data retrieval](#13-for-data-retrieval) * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) - * [1.3.3 View daily calories consumed: `calories`](#133-find-the-information-about-a-certain-exercise-infoexercise) - * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-calories-consumed-calories) - * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-carbohydrates-consumed-carbs) - * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-proteins-consumed-protein) - * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-fat-consumed-fat) - * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-sugar-consumed-sugar) - * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-fiber-consumed-fiber) -* [1.4 For listing arrays](#14-for-listing-arrays) - * [1.4.1 List all meal intake: `listMeals`](#141-list-all-meal-intake-listmeals) - * [1.4.2 List all drink intake: `listDrinks`](#142-list-all-drink-intake-listdrinks) - * [1.4.3 List all exercises done: `listExercises`](#143-list-all-exercises-done-listexercises) - * [1.4.4 List everything inputted: `listEverything`](#144-list-everything-inputted-listeverything) + * [1.3.3 Find the information about a certain exercise: `infoExercise`](#133-find-the-information-about-a-certain-exercise-infoexercise) + * [1.3.4 View daily calories consumed: `calories`](#134-view-daily-calories-consumed-calories) + * [1.3.5 View daily carbohydrates consumed: `carbs`](#135-view-daily-carbohydrates-consumed-carbs) + * [1.3.6 View daily proteins consumed: `protein`](#136-view-daily-proteins-consumed-protein) + * [1.3.7 View daily fat consumed: `fat`](#137-view-daily-fat-consumed-fat) + * [1.3.8 View daily sugar consumed: `sugar`](#138-view-daily-sugar-consumed-sugar) + * [1.3.9 View daily fiber consumed: `fiber`](#139-view-daily-fiber-consumed-fiber) + * [1.3.10 View daily water consumption: `viewWater`](#1310-view-daily-water-consumption-viewwater) + * [1.3.11 View daily calories consumed: `caloriesBurnt`](#1311-view-daily-calories-consumed-caloriesburnt) + * [1.4 For listing arrays](#14-for-listing-arrays) + * [1.4.1 List today's meal intake: `listMeals`](#141-list-todays-meal-intake-listmeals) + * [1.4.2 List today's drink intake: `listDrinks`](#142-list-todays-drink-intake-listdrinks) + * [1.4.3 List today's exercises done: `listExercises`](#143-list-todays-exercises-done-listexercises) + * [1.4.4 List everything inputted today: `listEverything`](#144-list-everything-inputted-today-listeverything) * [1.4.5 List entire app's lifecycle meals intake: `listMealsAll`](#145-list-entire-apps-lifecycle-meals-intake-listmealsall) * [1.4.6 List entire app's lifecycle drinks intake: `listDrinksAll`](#146-list-entire-apps-lifecycle-drinks-intake-listdrinksall) * [1.4.7 List entire app's lifecycle exercises done: `listExercisesAll`](#147-list-entire-apps-lifecycle-exercises-done-listexercisesall) * [1.4.8 List everything inputted for the entire app's lifecycle: `listEverythingAll`](#148-list-everything-inputted-for-the-entire-apps-lifecycle-listeverythingall) -* [1.5 For editing existing data](#15-for-editing-existing-data) + * [1.4.9 List meal intake for a certain date: `listMeals d/[DATE]`](#149-list-meal-intake-for-a-certain-date-listmeals-ddate) + * [1.4.10 List drink intake for a certain date: `listDrinks d/[DATE]`](#1410-list-drink-intake-for-a-certain-date-listdrinks-ddate) + * [1.4.11 List exercise done for a certain date: `listExercises d/[DATE]`](#1411-list-exercise-done-for-a-certain-date-listexercises-ddate) + * [1.4.12 List entire food intake and exercise done for a certain date: `listEverything d/[DATE]`](#1412-list-entire-food-intake-and-exercise-done-for-a-certain-date-listeverything-ddate) + * [1.5 For editing existing data](#15-for-editing-existing-data) * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) * [1.5.3 Edit water intake after inserted: `editWater`](#153-edit-water-intake-after-inserted-editwater) -* [1.6 For deleting data](#16-for-deleting-data) + * [1.6 For deleting data](#16-for-deleting-data) * [1.6.1 Delete certain meal entry: `deleteMeal`](#161-delete-certain-meal-entry-deletemeal) * [1.6.2 Delete certain drink entry: `deleteDrink`](#162-delete-certain-drink-entry-deletedrink) -* [1.7 For clearing data](#17-for-clearing-data-) + * [1.7 For clearing data](#17-for-clearing-data) * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) -* [1.8: Exit program](#18-exit-program) + * [1.8: Exit program](#18-exit-program) * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) @@ -234,7 +244,7 @@ Total calories burnt: 70 ~~~ ## 1.4 For listing arrays -### 1.4.1 List all meal intake: `listMeals` +### 1.4.1 List today's meal intake: `listMeals` Display all the meals user input today **Format**: `listMeals` **Expected output**: @@ -243,7 +253,7 @@ here's what you have eaten today 1. chicken rice (serving size: 1) | date: 01-04-2024 ~~~ -### 1.4.2 List all drink intake: `listDrinks` +### 1.4.2 List today's drink intake: `listDrinks` Display all the drinks user input today **Format**: `listDrinks` **Expected output**: @@ -254,7 +264,7 @@ here's what you have drank today Total water intake today: 0 ml ~~~ -### 1.4.3 List all exercises done: `listExercises` +### 1.4.3 List today's exercises done: `listExercises` Display all the exercises user tracked today **Format**: `listExercises` **Expected output**: @@ -263,7 +273,7 @@ here's the exercises you've done today 1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.4 List everything inputted: `listEverything` +### 1.4.4 List everything inputted today: `listEverything` Display all the meals, drinks and exercises user tracked today **Format**: `listEverything` **Expected output**: @@ -330,6 +340,57 @@ here's the exercises you've done so far 3. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ +### 1.4.9 List meal intake for a certain date: `listMeals d/[DATE]` +Display all the meals user inputted for the specified date +**Format**: `listMeals d/dd-MM-yyyy` +**Expected output**: +~~~ +here's what you have eaten on 01-04-2024 +1. soup kambeng (serving size: 2) | date: 01-04-2024 +2. nasi lemak (serving size: 2) | date: 01-04-2024 +3. tau huay (serving size: 1) | date: 01-04-2024 +4. roti prata (serving size: 2) | date: 01-04-2024 +~~~ + +### 1.4.10 List drink intake for a certain date: `listDrinks d/[DATE]` +Display all the drinks user inputted for the specified date (excluding water) +**Format**: `listDrinks d/dd-MM-yyyy` +**Expected output**: +~~~ +here's what you have drank on 01-04-2024 +1. honey lemon tea (volume: 200ml) | date: 01-04-2024 +2. kopi c (volume: 500ml) | date: 01-04-2024 +3. milo (volume: 200ml) | date: 01-04-2024 +~~~ + +### 1.4.11 List exercise done for a certain date: `listExercises d/[DATE]` +Display all the exercises user inputted for the specified date +**Format**: `listExercises d/dd-MM-yyyy` +**Expected output**: +~~~ +here's the exercises you've done on 01-04-2024 +1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 +~~~ + +### 1.4.12 List entire food intake and exercise done for a certain date: `listEverything d/[DATE]` +Display all the meals, drinks, and exercises user inputted for the specified date +**Format**: `listEverything d/dd-MM-yyyy` +**Expected output**: +~~~ +here's what you have consumed on 01-04-2024 +1. soup kambeng (serving size: 2) | date: 01-04-2024 +2. nasi lemak (serving size: 2) | date: 01-04-2024 +3. tau huay (serving size: 1) | date: 01-04-2024 +4. roti prata (serving size: 2) | date: 01-04-2024 +5. honey lemon tea (volume: 200ml) | date: 01-04-2024 +6. kopi c (volume: 500ml) | date: 01-04-2024 +7. milo (volume: 200ml) | date: 01-04-2024 + + ~~~ +here's the exercises you've done on 01-04-2024 +1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 +~~~ + ## 1.5 For editing existing data ### 1.5.1 Edit an existing meal after inserted: `editMeal` For a meal that was inputted in the day, edit its serving size diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 616b0f61ba..854d0a6fe6 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -220,7 +220,7 @@ public static void handleHelp() { System.out.println("- List all meal intake: listMealsAll"); System.out.println("- List all drink intake: listDrinksAll"); System.out.println("- List all exercises done: listExercisesAll"); - System.out.println("- List all entire food intake and exercises: listEverythingAll"); + System.out.println("- List all food intake and exercises: listEverythingAll"); System.out.println("- List meal intake for certain date: listMeals d/dd-MM-yyyy"); System.out.println("- List drink intake for certain date: listDrinks d/dd-MM-yyyy"); System.out.println("- List exercises done for certain date: listExercises d/dd-MM-yyyy"); From 432a5ea4e11ec2e2bf02eeaad0d82b6225c67840 Mon Sep 17 00:00:00 2001 From: Jason Lienardi <76238813+jasonlienardi@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:51:19 +0800 Subject: [PATCH 137/274] Revert "added recommendations to view Calories and view Water" --- db/Meal_db.csv | 10 ++-- db/Output_Food_2024-04-02.csv | 1 - src/main/java/seedu/fitnus/CSVReader.java | 30 ++++++---- src/main/java/seedu/fitnus/CSVWriter.java | 19 ++----- src/main/java/seedu/fitnus/user/User.java | 69 +---------------------- 5 files changed, 33 insertions(+), 96 deletions(-) delete mode 100644 db/Output_Food_2024-04-02.csv diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 2524f79650..e8b89e4989 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,5 +1,5 @@ -chicken rice,607,75,25,23,2,10 -char kway teow,744,76,23,29,7,10 +Chicken Rice,607,75,25,23,2,10 +Char Kway Teow,744,76,23,29,7,10 Laksa,377,71,18,2,4,10 Hokkien Prawn Mee,522,69,18,19,4,10 Kaya Toast,459,44,8,27,10,1 @@ -10,9 +10,9 @@ roti prata ,209,32,5,7,2,10 Pork Satay with Satay Sauce ,36,1,5,2,10,0 Nasi Goreng,346,45,13,12,10,2 Wanton Mee,555,97,15,14,13,10 -Mala,583,72,12,30,10,7 -Oyster Omlette,467,40,19,24,10,1 -Pepper lunch,500,50,40,11,4,5 +Mala ,583,72,12,30,10,7 +Oyster Omlette ,467,40,19,24,10,1 +Pepper lunch ,500,50,40,11,4,5 Ban Mian,475,48,22,22,3,10 Soup Kambeng,203,6,28,7,2,5 Durian,147,27,2,5,3,5 diff --git a/db/Output_Food_2024-04-02.csv b/db/Output_Food_2024-04-02.csv deleted file mode 100644 index 7000af8eed..0000000000 --- a/db/Output_Food_2024-04-02.csv +++ /dev/null @@ -1 +0,0 @@ -chicken rice,607,75,25,23,2,10 diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/CSVReader.java index 86585dd8d6..30f424f6b7 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/CSVReader.java @@ -10,9 +10,11 @@ public class CSVReader { private static HashMap foodItems = new HashMap<>(); public static void main(String[] args){ - String mealCsvFile = "./tp/db//Meal_db.csv"; + String mealCsvFile = "./db/Meal_db.csv"; String drinkCSVFile = "./db/Drink_db.csv"; CSVReader.read(mealCsvFile); + printInfo(); + readMealInfo(mealCsvFile, "Pepper lunch "); } public static void read(String filename) { try{ @@ -20,7 +22,7 @@ public static void read(String filename) { FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); - String line = " "; + String line = ""; String[] tempArr; while ((line = br.readLine()) != null) { tempArr = line.split(DELIMITER); @@ -39,9 +41,8 @@ public static void read(String filename) { e.printStackTrace(); } } - public static String readMealInfo(String filename, String foodName) { + public static void readMealInfo(String filename, String foodName) { read(filename); - StringBuilder result = new StringBuilder(); boolean found = false; String[] nutrientInfo = null; if (foodItems.containsKey(foodName)) { @@ -51,16 +52,25 @@ public static String readMealInfo(String filename, String foodName) { System.out.println("Error! Food not found. Please input a valid item."); } if (found && nutrientInfo != null) { - result.append(foodName); - for(int i = 0; i < nutrientInfo.length; i++) { - result.append(DELIMITER).append(nutrientInfo[i]); + for (String nutrients : nutrientInfo) { + System.out.println(nutrients); } } - return result.toString(); } - public static void combineKeyandValue(String key) { - + public static void printInfo() { + for (HashMap.Entry entry : foodItems.entrySet()) { + String key = entry.getKey(); + String[] value = entry.getValue(); + System.out.print("Key: " + key + ", Value: ["); + for (int i = 0; i < value.length; i++) { + System.out.print(value[i]); + if (i < value.length - 1) { + System.out.print(", "); + } + } + System.out.println("]"); + } } } diff --git a/src/main/java/seedu/fitnus/CSVWriter.java b/src/main/java/seedu/fitnus/CSVWriter.java index 9ce96c9d61..3cfbd260ab 100644 --- a/src/main/java/seedu/fitnus/CSVWriter.java +++ b/src/main/java/seedu/fitnus/CSVWriter.java @@ -9,22 +9,16 @@ import java.util.Date; public class CSVWriter { - private static CSVReader csvreader = new CSVReader(); - public static void main(String[] args) { - writeIntoFile("Chicken Rice", "FOOD"); + writeIntoFile("hi", "FOOD"); } public static void writeIntoFile(String foodItem, String fileName) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); File file = null; - String readFromFile = ""; if (fileName.toLowerCase().contains("food")) { - file = new File("./tp/db/Output_Food_" + df.format(new Date())+".csv"); - readFromFile += "./tp/db//Meal_db.csv"; + file = new File("./db/Output_Food_" + df.format(new Date())+".csv"); } else { - file = new File("./tp/db/Output_Drink_" + df.format(new Date())+".csv"); - readFromFile += "./tp/db//Drink_db.csv"; - + file = new File("./db/Output_Drink_" + df.format(new Date())+".csv"); } if (!file.exists()) { try{ @@ -35,14 +29,11 @@ public static void writeIntoFile(String foodItem, String fileName) { } try (FileWriter fw = new FileWriter(file)){ BufferedWriter writer = new BufferedWriter(fw); - writer.write(csvreader.readMealInfo(readFromFile, foodItem)); + writer.write(foodItem); writer.newLine(); writer.close(); } catch (IOException e) { - e.printStackTrace(); + System.out.println("error trying to add something into the file"); } } - public static void deleteFromFile(String foodItem, String fileName) { - - } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index df21fc5106..f98edd40eb 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -6,6 +6,7 @@ import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Meal; import seedu.fitnus.parser.Parser; +import seedu.fitnus.Water; import seedu.fitnus.storage.Storage; import seedu.fitnus.exception.IncompleteDeleteException; @@ -22,19 +23,15 @@ import java.io.FileNotFoundException; import java.io.IOException; -import java.text.SimpleDateFormat; import java.util.ArrayList; public class User { - public static final int RECOMMEND_WATER_INTAKE = 2600; - public static final int RECOMMEND_CALORIE_INTAKE = 2200; // list for today protected static ArrayList mealList; protected static ArrayList drinkList; protected static ArrayList waterList; protected static ArrayList exerciseList; - - // list for all dates except today + // list for all dates except today protected static ArrayList mealListAll; protected static ArrayList drinkListAll; protected static ArrayList waterListAll; @@ -278,7 +275,6 @@ public void handleMeal(String command) throws IncompleteMealException, Unregiste assert !mealList.isEmpty(): "failed to add meal"; System.out.println("Added " + servingSize + " serving of " + mealName); - csvWriter.writeIntoFile(mealName, "FOOD"); } public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, @@ -318,38 +314,6 @@ public void handleViewCalories() { caloriesCount -= exercise.getCaloriesBurnt(); } System.out.println("Total Calories: " + caloriesCount); - - long millis = System.currentTimeMillis(); - java.sql.Date date = new java.sql.Date(millis); - SimpleDateFormat dateFormat = new SimpleDateFormat("hh"); - - String currentFormattedDate = dateFormat.format(date); - int currentHour = Integer.parseInt(currentFormattedDate); - if(currentHour >= 0 && currentHour < 12) { - if (caloriesCount < RECOMMEND_CALORIE_INTAKE / 4 - 200 || Math.min(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4) == caloriesCount) { - System.out.println("Recommend eating more food. Your daily recommended calories intake by this time is 550 calories. You have: " + (RECOMMEND_CALORIE_INTAKE - caloriesCount) + "calories left!"); - } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE / 4 + 200 || Math.max(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4 + 200) == caloriesCount) { - System.out.println("Recommend eating less food. "); - } else { - System.out.println("Eating sufficient amount of calories by this time of day. Good job!"); - } - } else if (currentHour >= 12 && currentHour < 18) { - if (caloriesCount < RECOMMEND_CALORIE_INTAKE / 2 - 100 || Math.min(caloriesCount, RECOMMEND_WATER_INTAKE/2) == caloriesCount) { - System.out.println("Recommend eating more food. Your daily recommended calories intake by this time is 1100 calories. You have: " + (RECOMMEND_CALORIE_INTAKE - caloriesCount) + "calories left!"); - } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE / 4 + 200 || Math.max(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4 + 200) == caloriesCount) { - System.out.println("Recommend eating less food. "); - } else { - System.out.println("Eating sufficient amount of calories by this time of day. Good job!"); - } - } else { - if (caloriesCount < RECOMMEND_CALORIE_INTAKE - 100 || Math.min(caloriesCount, RECOMMEND_WATER_INTAKE/2) == caloriesCount) { - System.out.println("Recommend eating more food. Your daily recommended calories intake by this time is 1650 calories. You have: " + (RECOMMEND_CALORIE_INTAKE - caloriesCount) + "calories left!"); - } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE / 4 + 200 || Math.max(caloriesCount, RECOMMEND_CALORIE_INTAKE / 4 + 200) == caloriesCount) { - System.out.println("Recommend eating less food. "); - } else { - System.out.println("Eating sufficient amount of calories by this time of day. Good job! "); - } - } } public void handleViewCarbohydrates() { @@ -379,34 +343,7 @@ public void handleViewWaterIntake() { for (Water water: waterList) { waterIntake += water.getWater(); } - - System.out.println("Total water intake: " + waterIntake + " ml"); - // if current date time is more than half the day, user should have drank 400 ml of water, if not then print a statement that recommends the user to drink more wate - long millis = System.currentTimeMillis(); - java.sql.Date date = new java.sql.Date(millis); - SimpleDateFormat dateFormat = new SimpleDateFormat("hh"); - - String currentFormattedDate = dateFormat.format(date); - int currentHour = Integer.parseInt(currentFormattedDate); - if(currentHour >= 0 && currentHour < 12) { - if (waterIntake < RECOMMEND_WATER_INTAKE / 4 || Math.min(waterIntake, RECOMMEND_WATER_INTAKE / 4) == waterIntake) { - System.out.println("Recommend drinking more water. Your daily recommended water intake by this time is 650ml of water. You have: " + (RECOMMEND_WATER_INTAKE - waterIntake) + "ml left!"); - } else { - System.out.println("On track with water intake!"); - } - } else if (currentHour >= 12 && currentHour < 18) { - if (waterIntake < RECOMMEND_WATER_INTAKE / 2 || Math.min(waterIntake, RECOMMEND_WATER_INTAKE/2) == waterIntake) { - System.out.println("Recommend drinking more water. Your daily recommended water intake by this time is 400ml of water. You have: " + (RECOMMEND_WATER_INTAKE - waterIntake) + "ml left!"); - } else { - System.out.println("On track with water intake!"); - } - } else { - if (currentHour < RECOMMEND_WATER_INTAKE || Math.min(waterIntake, RECOMMEND_WATER_INTAKE/2) == waterIntake) { - System.out.println("Recommend drinking more water. Your daily recommended water intake by this time is 800ml of water. You have: " + (RECOMMEND_WATER_INTAKE - waterIntake) + "ml left!"); - } else { - System.out.println("On track with water intake!"); - } - } + System.out.println("Total water intake today: " + waterIntake + " ml"); } public void handleViewFiber() { From e3618ab2fbc18c54e7f302fd976c2ceee5243d01 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 2 Apr 2024 16:33:58 +0800 Subject: [PATCH 138/274] Edit recommendation feature ...edit existing recommendation feature by Tina --- src/main/java/seedu/fitnus/parser/Parser.java | 2 ++ src/main/java/seedu/fitnus/user/User.java | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 854d0a6fe6..7ba7d0280e 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -151,6 +151,8 @@ public void handleCommand(String command) { user.handleDeleteExercise(command); } else if (command.equals("clear")) { user.handleClear(); + } else if (command.equals("recommend")) { + user.handleRecommendations(); } else { throw new InvalidCommandException(); } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f98edd40eb..8d02f75582 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -26,6 +26,8 @@ import java.util.ArrayList; public class User { + public static final int RECOMMEND_WATER_INTAKE = 2600; + public static final int RECOMMEND_CALORIE_INTAKE = 2200; // list for today protected static ArrayList mealList; protected static ArrayList drinkList; @@ -736,4 +738,38 @@ public void handleCaloriesBurnt() { } System.out.println("Total calories burnt: " + caloriesBurnt); } + + public void handleRecommendations() { + int waterIntake = 0; + for (Water water: waterList) { + waterIntake += water.getWater(); + } + int waterDifference = RECOMMEND_WATER_INTAKE -waterIntake; + if (waterIntake < RECOMMEND_WATER_INTAKE) { + System.out.println("Recommend drinking more water. Please drink " + + waterDifference + " ml more water"); + } else { + System.out.println("Great! You are on track with the water intake!"); + } + System.out.println(" ~~~"); + int caloriesCount = 0; + for (Meal meal: mealList) { + caloriesCount += meal.getCalories(); + } + for (Drink drink: drinkList) { + caloriesCount += drink.getCalories(); + } + for (Exercise exercise: exerciseList) { + caloriesCount -= exercise.getCaloriesBurnt(); + } + int caloriesDifference = RECOMMEND_CALORIE_INTAKE - caloriesCount; + if (caloriesCount < RECOMMEND_CALORIE_INTAKE) { + System.out.println("Recommend eating more food. Please eat " + caloriesDifference + " more calories"); + } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE && caloriesCount < RECOMMEND_CALORIE_INTAKE + 200) { + System.out.println("Great! You are on track with the calorie intake!"); + } else { + System.out.println("You are " + -caloriesDifference + + " above the recommended calorie amount, consider exercising!"); + } + } } From 4f7b9dade0563e643f005e6709766b4fa36691e4 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Tue, 2 Apr 2024 16:59:53 +0800 Subject: [PATCH 139/274] Update DeveloperGuide --- docs/DeveloperGuide.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 38fe7f7e6b..69995e08e7 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -16,6 +16,18 @@ - Using a hashmap, access the data regarding the amount of calories burnt per hour for the given exercise and calculate the total calories burnt for the given duration. - Store the total calories burnt through exercise in the User class +### CSV Storage +- Create three CSV files for storing meal nutrients, drink nutrients, and exercise calories information. +- For each line in the CSV, parse the string with "," as the delimiter, with the first element being the name and the others being the nutrient/calories information +- Save each description name and nutrient/calories information in the corresponding hashmap (meal, drink, and exercise) to be used by other functions. + +### Saved Meal, Drink, Exercises Storage +- Each meal object in the meal list corresponds to a string with a format of `meal_name,serving_size,date` +- Each drink object in the drink list corresponds to a string with a format of `drink_name,volume,date` +- Each exercise object in the exercise list corresponds to a string with a format of `exercise_name,duration,intensity,date` +- To store, convert all objects (meal, drink, exercise) in the list into its corresponding string, then write the appended strings into a .txt file +- To retrieve, parse each string using "," as its delimiter and convert it into its corresponding objects, then add all the entries to the object list (mealList, drinkList, exerciseList) + ## Product scope ### Target user profile From b6618dac1cd735d7125de71e4af668fd991fd88c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:01:02 +0800 Subject: [PATCH 140/274] Add javadoc for User class --- src/main/java/seedu/fitnus/user/User.java | 250 +++++++++++++++++++++- 1 file changed, 247 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f98edd40eb..13f6d43dfb 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -25,6 +25,9 @@ import java.io.IOException; import java.util.ArrayList; +/** + * Handles all methods related to the user's meals, drinks and exercise. + */ public class User { // list for today protected static ArrayList mealList; @@ -55,6 +58,12 @@ public User(Storage mealStorage, Storage drinkStorage, Storage exerciseStorage, loadExercise(exerciseStorage); } + /** + * Loads any previously stored mealList from the user and + * adds the saved meals into the ArrayList mealListAll. + * + * @param mealStorage contains filePath and folderPath of where the saved meals are stored. + */ public void loadMeal(Storage mealStorage) { try { ArrayList mealStorageList = mealStorage.readFile(); @@ -80,6 +89,12 @@ public void loadMeal(Storage mealStorage) { } } + /** + * Loads any previously stored drinkList from the user and + * adds the saved drinks into the ArrayList drinkListAll. + * + * @param drinkStorage contains filePath and folderPath of where the saved drinks are stored. + */ public void loadDrink(Storage drinkStorage) { try { ArrayList drinkStorageList = drinkStorage.readFile(); @@ -115,6 +130,12 @@ public void loadDrink(Storage drinkStorage) { } } + /** + * Loads any previously stored exerciseList from the user and + * adds the saved exercises into the ArrayList exerciseListAll. + * + * @param exerciseStorage contains filePath and folderPath of where the saved exerciseList was stored. + */ public void loadExercise(Storage exerciseStorage) { try { ArrayList exerciseStorageList = exerciseStorage.readFile(); @@ -145,6 +166,11 @@ public void loadExercise(Storage exerciseStorage) { } } + /** + * Loads the file where pre-defined meals and their nutrient counts are stored. + * + * @param mealNutrientStorage contains filePath and folderPath of where the pre-defined meals are stored. + */ public void loadMealNutrient(Storage mealNutrientStorage) { try { ArrayList mealNutrientList = mealNutrientStorage.readFile(); @@ -166,6 +192,11 @@ public void loadMealNutrient(Storage mealNutrientStorage) { } } + /** + * Loads the file where pre-defined drinks and their nutrient counts are stored. + * + * @param drinkNutrientStorage contains filePath and folderPath of where the pre-defined drinks are stored. + */ public void loadDrinkNutrient(Storage drinkNutrientStorage) { try { ArrayList drinkNutrientList = drinkNutrientStorage.readFile(); @@ -186,6 +217,12 @@ public void loadDrinkNutrient(Storage drinkNutrientStorage) { } } + /** + * Loads the file where pre-defined exercises and the number of calories burnt per minute for + * respective intensities (HIGH, MEDIUM, LOW) are stored. + * + * @param exerciseCaloriesStorage contains filePath and folderPath of where the pre-defined exercises are stored. + */ public void loadExerciseCalories(Storage exerciseCaloriesStorage) { try { ArrayList exerciseCaloriesList = exerciseCaloriesStorage.readFile(); @@ -204,6 +241,12 @@ public void loadExerciseCalories(Storage exerciseCaloriesStorage) { } } + /** + * Saves the user's meals when the user exits the program. + * Meals from the current day is saved with the date into the .txt file. + * + * @param mealStorage contains filePath and folderPath of where the saved meals are stored. + */ public void saveMeal(Storage mealStorage) { for (Meal meal : mealListAll) { String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); @@ -220,6 +263,12 @@ public void saveMeal(Storage mealStorage) { } } + /** + * Saves the user's drinks when the user exits the program. + * MealDrinkss from the current day is saved with the date into the .txt file. + * + * @param drinkStorage contains filePath and folderPath of where the saved drinksList are stored. + */ public void saveDrink(Storage drinkStorage) { for (Water water : waterListAll) { String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); @@ -244,6 +293,12 @@ public void saveDrink(Storage drinkStorage) { } } + /** + * Saves the user's exercises when the user exits the program. + * Exercises from the current day is saved with the date into the .txt file. + * + * @param exerciseStorage contains filePath and folderPath of where the saved exerciseList are stored. + */ public void saveExercise(Storage exerciseStorage) { for (Exercise exercise : exerciseListAll) { String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," @@ -262,7 +317,14 @@ public void saveExercise(Storage exerciseStorage) { } } - + /** + * Adds a meal to the user's current mealList, based on what the user has eaten and the serving size consumed. + * + * @param command string inputted by the user, containing the meal they ate and its serving size + * @throws IncompleteMealException if the user did not comply with the required format + * @throws UnregisteredMealException if the user has inputted a meal that was not pre-defined + * @throws NegativeValueException if the provided serving size is a negative value + */ public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, NegativeValueException { Parser.parseMeal(command); @@ -277,6 +339,14 @@ public void handleMeal(String command) throws IncompleteMealException, Unregiste System.out.println("Added " + servingSize + " serving of " + mealName); } + /** + * Adds a drink to the user's current drinkList, based on what the user has drank and the serving size consumed. + * + * @param command string inputted by the user, containing the drink they consumed and its serving size + * @throws IncompleteDrinkException if the user did not comply with the required format + * @throws UnregisteredDrinkException if the user has inputted a drink that was not pre-defined + * @throws NegativeValueException if the provided serving size is a negative value + */ public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, NegativeValueException { Parser.parseDrink(command); @@ -302,6 +372,10 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis System.out.println("Added " + servingSize + " ml of " + drinkName); } + /** + * Prints the user's total calorie intake of the day. + * The method sums up the calories from meals and drinks, and subtracts calories burnt from exercise. + */ public void handleViewCalories() { int caloriesCount = 0; for (Meal meal: mealList) { @@ -316,6 +390,10 @@ public void handleViewCalories() { System.out.println("Total Calories: " + caloriesCount); } + /** + * Prints the user's total carbohydrate intake of the day. + * The method sums up the carbohydrates from meals and drinks. + */ public void handleViewCarbohydrates() { int carbohydratesCount = 0; for (Meal meal: mealList) { @@ -327,6 +405,10 @@ public void handleViewCarbohydrates() { System.out.println("Total Carbohydrates: " + carbohydratesCount + " grams"); } + /** + * Prints the user's total protein intake of the day. + * The method sums up the protein from meals and drinks. + */ public void handleViewProteins() { int proteinCount = 0; for (Meal meal: mealList) { @@ -338,6 +420,9 @@ public void handleViewProteins() { System.out.println("Total Proteins: " + proteinCount + " grams"); } + /** + * Prints the user's total water intake of the day. + */ public void handleViewWaterIntake() { int waterIntake = 0; for (Water water: waterList) { @@ -346,6 +431,10 @@ public void handleViewWaterIntake() { System.out.println("Total water intake today: " + waterIntake + " ml"); } + /** + * Prints the user's total fiber intake of the day. + * The method sums up the fiber from meals. + */ public void handleViewFiber() { int fibreCount = 0; for (Meal meal: mealList) { @@ -354,6 +443,10 @@ public void handleViewFiber() { System.out.println("Total Fiber: " + fibreCount + " grams"); } + /** + * Prints the user's total fat intake of the day. + * The method sums up the fat from meals and drinks. + */ public void handleViewFat() { int fatCount = 0; for (Meal meal: mealList) { @@ -365,6 +458,10 @@ public void handleViewFat() { System.out.println("Total Fat: " + fatCount + " grams"); } + /** + * Prints the user's total sugar intake of the day. + * The method sums up the sugar from meals and drinks. + */ public void handleViewSugar() { int sugarCount = 0; for (Meal meal: mealList) { @@ -376,6 +473,13 @@ public void handleViewSugar() { System.out.println("Total Sugar: " + sugarCount + " grams"); } + /** + * Prints all the meals in the mealListToPrint, + * inclusive of the serving size and date. + * + * @param startIndex starting integer value when printing the list, where startIndex >= 1 + * @param mealListToPrint arraylist containing the meals that should be printed + */ public void printMealList(int startIndex, ArrayList mealListToPrint) { for (int i = 0; i < mealListToPrint.size(); i++) { Meal currentMeal = mealListToPrint.get(i); @@ -384,6 +488,12 @@ public void printMealList(int startIndex, ArrayList mealListToPrint) { } } + /** + * Prints all the exercises in the exerciseListToPrint, + * inclusive of the duration, intensity and date. + * + * @param exerciseListToPrint arraylist containing the exercises that should be printed + */ public void printExerciseList(ArrayList exerciseListToPrint) { for (int i = 0; i < exerciseListToPrint.size(); i++) { Exercise currentExercise = exerciseListToPrint.get(i); @@ -392,6 +502,11 @@ public void printExerciseList(ArrayList exerciseListToPrint) { + " | date: " + currentExercise.getDate()); } } + + /** + * Handles when the user is listing the meals they have eaten today. + * Method first checks if the list is empty. + */ public void handleListMeals() { System.out.println("here's what you have eaten today"); if (mealList.isEmpty()) { @@ -401,6 +516,10 @@ public void handleListMeals() { } } + /** + * Handles when the user is listing all meals they have eaten, inclusive of previously saved meals. + * Method first checks if the list is empty. + */ public void handleListMealsAll() { System.out.println("here's what you have eaten so far"); if (mealListAll.isEmpty() && mealList.isEmpty()) { @@ -411,6 +530,14 @@ public void handleListMealsAll() { } } + /** + * Handles when the user is listing the meals they have eaten on a certain date. + * Method will first extract all meals that have this corresponding date, + * before printing. + * + * @param command string inputted by the user, containing the date of which they would like to list meals of + * @throws InvalidDateException if the date inputted by user is invalid + */ public void handleListMealsDate(String command) throws InvalidDateException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); @@ -432,6 +559,13 @@ public void handleListMealsDate(String command) throws InvalidDateException { } } + /** + * Prints all the drinks in the drinkListToPrint, + * inclusive of the volume consumed and date. + * + * @param startIndex starting integer value when printing the list, where startIndex >= 1 + * @param drinkListToPrint arraylist containing the drinks that should be printed + */ public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { for (int i = 0; i < drinkListToPrint.size(); i++) { Drink currentDrink = drinkListToPrint.get(i); @@ -440,6 +574,10 @@ public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { } } + /** + * Handles when the user is listing the drinks they have consumed today. + * Method first checks if the list is empty. + */ public void handleListDrinks() { System.out.println("here's what you have drank today"); int totalWater = 0; @@ -458,6 +596,10 @@ public void handleListDrinks() { } } + /** + * Handles when the user is listing all drinks they have consumed, inclusive of previously saved drinks. + * Method first checks if the list is empty. + */ public void handleListDrinksAll() { System.out.println("here's what you have drank so far"); int totalWater = 0; @@ -477,6 +619,14 @@ public void handleListDrinksAll() { } } + /** + * Handles when the user is listing the drinks they have consumed on a certain date. + * Method will first extract all drinks that have this corresponding date, + * before printing. + * + * @param command string inputted by the user, containing the date of which they would like to list drinks of + * @throws InvalidDateException if the date inputted by user is invalid + */ public void handleListDrinksDate(String command) throws InvalidDateException { String date = Parser.parseListDate(command); ArrayList drinkListDate = new ArrayList<>(); @@ -498,6 +648,10 @@ public void handleListDrinksDate(String command) throws InvalidDateException { } } + /** + * Handles when the user is listing the exercises they have done today. + * Method first checks if the list is empty. + */ public void handleListExercises() { System.out.println("here's the exercises you've done today"); if (exerciseList.isEmpty()) { @@ -507,6 +661,11 @@ public void handleListExercises() { } } + /** + * Handles when the user is listing all exercises they have done, inclusive of previously saved exercises. + * Method first checks if the list is empty. + */ + public void handleListExercisesAll() { System.out.println("here's the exercises you've done so far"); if (exerciseListAll.isEmpty() && exerciseList.isEmpty()) { @@ -519,6 +678,14 @@ public void handleListExercisesAll() { } } + /** + * Handles when the user is listing the exercises they have done on a certain date. + * Method will first extract all exercises that have this corresponding date, + * before printing. + * + * @param command string inputted by the user, containing the date of which they would like to list exercises of + * @throws InvalidDateException if the date inputted by user is invalid + */ public void handleListExercisesDate(String command) throws InvalidDateException { String date = Parser.parseListDate(command); ArrayList exercisesListDate = new ArrayList<>(); @@ -540,6 +707,10 @@ public void handleListExercisesDate(String command) throws InvalidDateException } } + /** + * Handles when the user is listing all meals and drinks they have inputted today. + * Method first checks if the lists is empty. + */ public void handleListEverything() { System.out.println("here's what you have consumed today"); if (drinkList.isEmpty() && mealList.isEmpty()) { @@ -557,6 +728,11 @@ public void handleListEverything() { handleListExercises(); } + /** + * Handles when the user is listing all meals and drinks they have inputted, + * inclusive of previously saved meals and drinks. + * Method first checks if the lists is empty. + */ public void handleListEverythingAll() { System.out.println("here's what you have consumed so far"); if (drinkListAll.isEmpty() && mealListAll.isEmpty() && drinkList.isEmpty() && mealList.isEmpty()) { @@ -576,6 +752,14 @@ public void handleListEverythingAll() { handleListExercisesAll(); } + /** + * Handles when the user is listing all meals and drinks they have consumed on a certain date. + * Method will first extract all meals and drinks that have this corresponding date, + * before printing. + * + * @param command string inputted by the user, containing the date of which they would like to list + * @throws InvalidDateException if the date inputted by user is invalid + */ public void handleListEverythingDate(String command) throws InvalidDateException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); @@ -616,6 +800,14 @@ public void handleListEverythingDate(String command) throws InvalidDateException handleListExercisesDate(command); } + /** + * Handles when the user would like to edit the serving size of a previously inputted meal. + * + * @param command string inputted by the user, containing the index of the meal to edit and the new serving size + * @throws InvalidListIndexException if the provided index is not a valid index in mealList + * @throws NegativeValueException if the provided serving size is a negative value + * @throws IncompleteEditException if the user did not comply with the required command format + */ public void handleEditMealServingSize(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 @@ -631,6 +823,14 @@ public void handleEditMealServingSize(String command) throws InvalidListIndexExc System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); } + /** + * Handles when the user would like to edit the serving size of a previously inputted drink. + * + * @param command string inputted by the user, containing the index of the drink to edit and the new serving size + * @throws InvalidListIndexException if the provided index is not a valid index in drinkList + * @throws NegativeValueException if the provided serving size is a negative value + * @throws IncompleteEditException if the user did not comply with the required command format + */ public void handleEditDrinkServingSize(String command) throws InvalidListIndexException, NegativeValueException, IncompleteEditException { Parser.parseEditDrink(command); @@ -646,8 +846,14 @@ public void handleEditDrinkServingSize(String command) throws InvalidListIndexEx System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } - public void handleEditWaterIntake(String command) throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { + /** + * Handles when the user would like to edit the total volume of the water they consumed today. + * + * @param command string inputted by the user, containing the new total volume of water + * @throws NegativeValueException if the provided serving size is a negative value + * @throws IncompleteEditException if the user did not comply with the required command format + */ + public void handleEditWaterIntake(String command) throws NegativeValueException, IncompleteEditException { Parser.parseEditWater(command); Date currentDate = new Date(); for (Water water: waterList) { @@ -658,6 +864,13 @@ public void handleEditWaterIntake(String command) throws InvalidListIndexExcepti System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } + /** + * Handles when the user would like to delete a previously inputted meal. + * + * @param command string inputted by the user, containing the index of the meal to delete + * @throws InvalidListIndexException if the provided index is not a valid index in mealList + * @throws IncompleteDeleteException if the user did not comply with the required command format + */ public void handleDeleteMeal(String command) throws InvalidListIndexException, IncompleteDeleteException { if (command.length() < 12) { throw new IncompleteDeleteException(); @@ -673,6 +886,13 @@ public void handleDeleteMeal(String command) throws InvalidListIndexException, I System.out.println("Removed " + mealName + " from meals"); } + /** + * Handles when the user would like to delete a previously inputted drink. + * + * @param command string inputted by the user, containing the index of the drink to delete + * @throws InvalidListIndexException if the provided index is not a valid index in drinkList + * @throws IncompleteDeleteException if the user did not comply with the required command format + */ public void handleDeleteDrink(String command) throws InvalidListIndexException, IncompleteDeleteException { if (command.length() < 13) { throw new IncompleteDeleteException(); @@ -688,6 +908,13 @@ public void handleDeleteDrink(String command) throws InvalidListIndexException, System.out.println("Removed " + drinkName + " from drinks"); } + /** + * Handles when the user would like to delete a previously inputted exercise. + * + * @param command string inputted by the user, containing the index of the exercise to delete + * @throws InvalidListIndexException if the provided index is not a valid index in exerciseList + * @throws IncompleteDeleteException if the user did not comply with the required command format + */ public void handleDeleteExercise(String command) throws InvalidListIndexException, IncompleteDeleteException { if (command.length() < 16) { throw new IncompleteDeleteException(); @@ -703,6 +930,16 @@ public void handleDeleteExercise(String command) throws InvalidListIndexExceptio System.out.println("Removed " + exerciseName + " from exercises done"); } + /** + * Adds an exercise to the user's current exerciseList, based on what exercise the user has done, + * its duration and intensity. + * + * @param command string inputted by the user, containing the exercise they have done, its duration and + * intensity. + * @throws IncompleteExerciseException if the user did not comply with the required format + * @throws UnregisteredExerciseException if the user has inputted an exercise that was not pre-defined + * @throws NegativeValueException if the provided exercise duration is a negative value + */ public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, NegativeValueException { Parser.parseExercise(command); @@ -716,6 +953,10 @@ public void handleExercise(String command) throws IncompleteExerciseException, U System.out.println("Tracked " + duration + " minutes of " + exerciseType); } + /** + * Handle when user would like to clear all entries from today. + * This includes all meals, drinks and exercise. + */ public void handleClear() { mealList.clear(); drinkList.clear(); @@ -729,6 +970,9 @@ public void handleClear() { System.out.println("All entries have been deleted"); } + /** + * Prints the number of calories the user has burnt today. + */ public void handleCaloriesBurnt() { int caloriesBurnt = 0; for (Exercise exercise: exerciseList) { From 18dbe8280b872559e12f3334b2176c31322e32a2 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:03:34 +0800 Subject: [PATCH 141/274] Add javadoc for handleRecommendations method --- src/main/java/seedu/fitnus/user/User.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 26011a2306..f13bb011bc 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -983,6 +983,10 @@ public void handleCaloriesBurnt() { System.out.println("Total calories burnt: " + caloriesBurnt); } + /** + * Handles when user would like to see what is recommended to them, + * only regarding the calorie and water intake. + */ public void handleRecommendations() { int waterIntake = 0; for (Water water: waterList) { @@ -990,8 +994,8 @@ public void handleRecommendations() { } int waterDifference = RECOMMEND_WATER_INTAKE -waterIntake; if (waterIntake < RECOMMEND_WATER_INTAKE) { - System.out.println("Recommend drinking more water. Please drink " + - waterDifference + " ml more water"); + System.out.println("We recommend drinking more water. Please drink " + + waterDifference + " ml more water to hit the daily water intake goal :)"); } else { System.out.println("Great! You are on track with the water intake!"); } @@ -1008,7 +1012,7 @@ public void handleRecommendations() { } int caloriesDifference = RECOMMEND_CALORIE_INTAKE - caloriesCount; if (caloriesCount < RECOMMEND_CALORIE_INTAKE) { - System.out.println("Recommend eating more food. Please eat " + caloriesDifference + " more calories"); + System.out.println("We recommend eating more food. Please eat " + caloriesDifference + " more calories"); } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE && caloriesCount < RECOMMEND_CALORIE_INTAKE + 200) { System.out.println("Great! You are on track with the calorie intake!"); } else { From c5fc0b77bad461c3e4a541fe4083ca02c78d0526 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:11:09 +0800 Subject: [PATCH 142/274] Add javadoc to Date and IntegerValidation classes --- src/main/java/seedu/fitnus/Date.java | 20 ++++++++++++++++++- .../fitnus/validator/IntegerValidation.java | 9 +++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/Date.java b/src/main/java/seedu/fitnus/Date.java index 1a8d600063..128b7727d8 100644 --- a/src/main/java/seedu/fitnus/Date.java +++ b/src/main/java/seedu/fitnus/Date.java @@ -3,10 +3,16 @@ import java.text.ParseException; import java.text.SimpleDateFormat; +/** + * Class that handles any references to the current date and time. + */ public class Date { - // reference: https://www.javatpoint.com/java-get-current-date private String currentDate; + /** + * Constructor that gets the current system date and formats it in the stated format. + * This date is then saved as a string. + */ public Date() { long millis = System.currentTimeMillis(); java.sql.Date date = new java.sql.Date(millis); @@ -17,10 +23,22 @@ public Date() { this.currentDate = formattedDate; } + /** + * Returns the current system date. + * + * @return current system date + */ public String getDate() { return currentDate; } + /** + * Returns true if the date inputted by the user is a valid date. + * The method verifies the day, month and year are in the correct range. + * + * @param date string containing the date to check if valid + * @return true if the date inputted by the user is a valid date. + */ public static boolean isValidDate(String date) { SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); dateFormat.setLenient(false); diff --git a/src/main/java/seedu/fitnus/validator/IntegerValidation.java b/src/main/java/seedu/fitnus/validator/IntegerValidation.java index c1778218f3..adf0feaf50 100644 --- a/src/main/java/seedu/fitnus/validator/IntegerValidation.java +++ b/src/main/java/seedu/fitnus/validator/IntegerValidation.java @@ -2,8 +2,17 @@ import seedu.fitnus.exception.NegativeValueException; +/** + * Validates whether an integer value complies with the condition stated. + */ public class IntegerValidation { + /** + * Validates whether the integer value is a positive integer. + * + * @param value integer value to check + * @throws NegativeValueException if the value is less than or equals to zero + */ public static void checkIntegerGreaterThanZero (int value) throws NegativeValueException { if (value <= 0) { throw new NegativeValueException(); From 539d9822d6b3e52ea9ecf148577ebca90b4fce5a Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Tue, 2 Apr 2024 17:12:57 +0800 Subject: [PATCH 143/274] Add documentation for Parser --- src/main/java/seedu/fitnus/parser/Parser.java | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 7ba7d0280e..18e45980d3 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -23,6 +23,9 @@ import seedu.fitnus.user.User; import seedu.fitnus.validator.IntegerValidation; +/** + * The Parser class is responsible for parsing user commands and delegating them to the appropriate classes for execution. + */ public class Parser { public static final int MIN_INTEGER_VALUE = -2147483648; public static final int MAX_INTEGER_VALUE = 2147483647; @@ -77,10 +80,20 @@ public class Parser { public static ExerciseIntensity exerciseIntensity; private User user; + /** + * Constructs a Parser object with the given User. + * + * @param user The User object to interact with. + */ public Parser(User user) { this.user = user; } + /** + * Parses the user command and executes the corresponding action. + * + * @param command The command entered by the user. + */ public void handleCommand(String command) { try { if (command.equals("help")) { @@ -198,6 +211,9 @@ public void handleCommand(String command) { } + /** + * Displays a list of valid commands and their formats. + */ public static void handleHelp() { System.out.println("here's all the valid commands i recognise: "); System.out.println("- Add a meal eaten: eat m/MEAL s/SERVING_SIZE"); @@ -237,6 +253,14 @@ public static void handleHelp() { System.out.println("- Exit the app: exit "); } + /** + * Parses a meal command string and extracts the meal description and size. + * + * @param command The command entered by the user. + * @throws IncompleteMealException If the meal command is incomplete. + * @throws UnregisteredMealException If the meal is not registered in the database. + * @throws NegativeValueException If a negative value is encountered. + */ public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException, NegativeValueException { if (!command.contains("m/") || !command.contains("s/")) { @@ -258,6 +282,14 @@ public static void parseMeal(String command) throws IncompleteMealException, Unr IntegerValidation.checkIntegerGreaterThanZero(mealSize); } + /** + * Parses the command for adding a drink. + * + * @param command The command entered by the user. + * @throws IncompleteDrinkException If the drink command is incomplete. + * @throws UnregisteredDrinkException If the drink is not registered in the database. + * @throws NegativeValueException If a negative value is encountered. + */ public static void parseDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, NegativeValueException { if (!command.contains("d/") || !command.contains("s/")) { @@ -280,6 +312,14 @@ public static void parseDrink(String command) throws IncompleteDrinkException, U IntegerValidation.checkIntegerGreaterThanZero(drinkSize); } + /** + * Parses the command for obtaining information about a meal. + * + * @param command The command entered by the user. + * @return The description of the meal. + * @throws UnregisteredMealException If the meal is not registered in the database. + * @throws IncompleteInfoException If the command is incomplete. + */ public static String parseInfoMeal(String command) throws UnregisteredMealException, IncompleteInfoException { int mealIndex = 9; if (command.length() < mealIndex + 1) { @@ -293,6 +333,14 @@ public static String parseInfoMeal(String command) throws UnregisteredMealExcept return infoMealDescription; } + /** + * Parses the command for obtaining information about an exercise. + * + * @param command The command entered by the user. + * @return The description of the exercise. + * @throws UnregisteredExerciseException If the exercise is not registered in the database. + * @throws IncompleteInfoException If the command is incomplete. + */ public static String parseInfoExercise(String command) throws UnregisteredExerciseException, IncompleteInfoException { int exerciseIndex = 13; @@ -306,6 +354,14 @@ public static String parseInfoExercise(String command) throws UnregisteredExerci return infoExerciseDescription; } + /** + * Parses the command for obtaining information about a drink. + * + * @param command The command entered by the user. + * @return The description of the drink. + * @throws UnregisteredDrinkException If the drink is not registered in the database. + * @throws IncompleteInfoException If the command is incomplete. + */ public static String parseInfoDrink(String command) throws UnregisteredDrinkException, IncompleteInfoException { int drinkIndex = 10; if (command.length() < drinkIndex + 1) { @@ -318,6 +374,13 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce return infoDrinkDescription; } + /** + * Parses the command for editing a meal. + * + * @param command The command entered by the user. + * @throws NegativeValueException If a negative value is encountered. + * @throws IncompleteEditException If the command is incomplete. + */ public static void parseEditMeal(String command) throws NegativeValueException, IncompleteEditException { int mealSizePosition = command.indexOf("s/"); if (mealSizePosition <= 9) { @@ -329,6 +392,13 @@ public static void parseEditMeal(String command) throws NegativeValueException, IntegerValidation.checkIntegerGreaterThanZero(editMealSize); } + /** + * Parses the command for editing a drink. + * + * @param command The command entered by the user. + * @throws NegativeValueException If a negative value is encountered. + * @throws IncompleteEditException If the command is incomplete. + */ public static void parseEditDrink(String command) throws NegativeValueException, IncompleteEditException { int drinkSizePosition = command.indexOf("s/"); if (drinkSizePosition <= 10) { @@ -340,6 +410,13 @@ public static void parseEditDrink(String command) throws NegativeValueException, IntegerValidation.checkIntegerGreaterThanZero(editDrinkSize); } + /** + * Parses the command for editing water intake. + * + * @param command The command entered by the user. + * @throws NegativeValueException If a negative value is encountered. + * @throws IncompleteEditException If the command is incomplete. + */ public static void parseEditWater(String command) throws NegativeValueException, IncompleteEditException { int waterSizePosition = command.indexOf("s/") + 2; if (waterSizePosition <= 1) { //-1 + 2 @@ -349,6 +426,11 @@ public static void parseEditWater(String command) throws NegativeValueException, IntegerValidation.checkIntegerGreaterThanZero(editWaterSize); } + /** + * Parses the data for storing meal information. + * + * @param data The data string to be parsed. + */ public static void parseMealStorage(String data) { String delimiter = ","; String[] arrayOfMealData = data.split(delimiter); @@ -357,6 +439,11 @@ public static void parseMealStorage(String data) { mealStorageDate = arrayOfMealData[2]; } + /** + * Parses the data for storing drink information. + * + * @param data The data string to be parsed. + */ public static void parseDrinkStorage(String data) { String delimiter = ","; String[] arrayOfDrinkData = data.split(delimiter); @@ -365,6 +452,11 @@ public static void parseDrinkStorage(String data) { drinkStorageDate = arrayOfDrinkData[2]; } + /** + * Parses the data for storing exercise information. + * + * @param data The data string to be parsed. + */ public static void parseExerciseStorage(String data) { String delimiter = ","; String[] arrayOfExerciseData = data.split(delimiter); @@ -374,6 +466,14 @@ public static void parseExerciseStorage(String data) { exerciseStorageDate = arrayOfExerciseData[3]; } + /** + * Parses the command for adding an exercise. + * + * @param command The command entered by the user. + * @throws IncompleteExerciseException If the exercise command is incomplete. + * @throws UnregisteredExerciseException If the exercise is not registered in the database. + * @throws NegativeValueException If a negative value is encountered. + */ public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, NegativeValueException { if (!command.contains("e/") || !command.contains("d/") || !command.contains("i/")) { @@ -404,6 +504,11 @@ public static void parseExercise(String command) throws IncompleteExerciseExcept } } + /** + * Parses the nutrient information for a meal. + * + * @param data The nutrient data string to be parsed. + */ public static void parseMealNutrient(String data) { String delimiter = ","; String[] arrayOfMealNutrient = data.split(delimiter); @@ -416,6 +521,11 @@ public static void parseMealNutrient(String data) { mealNutrientSugar = Integer.parseInt(arrayOfMealNutrient[6]); } + /** + * Parses the nutrient information for a drink. + * + * @param data The nutrient data string to be parsed. + */ public static void parseDrinkNutrient(String data) { String delimiter = ","; String[] arrayOfDrinkNutrient = data.split(delimiter); @@ -427,6 +537,11 @@ public static void parseDrinkNutrient(String data) { drinkNutrientFat = Integer.parseInt(arrayOfDrinkNutrient[5]); } + /** + * Parses the calorie information for an exercise. + * + * @param data The calorie data string to be parsed. + */ public static void parseExerciseCalories(String data) { String delimiter = ","; String[] arrayOfExerciseCalories = data.split(delimiter); @@ -436,6 +551,13 @@ public static void parseExerciseCalories(String data) { exerciseCaloriesLow = Integer.parseInt(arrayOfExerciseCalories[3]); } + /** + * Parses the date from a command string. + * + * @param command The command entered by the user. + * @return The parsed date string. + * @throws InvalidDateException If the date format is invalid. + */ public static String parseListDate(String command) throws InvalidDateException { int indexOfDate = command.indexOf("d/") + 2; String date = command.substring(indexOfDate); From 52bb67c545b8f9c33de664b2b7e8902b7a278278 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:18:05 +0800 Subject: [PATCH 144/274] Add documentation for FitNUS, UI and Water class --- src/main/java/seedu/fitnus/FitNus.java | 4 +++- src/main/java/seedu/fitnus/Ui.java | 16 ++++++++++++++-- src/main/java/seedu/fitnus/Water.java | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/FitNus.java b/src/main/java/seedu/fitnus/FitNus.java index 53372a00e1..c2a91af478 100644 --- a/src/main/java/seedu/fitnus/FitNus.java +++ b/src/main/java/seedu/fitnus/FitNus.java @@ -8,7 +8,9 @@ public FitNus() { ui = new Ui(); } - /** Runs the program until termination. */ + /** + * Begins the program until termination. + */ public void run() { ui.printWelcomeMessage(); while (!ui.isExit) { diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 9bc76c5c3b..f1a290619b 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -9,7 +9,6 @@ public class Ui { public static final String LINE = "_________________________________________________________________"; static Scanner input = new Scanner(System.in); - /** Specifies whether user has input the exit command */ public boolean isExit = false; private Storage mealStorage = new Storage("./data", "./data/MealList.txt"); @@ -22,7 +21,10 @@ public class Ui { mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); private Parser parser = new Parser(user); - /** Prints the welcome message upon the start of the application */ + /** + * Prints the welcome message upon the start of the application, + * including all pre-defined meals, drinks and exercises. + * */ public void printWelcomeMessage() { System.out.println(LINE); System.out.println("Hello! Welcome to FitNUS"); @@ -33,6 +35,10 @@ public void printWelcomeMessage() { System.out.println(LINE); } + /** + * Prints the goodbye message when the user exits the program. + * The lists for meal, drink and exercise would be stores before exiting. + */ public void handleExit() { System.out.println("Bye. Hope to see you again soon!"); input.close(); @@ -42,10 +48,16 @@ public void handleExit() { user.saveExercise(exerciseStorage); } + /** + * Prints the divider line between messages. + */ public static void showLine() { System.out.println(LINE); } + /** + * Reads the user's input into command line. + */ public void readCommand() { String command = input.nextLine(); showLine(); diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/Water.java index 1c147443b3..7eccdeb358 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/Water.java @@ -16,18 +16,38 @@ public Water(int amount, String dateAdded) { this.dateAdded = dateAdded; } + /** + * Returns the user's water intake of the day. + * + * @return total water intake of the day + */ public int getWater() { return waterIntake; } + /** + * Add a specified amount of water to the user's waterIntake of the day. + * + * @param amount volume of water to add to intake. + */ public void addWaterIntake(int amount) { waterIntake += amount; } + /** + * Updates the total water intake of the day. + * + * @param amount volume specified by user to be the new total water intake of the day + */ public void editWaterIntake(int amount) { waterIntake = amount; } + /** + * Returns the date of which the water was added into drinkList. + * + * @return date of which the water was added into drinkList + */ public String getDate() { return dateAdded; } From f8172f24f63f04ef2189c3b6f6f041876e465aa1 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:32:38 +0800 Subject: [PATCH 145/274] Fix checkstyle error in Parser --- src/main/java/seedu/fitnus/parser/Parser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 18e45980d3..c0e0a2a6fe 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -24,7 +24,8 @@ import seedu.fitnus.validator.IntegerValidation; /** - * The Parser class is responsible for parsing user commands and delegating them to the appropriate classes for execution. + * The Parser class is responsible for parsing user commands and + * delegating them to the appropriate classes for execution. */ public class Parser { public static final int MIN_INTEGER_VALUE = -2147483648; From 032f0e63cdac50a25dc09837064c4534852d5cff Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 2 Apr 2024 17:46:58 +0800 Subject: [PATCH 146/274] Update user guide --- docs/DeveloperGuide.md | 18 ++++- docs/UserGuide.md | 73 ++++++++++++++----- src/main/java/seedu/fitnus/parser/Parser.java | 1 + src/main/java/seedu/fitnus/user/User.java | 2 +- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 69995e08e7..6a7dce3a24 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -39,7 +39,7 @@ ### Value proposition The fitness app aims to help users manage their dietary habits and exercise routines more efficiently compared to traditional GUI-driven apps. -By offering a streamlined interface optimized for keyboard input and CLI interactions, users can track their meals, drinks, and exercises swiftly, allowing them to focus more on their fitness goals and less on navigating through complex user interfaces. +By offering a streamlined interface optimized for keyboard input and CLI interactions, users can track their meals, drinks, and exercises swiftly, allowing them to focus more on their fitness and nutritional goals and less on navigating through complex user interfaces. ## User Stories @@ -50,7 +50,7 @@ By offering a streamlined interface optimized for keyboard input and CLI interac ## Non-Functional Requirements -1. Should work on any mainstream OS as long as it has Java 11 or above installed. +1. Should work on any mainstream OS (Linux, Windows, MacOS) as long as it has Java 11 or above installed. 2. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. ## Glossary @@ -68,5 +68,15 @@ By offering a streamlined interface optimized for keyboard input and CLI interac ## 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 to test the app on your own device. +### Launch and Shutdown +1. Initial Launch + 1. Create an empty folder, download the jar file, and place the file inside the folder. + 2. Open the terminal and navigate to the folder you just created. + 3. Type `java -jar [name of the jar]`, e.g.`(java -jar FitNUS.jar)` on the CLI. +2. Window Preference + 1. Resize the window to an optimum size. Ideally full screen, as some text might not be displayed correctly. +3. App Features and Commands +4. Save and Shutdown + 1. Type `exit` to shut down the FitNUS app. + 2. Upon exiting, all entries inputted will be updated to the database locally. diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 709cc87acd..c63599b017 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,9 +1,9 @@ # User Guide: FitNUS ## Project Introduction FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and -carbohydrates. Promote healthy lifestyle. +carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. -Users are able to track the meals and drinks they have in a day. +Users are able to track the meals, drinks, and exercises they have in a day and even past records. ## Table of Contents @@ -30,6 +30,7 @@ Users are able to track the meals and drinks they have in a day. * [1.3.9 View daily fiber consumed: `fiber`](#139-view-daily-fiber-consumed-fiber) * [1.3.10 View daily water consumption: `viewWater`](#1310-view-daily-water-consumption-viewwater) * [1.3.11 View daily calories consumed: `caloriesBurnt`](#1311-view-daily-calories-consumed-caloriesburnt) + * [1.3.12 View daily calories and water intake recommendation: `recommend`](#1312-view-daily-calories-and-water-intake-recommendation-recommend) * [1.4 For listing arrays](#14-for-listing-arrays) * [1.4.1 List today's meal intake: `listMeals`](#141-list-todays-meal-intake-listmeals) * [1.4.2 List today's drink intake: `listDrinks`](#142-list-todays-drink-intake-listdrinks) @@ -78,6 +79,7 @@ here's all the valid commands I recognise: - View daily fiber consumed: fiber - View daily water consumption: viewWater - View daily calories burnt: caloriesBurnt +- View daily calories and water intake recommendation: recommend - List today's meal intake: listMeals - List today's drink intake: listDrinks - List today's exercises done: listExercises @@ -243,6 +245,16 @@ Display current total calorie burnt for the day Total calories burnt: 70 ~~~ +### 1.3.12 View daily calories and water intake recommendation: `recommend` +Display today's recommended water and calories intake +**Format**: `recommend` +**Expected output**: +~~~ +Great! You are on track with the water intake! + ~~ +Recommend eating more food. Please eat 500 more calories +~~~ + ## 1.4 For listing arrays ### 1.4.1 List today's meal intake: `listMeals` Display all the meals user input today @@ -394,42 +406,63 @@ here's the exercises you've done on 01-04-2024 ## 1.5 For editing existing data ### 1.5.1 Edit an existing meal after inserted: `editMeal` For a meal that was inputted in the day, edit its serving size -**Format**: editMealServingSize INDEX s/NEW_SERVING_SIZE -**Sample input**: editMeal 2 s/2 -**Expected output**: Pizza has been edited to 2 servings +**Format**: `editMeal INDEX s/NEW_SERVING_SIZE` +**Sample input**: `editMeal 2 s/2` +**Expected output**: +~~~ +Pizza has been edited to 2 servings +~~~ ### 1.5.2 Edit an existing drink after inserted: `editDrink` For a drink that was inputted in the day, edit its serving size -**Format**: editDrinkServingSize INDEX s/NEW_SERVING_SIZE +**Format**: `editDrink INDEX s/NEW_SERVING_SIZE` **Sample input**: editDrink 1 s/200 -**Expected output**: Sprite has been edited to 200 ml +**Expected output**: +~~~ +Sprite has been edited to 200 ml +~~~ ### 1.5.3 Edit water intake after inserted: `editWater` Edit serving size of total water intake -**Format**: editWaterIntake s/TOTAL_WATER_INTAKE -**Sample input**: editWaterIntake 200 -**Expected output**: Total water has been edited to 200 ml +**Format**: `editWater s/TOTAL_WATER_INTAKE` +**Sample input**: `editWater 200` +**Expected output**: +~~~ +Total water has been edited to 200 ml +~~~ ## 1.6 For deleting data ### 1.6.1 Delete certain meal entry: `deleteMeal` For a meal that was inputted in the day, delete its input based on its index in the meal list -**Format**: deleteMeal INDEX -**Sample Input**: deleteMeal 1 -**Expected output**: Removed Chicken Rice From Meals +**Format**: `deleteMeal INDEX` +**Sample Input**: `deleteMeal 1` +**Expected output**: +~~~ +Removed Chicken Rice From Meals +~~~ ### 1.6.2 Delete certain drink entry: `deleteDrink` For a drink that was inputted in the day, delete its input based on its index in the drink list -**Format**: deleteDrink INDEX -**Sample input**: deleteDrink 1 -**Expected output:** Removed Iced Lemon Tea From Drinks +**Format**: `deleteDrink INDEX` +**Sample input**: `deleteDrink 1` +**Expected output:** +~~~ +Removed Iced Lemon Tea From Drinks +~~~ ## 1.7 For clearing data ### 1.7.1 Clear all entries: `clear` Clear all entries in mealList and drinkList -**Format**: clear -**Expected output**: All entries have been deleted +**Format**: `clear` +**Expected output**: +~~~ +All entries have been deleted +~~~ ## 1.8: Exit program ### 1.8.1 Exit the app: `exit` -**Format**: exit -**Expected output**: Bye. Hope to see you again soon! +**Format**: `exit` +**Expected output**: +~~~ +Bye. Hope to see you again soon! +~~~ diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index c0e0a2a6fe..74fcef7788 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -232,6 +232,7 @@ public static void handleHelp() { System.out.println("- View daily fiber consumed: fiber"); System.out.println("- View daily water consumption: viewWater"); System.out.println("- View daily calories burnt: caloriesBurnt"); + System.out.println("- View daily calories and water intake recommendation: recommend"); System.out.println("- List today's meal intake: listMeals"); System.out.println("- List today's drink intake: listDrinks"); System.out.println("- List today's exercises done: listExercises"); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f13bb011bc..eeb5d22e49 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -999,7 +999,7 @@ public void handleRecommendations() { } else { System.out.println("Great! You are on track with the water intake!"); } - System.out.println(" ~~~"); + System.out.println(" ~~"); int caloriesCount = 0; for (Meal meal: mealList) { caloriesCount += meal.getCalories(); From 8c656495f74ba8c3fed6b7f55088e374c5f9525b Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:52:08 +0800 Subject: [PATCH 147/274] Add methods where user can view a list of pre-defined meals, drinks or exercises --- src/main/java/seedu/fitnus/Drink.java | 9 +++++++++ src/main/java/seedu/fitnus/Exercise.java | 9 +++++++++ src/main/java/seedu/fitnus/Meal.java | 9 +++++++++ src/main/java/seedu/fitnus/parser/Parser.java | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index d6ce811bb3..4ecd295706 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -63,6 +63,15 @@ public static void printAvailableDrinks() { System.out.println(); } + public static void listAvailableDrinks() { + System.out.println("Available drinks: "); + for (String drink : nutrientDetails.keySet()) { + System.out.println("- " + drink); + } + System.out.println(); + System.out.println("You may also input a drink that isn't here."); + } + public String getName() { return name; } diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index df66bc8f53..25276890e9 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -101,6 +101,15 @@ public static void printAvailableExercises() { System.out.println(); } + public static void listAvailableExercises() { + System.out.println("Available exercises: "); + for (String exercise : exerciseDetails.keySet()) { + System.out.println("- " + exercise); + } + System.out.println(); + System.out.println("You may also input an exercise that isn't here."); + } + public static HashMap getExerciseDetails() { return exerciseDetails; } diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 2aa963dd92..5da6362551 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -97,6 +97,15 @@ public static void printAvailableMeals() { System.out.println(); } + public static void listAvailableMeals() { + System.out.println("Available meals: "); + for (String meal : nutrientDetails.keySet()) { + System.out.println("- " + meal); + } + System.out.println(); + System.out.println("You may also input a meal that isn't here."); + } + public static HashMap getNutrientDetails() { return nutrientDetails; } diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 74fcef7788..ecc3848268 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -105,6 +105,12 @@ public void handleCommand(String command) { user.handleDrink(command); } else if (command.startsWith("exercise")) { user.handleExercise(command); + } else if (command.startsWith("allMeals")) { + Meal.listAvailableMeals(); + } else if (command.startsWith("allDrinks")) { + Drink.listAvailableDrinks(); + } else if (command.startsWith("allExercises")) { + Exercise.listAvailableExercises(); } else if (command.startsWith("infoMeal")) { Meal.handleInfoMeal(command); } else if (command.startsWith("infoDrink")) { From f6b9b456111b5d9b6f0884dedcea2b416d7eccd8 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:52:45 +0800 Subject: [PATCH 148/274] Update help command with new methods --- src/main/java/seedu/fitnus/parser/Parser.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index ecc3848268..18cffdec4b 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -227,6 +227,9 @@ public static void handleHelp() { System.out.println("- Add a drink: drink d/DRINK s/VOLUME(ML)"); System.out.println("- Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) " + "i/INTENSITY(HIGH, MEDIUM, LOW)"); + System.out.println("- View all meals that you can input: allMeals"); + System.out.println("- View all drinks that you can input: allDrinks"); + System.out.println("- View all exercises that you can input: allExercises"); System.out.println("- Find the information about a certain meal: infoMeal MEAL"); System.out.println("- Find the information about a certain drink: infoDrink DRINK"); System.out.println("- Find the information about a certain exercise: infoExercise EXERCISE"); From 5893460330215548f900eb3edd6612938ebe9327 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 17:53:34 +0800 Subject: [PATCH 149/274] Update UserGuide --- docs/UserGuide.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index c63599b017..8c60f31088 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -59,15 +59,18 @@ Users are able to track the meals, drinks, and exercises they have in a day and ## 1) Features List ### 1.1 Information for users -### 1.1.1 Viewing all commands:** `help` +### 1.1.1 Viewing all commands: `help` Shows a list of all possible command inputs. **Format**: help **Sample Input**: help **Expected Output**: -here's all the valid commands I recognise: +here's all the valid commands i recognise: - Add a meal eaten: eat m/MEAL s/SERVING_SIZE - Add a drink: drink d/DRINK s/VOLUME(ML) - Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, LOW) +- View all meals that you can input: allMeals +- View all drinks that you can input: allDrinks +- View all exercises that you can input: allExercises - Find the information about a certain meal: infoMeal MEAL - Find the information about a certain drink: infoDrink DRINK - Find the information about a certain exercise: infoExercise EXERCISE @@ -79,7 +82,6 @@ here's all the valid commands I recognise: - View daily fiber consumed: fiber - View daily water consumption: viewWater - View daily calories burnt: caloriesBurnt -- View daily calories and water intake recommendation: recommend - List today's meal intake: listMeals - List today's drink intake: listDrinks - List today's exercises done: listExercises @@ -87,7 +89,7 @@ here's all the valid commands I recognise: - List all meal intake: listMealsAll - List all drink intake: listDrinksAll - List all exercises done: listExercisesAll -- List all entire food intake and exercises: listEverythingAll +- List all food intake and exercises: listEverythingAll - List meal intake for certain date: listMeals d/dd-MM-yyyy - List drink intake for certain date: listDrinks d/dd-MM-yyyy - List exercises done for certain date: listExercises d/dd-MM-yyyy @@ -101,6 +103,21 @@ here's all the valid commands I recognise: - Clear all entries: clear - Exit the app: exit +### 1.1.2 Viewing all pre-defined meals: `allMeals` +Shows a list of all pre-defined meals. These meals will have their nutritional content defined per serving size and can +be inputted immediately. +**Format**: allMeals + +### 1.1.3 Viewing all pre-defined drinks: `allDrinks` +Shows a list of all pre-defined drinks. These drinks will have their nutritional content defined per 100ml +and can be inputted immediately. +**Format**: allDrinks + +### 1.1.3 Viewing all pre-defined exercises: `allExercises` +Shows a list of all pre-defined exercises. These exercises will have the number of calories burnt for a +high/medium/low intensity workout defined per minute and can be inputted immediately. +**Format**: allExercises + ### 1.2 For user to add data ### 1.2.1 Add a meal eaten: `eat` Adds a meal to the list of meals From 7ba816a4d56b8ad806a99b9ef89326ee1a64c6e5 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Tue, 2 Apr 2024 18:03:50 +0800 Subject: [PATCH 150/274] Add more test to ParserTest --- src/main/java/seedu/fitnus/parser/Parser.java | 3 +- .../java/seedu/fitnus/parser/ParserTest.java | 146 +++++++++++++++--- 2 files changed, 130 insertions(+), 19 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 18e45980d3..38548550f0 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -24,7 +24,8 @@ import seedu.fitnus.validator.IntegerValidation; /** - * The Parser class is responsible for parsing user commands and delegating them to the appropriate classes for execution. + * The Parser class is responsible for parsing user commands and delegating + * them to the appropriate classes for execution. */ public class Parser { public static final int MIN_INTEGER_VALUE = -2147483648; diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 1cbdbbeea2..86f964f0bc 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -8,6 +8,10 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.ExerciseIntensity; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -24,15 +28,6 @@ public void parseMeal_validInputs_success() throws IncompleteMealException, Unre assertEquals(1, Parser.mealSize); } - @Test - public void parseEditMeal_validInputs_success() throws IncompleteEditException, NegativeValueException { - String command = "editMeal 3 s/120"; - Parser.parseEditMeal(command); - // Meal list starts from 1, however the array index starts from 0, hence the n - 1 - assertEquals(2, Parser.editMealIndex); - assertEquals(120, Parser.editMealSize); - } - @Test public void parseDrink_validInputs_success() throws IncompleteDrinkException, UnregisteredDrinkException, NegativeValueException { @@ -42,15 +37,6 @@ public void parseDrink_validInputs_success() throws IncompleteDrinkException, Un assertEquals(300, Parser.drinkSize); } - @Test - public void parseEditDrink_validInputs_success() throws IncompleteEditException, NegativeValueException { - String command = "editDrink 1 s/500"; - Parser.parseEditDrink(command); - // Drink list starts from 1, however the array index starts from 0, hence the n - 1 - assertEquals(0, Parser.editDrinkIndex); - assertEquals(500, Parser.editDrinkSize); - } - @Test public void parseInfoMeal_unregisteredMeal_exceptionThrown() throws IncompleteInfoException { String command = "infoMeal blablabla"; @@ -61,6 +47,44 @@ public void parseInfoMeal_unregisteredMeal_exceptionThrown() throws IncompleteIn } } + @Test + public void parseInfoExercise_unregisteredExercise_exceptionThrown() throws IncompleteInfoException { + String command = "infoExercise blabla"; + try { + String infoExercise = Parser.parseInfoExercise(command); + } catch (UnregisteredExerciseException e) { + assertTrue(true); + } + } + + @Test + public void parseInfoDrink_unregisteredDrink_exceptionThrown() throws IncompleteInfoException { + String command = "infoDrink blabla"; + try { + String infoDrink = Parser.parseInfoDrink(command); + } catch (UnregisteredDrinkException e) { + assertTrue(true); + } + } + + @Test + public void parseEditMeal_validInputs_success() throws IncompleteEditException, NegativeValueException { + String command = "editMeal 3 s/120"; + Parser.parseEditMeal(command); + // Meal list starts from 1, however the array index starts from 0, hence the n - 1 + assertEquals(2, Parser.editMealIndex); + assertEquals(120, Parser.editMealSize); + } + + @Test + public void parseEditDrink_validInputs_success() throws IncompleteEditException, NegativeValueException { + String command = "editDrink 1 s/500"; + Parser.parseEditDrink(command); + // Drink list starts from 1, however the array index starts from 0, hence the n - 1 + assertEquals(0, Parser.editDrinkIndex); + assertEquals(500, Parser.editDrinkSize); + } + @Test public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NegativeValueException { String command = "editDrink s/100"; @@ -71,4 +95,90 @@ public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NegativeVal } } + @Test + public void parseEditWater_validInputs_success() throws IncompleteEditException, NegativeValueException { + String command = "editWater s/500"; + Parser.parseEditWater(command); + assertEquals(500, Parser.editWaterSize); + } + + @Test + public void parseMealStorage_validInputs_success() { + String data = "chicken rice,1,12-02-2024"; + Parser.parseMealStorage(data); + assertEquals("chicken rice", Parser.mealStorageDescription); + assertEquals(1, Parser.mealStorageSize); + assertEquals("12-02-2024", Parser.mealStorageDate); + } + + @Test + public void parseDrinkStorage_validInputs_success() { + String data = "milo,200,12-02-2024"; + Parser.parseDrinkStorage(data); + assertEquals("milo", Parser.drinkStorageDescription); + assertEquals(200, Parser.drinkStorageSize); + assertEquals("12-02-2024", Parser.drinkStorageDate); + } + + @Test + public void parseExerciseStorage_validInputs_success() { + String data = "cycling,100,LOW,29-02-2024"; + Parser.parseExerciseStorage(data); + assertEquals("cycling", Parser.exerciseStorageDescription); + assertEquals(100, Parser.exerciseStorageDuration); + assertEquals(ExerciseIntensity.LOW, Parser.exerciseStorageIntensity); + assertEquals("29-02-2024", Parser.exerciseStorageDate); + } + + @Test + public void parseExercise_validInputs_success() throws IncompleteExerciseException, NegativeValueException, + UnregisteredExerciseException { + String command = "exercise e/cycling d/100 i/LOW"; + Parser.parseExercise(command); + assertEquals("cycling", Parser.exerciseDescription); + assertEquals(100, Parser.exerciseDuration); + assertEquals(ExerciseIntensity.LOW, Parser.exerciseIntensity); + } + + @Test + public void parseMealNutrient_validInputs_success() { + String data = "fried rice,100,10,9,8,7,6"; + Parser.parseMealNutrient(data); + assertEquals("fried rice", Parser.mealNutrientDescription); + assertEquals(100, Parser.mealNutrientCalories); + assertEquals(10, Parser.mealNutrientCarbs); + assertEquals(9, Parser.mealNutrientProtein); + assertEquals(8, Parser.mealNutrientFat); + assertEquals(7, Parser.mealNutrientFiber); + assertEquals(6, Parser.mealNutrientSugar); + } + + @Test + public void parseDrinkNutrient_validInputs_success() { + String data = "Guava Juice,143,38,10,9,5"; + Parser.parseDrinkNutrient(data); + assertEquals("guava juice", Parser.drinkNutrientDescription); + assertEquals(143, Parser.drinkNutrientCalories); + assertEquals(38, Parser.drinkNutrientCarbs); + assertEquals(10, Parser.drinkNutrientSugar); + assertEquals(9, Parser.drinkNutrientProtein); + assertEquals(5, Parser.drinkNutrientFat); + } + + @Test + public void parseExerciseCalories_validInputs_success() { + String data = "Running,14,10,7"; + Parser.parseExerciseCalories(data); + assertEquals("running", Parser.exerciseCaloriesDescription); + assertEquals(14, Parser.exerciseCaloriesHigh); + assertEquals(10, Parser.exerciseCaloriesMedium); + assertEquals(7, Parser.exerciseCaloriesLow); + } + + @Test + public void parseListDate_validInputs_success() throws InvalidDateException { + String command = "listMeals d/12-02-2024"; + String date = Parser.parseListDate(command); + assertEquals("12-02-2024", date); + } } From 7a264194d91bee9d7d40fc0013f5a53db999f938 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 18:20:54 +0800 Subject: [PATCH 151/274] Add documentation for Drink and Meal --- src/main/java/seedu/fitnus/Drink.java | 64 +++++++++++++++++++++++++ src/main/java/seedu/fitnus/Meal.java | 68 +++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 4ecd295706..a0258101c7 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -17,6 +17,14 @@ public class Drink { private int protein; private int fat; + /** + * Constructor for a Drink, requires the name and volume of the drink, + * as well as date that it is added into the list. + * + * @param name name of drink to be added into the list + * @param volume volume of the drink to be added into the list + * @param currentDate date of which the drink is added into list + */ public Drink(String name, int volume, String currentDate) { assert name != null: "Name must not be null"; this.name = name; @@ -41,6 +49,15 @@ private void setNutrientValues(String name) { protein = nutrients[3] * drinkVolume / 100; fat = nutrients[4] * drinkVolume / 100; } + + /** + * Handles when user would like to find out the information about a certain drink. + * Prints out all nutritional content of the drink. + * + * @param command string inputted by user, containing drink to be viewed + * @throws UnregisteredDrinkException if drink specified is not a pre-defined drink + * @throws IncompleteInfoException if the user did not comply with the required format + */ public static void handleInfoDrink(String command) throws UnregisteredDrinkException, IncompleteInfoException { String name = Parser.parseInfoDrink(command); int[] nutrients = nutrientDetails.get(name); @@ -53,6 +70,10 @@ public static void handleInfoDrink(String command) throws UnregisteredDrinkExcep System.out.println("Fat: " + nutrients[4]); } + /** + * Prints out all pre-defined drinks in one line, + * only called when the user first enters the program. + */ public static void printAvailableDrinks() { System.out.print("Available drinks: "); for (String drink : nutrientDetails.keySet()) { @@ -63,6 +84,9 @@ public static void printAvailableDrinks() { System.out.println(); } + /** + * Prints out all pre-defined drinks in a list. + */ public static void listAvailableDrinks() { System.out.println("Available drinks: "); for (String drink : nutrientDetails.keySet()) { @@ -72,30 +96,65 @@ public static void listAvailableDrinks() { System.out.println("You may also input a drink that isn't here."); } + /** + * Returns a string stating the name of the drink. + * + * @return string stating the name of the drink + */ public String getName() { return name; } + /** + * Returns an integer value of the volume of the drink. + * + * @return an integer value of the volume of the drink + */ public int getDrinkVolumeSize() { return drinkVolume; } + /** + * Returns an integer value of the amount of calories in the drink. + * + * @return an integer value of the amount of calories in the drink + */ public int getCalories() { return calories; } + /** + * Returns an integer value of the amount of carbohydrates in the drink. + * + * @return an integer value of the amount of carbohydrates in the drink + */ public int getCarbs() { return carbs; } + /** + * Returns an integer value of the amount of sugar in the drink. + * + * @return an integer value of the amount of sugar in the drink + */ public int getSugar() { return sugar; } + /** + * Returns an integer value of the amount of protein in the drink. + * + * @return an integer value of the amount of protein in the drink + */ public int getProtein() { return protein; } + /** + * Returns an integer value of the amount of fat in the drink. + * + * @return an integer value of the amount of fat in the drink + */ public int getFat() { return fat; } @@ -104,6 +163,11 @@ public static HashMap getNutrientDetails() { return nutrientDetails; } + /** + * Returns the date of which the drink was added into drinkList. + * + * @return date of which the drink was added into drinkList + */ public String getDate() { return dateAdded; } diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 5da6362551..9f8f6fca3b 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -18,6 +18,14 @@ public class Meal { private int fiber; private int sugar; + /** + * Constructor for a Meal, requires the name and serving size of the meal, + * as well as date that it is added into the list. + * + * @param name name of meal to be added into the list + * @param servingSize serving size of the meal to be added into the list + * @param currentDate date of which the meal is added into list + */ public Meal(String name, int servingSize, String currentDate) { assert name != null : "Name must not be null"; this.name = name; @@ -43,38 +51,86 @@ private void setNutrientValues(String name) { sugar = nutrients[5] * servingSize; } + /** + * Returns a string stating the name of the meal. + * + * @return string stating the name of the meal + */ public String getName() { return name; } + /** + * Returns an integer value of the amount of calories in the meal. + * + * @return an integer value of the amount of calories in the meal + */ public int getCalories() { return calories; } + /** + * Returns an integer value of the amount of carbohydrates in the meal. + * + * @return an integer value of the amount of carbohydrates in the meal + */ public int getCarbs() { return carbs; } + /** + * Returns an integer value of the amount of protein in the meal. + * + * @return an integer value of the amount of protein in the meal + */ public int getProtein() { return protein; } + /** + * Returns an integer value of the amount of fat in the meal. + * + * @return an integer value of the amount of fat in the meal + */ public int getFat() { return fat; } + /** + * Returns an integer value of the amount of fiber in the meal. + * + * @return an integer value of the amount of fiber in the meal + */ public int getFiber() { return fiber; } + /** + * Returns an integer value of the amount of sugar in the meal. + * + * @return an integer value of the amount of sugar in the meal + */ public int getSugar() { return sugar; } + /** + * Returns an integer value of the serving size of the meal. + * + * @return an integer value of the serving size of the meal + */ public int getServingSize() { return servingSize; } + /** + * Handles when user would like to find out the information about a certain meal. + * Prints out all nutritional content of the meal. + * + * @param command string inputted by user, containing meal to be viewed + * @throws UnregisteredMealException if meal specified is not a pre-defined meal + * @throws IncompleteInfoException if the user did not comply with the required format + */ public static void handleInfoMeal(String command) throws UnregisteredMealException, IncompleteInfoException { String name = Parser.parseInfoMeal(command); int[] nutrients = nutrientDetails.get(name); @@ -87,6 +143,10 @@ public static void handleInfoMeal(String command) throws UnregisteredMealExcepti System.out.println("Sugar: " + nutrients[5]); } + /** + * Prints out all pre-defined meals in one line, + * only called when the user first enters the program. + */ public static void printAvailableMeals() { System.out.print("Available meals: "); for (String meal : nutrientDetails.keySet()) { @@ -97,6 +157,9 @@ public static void printAvailableMeals() { System.out.println(); } + /** + * Prints out all pre-defined meals in a list. + */ public static void listAvailableMeals() { System.out.println("Available meals: "); for (String meal : nutrientDetails.keySet()) { @@ -110,6 +173,11 @@ public static HashMap getNutrientDetails() { return nutrientDetails; } + /** + * Returns the date of which the meal was added into mealList. + * + * @return date of which the meal was added into mealList + */ public String getDate() { return dateAdded; } From b7aa975a0a88388cfaf565872fc0a46730478226 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 18:27:02 +0800 Subject: [PATCH 152/274] Add documentation for exercise --- src/main/java/seedu/fitnus/Exercise.java | 73 ++++++++++++++++++++---- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index 25276890e9..a0be350572 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -14,6 +14,15 @@ public class Exercise { private int caloriesBurnt; private String dateAdded; + /** + * Constructor for an Exercise, requires the name, duration and intensity of the exercise, + * as well as date that it is added into the list. + * + * @param name name of exercise to be added into the list + * @param duration duration of the exercise to be added into the list + * @param intensity intensity of the exercise to be added into the list, can be HIGH/MEDIUM/LOW + * @param currentDate date of which the exercise is added into list + */ public Exercise(String name, int duration, ExerciseIntensity intensity, String currentDate) throws UnregisteredExerciseException { assert name != null : "Name must not be null"; @@ -32,6 +41,11 @@ public Exercise(String name, int duration, ExerciseIntensity intensity, String c exerciseDetails.put("swimming", new int[]{10, 7, 4}); } + /** + * Calculate the number of calories burnt from the exercise. + * + * @throws UnregisteredExerciseException if specified exercise is not pre-defined. + */ private void setCaloriesBurnt() throws UnregisteredExerciseException { int[] details = exerciseDetails.get(name); if (details == null) { @@ -40,43 +54,71 @@ private void setCaloriesBurnt() throws UnregisteredExerciseException { this.caloriesBurnt = duration * details[intensity.ordinal()]; } + /** + * Returns true if the exercise intensity specified is valid, + * following the ExerciseIntensity enum. + * + * @param intensity intensity of exercise, only can be a value of high/medium/low + * @return true if the exercise intensity specified is valid + */ private boolean isValidIntensity(ExerciseIntensity intensity) { return intensity == ExerciseIntensity.HIGH || intensity == ExerciseIntensity.MEDIUM || intensity == ExerciseIntensity.LOW; } + /** + * Returns a string stating the name of the exercise. + * + * @return string stating the name of the exercise + */ public String getName() { return name; } + /** + * Returns an integer value of the duration of the exercise. + * + * @return an integer value of the duration of the exercise + */ public int getDuration() { return duration; } + /** + * Returns the intensity of the exercise. + * + * @return the intensity of the exercise + */ public ExerciseIntensity getIntensity() { return intensity; } + /** + * Returns the date of which the exercise was added into exerciseList. + * + * @return date of which the exercise was added into exerciseList + */ public String getDate() { return dateAdded; } - public void setName(String name) { - this.name = name; - } - - public void setDuration(int duration) { - this.duration = duration; - } - - public void setIntensity(ExerciseIntensity intensity) { - this.intensity = intensity; - } - + /** + * Returns an integer value of the amount of calories burnt from the exercise. + * + * @return an integer value of the amount of calories burnt from the exercise + */ public int getCaloriesBurnt() { return caloriesBurnt; } + /** + * Handles when user would like to find out the information about a certain exercise. + * Prints out the calories burnt for 1 minute of the workout. + * + * @param command string inputted by user, containing exercise to be viewed + * @throws UnregisteredExerciseException if exercise specified is not a pre-defined exercise + * @throws IncompleteInfoException if the user did not comply with the required format + */ public static void handleInfoExercise(String command) throws UnregisteredExerciseException, IncompleteInfoException { String name = Parser.parseInfoExercise(command); @@ -91,6 +133,10 @@ public static void handleInfoExercise(String command) throws UnregisteredExercis System.out.println("LOW intensity: " + details[2]); } + /** + * Prints out all pre-defined exercises in one line, + * only called when the user first enters the program. + */ public static void printAvailableExercises() { System.out.print("Available exercises: "); for (String exercise : exerciseDetails.keySet()) { @@ -101,6 +147,9 @@ public static void printAvailableExercises() { System.out.println(); } + /** + * Prints out all pre-defined exercises in a list. + */ public static void listAvailableExercises() { System.out.println("Available exercises: "); for (String exercise : exerciseDetails.keySet()) { From 9c1e37123c33cf5a0594e8a0cb8f254e499f7952 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 18:31:49 +0800 Subject: [PATCH 153/274] Add documentations to exception classes --- .../seedu/fitnus/exception/IncompleteDeleteException.java | 4 ++++ .../java/seedu/fitnus/exception/IncompleteDrinkException.java | 4 ++++ .../java/seedu/fitnus/exception/IncompleteEditException.java | 4 ++++ .../seedu/fitnus/exception/IncompleteExerciseException.java | 4 ++++ .../java/seedu/fitnus/exception/IncompleteInfoException.java | 4 ++++ .../java/seedu/fitnus/exception/IncompleteMealException.java | 4 ++++ .../java/seedu/fitnus/exception/InvalidCommandException.java | 4 ++++ .../java/seedu/fitnus/exception/InvalidDateException.java | 4 ++++ .../seedu/fitnus/exception/InvalidListIndexException.java | 4 ++++ .../java/seedu/fitnus/exception/NegativeValueException.java | 4 ++++ .../seedu/fitnus/exception/UnregisteredDrinkException.java | 4 ++++ .../seedu/fitnus/exception/UnregisteredExerciseException.java | 4 ++++ .../seedu/fitnus/exception/UnregisteredMealException.java | 4 ++++ 13 files changed, 52 insertions(+) diff --git a/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java b/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java index 61d2aff02b..ad44965d4f 100644 --- a/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteDeleteException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the user did not comply with the required format for delete. + * Class is inherited from Exception. + */ public class IncompleteDeleteException extends Exception { } diff --git a/src/main/java/seedu/fitnus/exception/IncompleteDrinkException.java b/src/main/java/seedu/fitnus/exception/IncompleteDrinkException.java index 8bbd175165..ccea3df7ae 100644 --- a/src/main/java/seedu/fitnus/exception/IncompleteDrinkException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteDrinkException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the user did not comply with the required format to add a drink. + * Class is inherited from Exception. + */ public class IncompleteDrinkException extends Exception{ } diff --git a/src/main/java/seedu/fitnus/exception/IncompleteEditException.java b/src/main/java/seedu/fitnus/exception/IncompleteEditException.java index 013e3361aa..ba76f2e48d 100644 --- a/src/main/java/seedu/fitnus/exception/IncompleteEditException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteEditException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the user did not comply with the required format to edit a saved object. + * Class is inherited from Exception. + */ public class IncompleteEditException extends Exception { } diff --git a/src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java b/src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java index cbd0327434..7355df7fe3 100644 --- a/src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteExerciseException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the user did not comply with the required format to add an exercise. + * Class is inherited from Exception. + */ public class IncompleteExerciseException extends Exception{ } diff --git a/src/main/java/seedu/fitnus/exception/IncompleteInfoException.java b/src/main/java/seedu/fitnus/exception/IncompleteInfoException.java index 73cf489f1b..eb4d55d478 100644 --- a/src/main/java/seedu/fitnus/exception/IncompleteInfoException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteInfoException.java @@ -1,5 +1,9 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the user did not comply with the required format to view the info of a object. + * Class is inherited from Exception. + */ public class IncompleteInfoException extends Exception { } diff --git a/src/main/java/seedu/fitnus/exception/IncompleteMealException.java b/src/main/java/seedu/fitnus/exception/IncompleteMealException.java index 36cecf5d8e..f609c4ef52 100644 --- a/src/main/java/seedu/fitnus/exception/IncompleteMealException.java +++ b/src/main/java/seedu/fitnus/exception/IncompleteMealException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the user did not comply with the required format to add a meal. + * Class is inherited from Exception. + */ public class IncompleteMealException extends Exception{ } diff --git a/src/main/java/seedu/fitnus/exception/InvalidCommandException.java b/src/main/java/seedu/fitnus/exception/InvalidCommandException.java index 957702a9ea..c7674f5544 100644 --- a/src/main/java/seedu/fitnus/exception/InvalidCommandException.java +++ b/src/main/java/seedu/fitnus/exception/InvalidCommandException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the user inputs an unrecognised command. + * Class is inherited from Exception. + */ public class InvalidCommandException extends Exception{ } diff --git a/src/main/java/seedu/fitnus/exception/InvalidDateException.java b/src/main/java/seedu/fitnus/exception/InvalidDateException.java index 7315da5911..a1c2791fd1 100644 --- a/src/main/java/seedu/fitnus/exception/InvalidDateException.java +++ b/src/main/java/seedu/fitnus/exception/InvalidDateException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the date is invalid. + * Class is inherited from Exception. + */ public class InvalidDateException extends Exception{ } diff --git a/src/main/java/seedu/fitnus/exception/InvalidListIndexException.java b/src/main/java/seedu/fitnus/exception/InvalidListIndexException.java index a52ed8c25c..be7e5ed6d4 100644 --- a/src/main/java/seedu/fitnus/exception/InvalidListIndexException.java +++ b/src/main/java/seedu/fitnus/exception/InvalidListIndexException.java @@ -1,5 +1,9 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the index is not a valid index in the list. + * Class is inherited from Exception. + */ public class InvalidListIndexException extends Exception { } diff --git a/src/main/java/seedu/fitnus/exception/NegativeValueException.java b/src/main/java/seedu/fitnus/exception/NegativeValueException.java index 04415347b8..94d3dc65b0 100644 --- a/src/main/java/seedu/fitnus/exception/NegativeValueException.java +++ b/src/main/java/seedu/fitnus/exception/NegativeValueException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the integer is a non-positive value. + * Class is inherited from Exception. + */ public class NegativeValueException extends Exception { } diff --git a/src/main/java/seedu/fitnus/exception/UnregisteredDrinkException.java b/src/main/java/seedu/fitnus/exception/UnregisteredDrinkException.java index 92c1e52f28..cf589cd251 100644 --- a/src/main/java/seedu/fitnus/exception/UnregisteredDrinkException.java +++ b/src/main/java/seedu/fitnus/exception/UnregisteredDrinkException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the specified drink is not pre-defined. + * Class is inherited from Exception. + */ public class UnregisteredDrinkException extends Exception{ } diff --git a/src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java b/src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java index d43b8f2480..798d140be3 100644 --- a/src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java +++ b/src/main/java/seedu/fitnus/exception/UnregisteredExerciseException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the specified exercise is not pre-defined. + * Class is inherited from Exception. + */ public class UnregisteredExerciseException extends Exception { } diff --git a/src/main/java/seedu/fitnus/exception/UnregisteredMealException.java b/src/main/java/seedu/fitnus/exception/UnregisteredMealException.java index 0748dbb1a8..1f38a8ef36 100644 --- a/src/main/java/seedu/fitnus/exception/UnregisteredMealException.java +++ b/src/main/java/seedu/fitnus/exception/UnregisteredMealException.java @@ -1,4 +1,8 @@ package seedu.fitnus.exception; +/** + * Exception class thrown when the specified meal is not pre-defined. + * Class is inherited from Exception. + */ public class UnregisteredMealException extends Exception{ } From 9adbf149baaa4ccec63505cbdcd3e19c6fd5717b Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 18:44:59 +0800 Subject: [PATCH 154/274] Configure github pages theme --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000000..2f7efbeab5 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-minimal \ No newline at end of file From c8ccc2d9f3c1a8b671491c2a61913ba7f259b682 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 19:00:14 +0800 Subject: [PATCH 155/274] Fix bug where user inputs command in the wrong order --- src/main/java/seedu/fitnus/parser/Parser.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 5e8a4155c4..3947721fde 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -179,11 +179,11 @@ public void handleCommand(String command) { } catch (InvalidCommandException e) { System.out.println("Invalid command, type [help] to view all commands."); } catch (IncompleteDrinkException e) { - System.out.println("Incomplete command, the format must be [drink d/DRINK s/SERVING_SIZE]."); + System.out.println("Incomplete/Incorrect command, the format MUST be [drink d/DRINK s/SERVING_SIZE]."); } catch (IncompleteMealException e) { - System.out.println("Incomplete command, the format must be [eat m/MEAL s/SERVING_SIZE]."); + System.out.println("Incomplete/Incorrect command, the format MUST be [eat m/MEAL s/SERVING_SIZE]."); } catch (IncompleteExerciseException e) { - System.out.println("Incomplete command, the format must be [exercise e/EXERCISE d/DURATION i/INTENSITY].\n" + System.out.println("Incomplete/Incorrect command, the format MUST be [exercise e/EXERCISE d/DURATION i/INTENSITY].\n" + " > DURATION should be in minutes and INTENSITY can only be HIGH/MEDIUM/LOW."); } catch (UnregisteredDrinkException e) { System.out.println("Sorry that drink is not registered in the database.Please check the spelling and " + @@ -279,9 +279,11 @@ public static void parseMeal(String command) throws IncompleteMealException, Unr } int descriptionIndex = command.indexOf("m/") + 2; int sizeIndex = command.indexOf("s/") + 2; - if (sizeIndex >= command.length()) { + + if (sizeIndex >= command.length() || sizeIndex < descriptionIndex) { throw new IncompleteMealException(); } + mealDescription = command.substring(descriptionIndex, sizeIndex - 2).trim().toLowerCase(); if (mealDescription.isEmpty()) { throw new IncompleteMealException(); @@ -308,7 +310,7 @@ public static void parseDrink(String command) throws IncompleteDrinkException, U } int descriptionIndex = command.indexOf("d/") + 2; int sizeIndex = command.indexOf("s/") + 2; - if (sizeIndex >= command.length()) { + if (sizeIndex >= command.length() || sizeIndex < descriptionIndex) { throw new IncompleteDrinkException(); } drinkDescription = command.substring(descriptionIndex, sizeIndex - 2).trim().toLowerCase(); @@ -493,7 +495,8 @@ public static void parseExercise(String command) throws IncompleteExerciseExcept int descriptionIndex = command.indexOf("e/") + 2; int durationIndex = command.indexOf("d/") + 2; int intensityIndex = command.indexOf("i/") + 2; - if (intensityIndex >= command.length()) { + if (intensityIndex >= command.length() || durationIndex < descriptionIndex || intensityIndex < descriptionIndex + || intensityIndex < durationIndex) { throw new IncompleteExerciseException(); } exerciseDescription = command.substring(descriptionIndex, durationIndex - 2).trim().toLowerCase(); From ef684bf506e06a987eefe5207508aacfece130ca Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 19:03:58 +0800 Subject: [PATCH 156/274] Fix handleCommand --- src/main/java/seedu/fitnus/parser/Parser.java | 6 +++--- src/main/java/seedu/fitnus/user/User.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 3947721fde..478e7e341c 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -105,11 +105,11 @@ public void handleCommand(String command) { user.handleDrink(command); } else if (command.startsWith("exercise")) { user.handleExercise(command); - } else if (command.startsWith("allMeals")) { + } else if (command.equals("allMeals")) { Meal.listAvailableMeals(); - } else if (command.startsWith("allDrinks")) { + } else if (command.equals("allDrinks")) { Drink.listAvailableDrinks(); - } else if (command.startsWith("allExercises")) { + } else if (command.equals("allExercises")) { Exercise.listAvailableExercises(); } else if (command.startsWith("infoMeal")) { Meal.handleInfoMeal(command); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index eeb5d22e49..6749301d8b 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -1017,7 +1017,7 @@ public void handleRecommendations() { System.out.println("Great! You are on track with the calorie intake!"); } else { System.out.println("You are " + -caloriesDifference - + " above the recommended calorie amount, consider exercising!"); + + " calories above the recommended calorie amount, consider exercising!"); } } } From 6a8d4ec2ec7c206654719ea6c0d86bb4e4743426 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Tue, 2 Apr 2024 19:07:04 +0800 Subject: [PATCH 157/274] Fix checkstyle error --- src/main/java/seedu/fitnus/parser/Parser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 478e7e341c..e478a8c489 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -183,7 +183,8 @@ public void handleCommand(String command) { } catch (IncompleteMealException e) { System.out.println("Incomplete/Incorrect command, the format MUST be [eat m/MEAL s/SERVING_SIZE]."); } catch (IncompleteExerciseException e) { - System.out.println("Incomplete/Incorrect command, the format MUST be [exercise e/EXERCISE d/DURATION i/INTENSITY].\n" + System.out.println("Incomplete/Incorrect command, " + + "the format MUST be [exercise e/EXERCISE d/DURATION i/INTENSITY].\n" + " > DURATION should be in minutes and INTENSITY can only be HIGH/MEDIUM/LOW."); } catch (UnregisteredDrinkException e) { System.out.println("Sorry that drink is not registered in the database.Please check the spelling and " + From 4d50784a840a673c1601a63a2d0fc90d8879c964 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 2 Apr 2024 19:56:00 +0800 Subject: [PATCH 158/274] Update user guide --- docs/UserGuide.md | 86 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 8c60f31088..0ba6d25fb8 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -63,7 +63,8 @@ Users are able to track the meals, drinks, and exercises they have in a day and Shows a list of all possible command inputs. **Format**: help **Sample Input**: help -**Expected Output**: +**Expected Output**: +~~~ here's all the valid commands i recognise: - Add a meal eaten: eat m/MEAL s/SERVING_SIZE - Add a drink: drink d/DRINK s/VOLUME(ML) @@ -102,21 +103,100 @@ here's all the valid commands i recognise: - Delete certain exercise entry: deleteExercise INDEX - Clear all entries: clear - Exit the app: exit - +~~~ ### 1.1.2 Viewing all pre-defined meals: `allMeals` Shows a list of all pre-defined meals. These meals will have their nutritional content defined per serving size and can be inputted immediately. -**Format**: allMeals +**Format**: `allMeals` +**Expected Output**: +~~~ +Available meals: +- char kway teow +- ban mian +- tau huay +- nasi goreng +- soup kambeng +- nasi lemak +- pepper lunch +- char siew rice +- pork satay with satay sauce +- roti prata +- mee goreng +- chendol +- wanton mee +- oyster omlette +- pizza +- ice kachang +- chicken rice +- fried rice +- kaya toast +- mala +- laksa +- hokkien prawn mee +- durian + +You may also input a meal that isn't here. +~~~ ### 1.1.3 Viewing all pre-defined drinks: `allDrinks` Shows a list of all pre-defined drinks. These drinks will have their nutritional content defined per 100ml and can be inputted immediately. **Format**: allDrinks +**Expected Output**: +~~~ +Available drinks: +- milo dinosaur +- chrysanthemun juice +- honey lemon tea +- soursop juice +- lemon tea +- kopi c +- kalamansi juice +- kopi o +- milo +- plum juice +- water +- 100 plus +- milk coffee +- teh c bing +- kopi +- guava juice +- tiger beer +- teh tarik +- sugarcane juice +- teh +- sprite +- iced lemon tea +- bandung + +You may also input a drink that isn't here. +~~~ ### 1.1.3 Viewing all pre-defined exercises: `allExercises` Shows a list of all pre-defined exercises. These exercises will have the number of calories burnt for a high/medium/low intensity workout defined per minute and can be inputted immediately. **Format**: allExercises +**Expected Output**: +~~~ +Available exercises: +- soccer +- rugby +- yoga +- badminton +- hiking +- cycling +- tennis +- running +- weightlifting +- swimming +- basketball +- rowing +- boxing +- volleyball +- skipping + +You may also input an exercise that isn't here. +~~~ ### 1.2 For user to add data ### 1.2.1 Add a meal eaten: `eat` From 2d45725d973b6aca53f162b0f0374b16e9803266 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Tue, 2 Apr 2024 19:58:09 +0800 Subject: [PATCH 159/274] Update user guide --- docs/UserGuide.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 0ba6d25fb8..506bdcd6d7 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -61,8 +61,7 @@ Users are able to track the meals, drinks, and exercises they have in a day and ### 1.1 Information for users ### 1.1.1 Viewing all commands: `help` Shows a list of all possible command inputs. -**Format**: help -**Sample Input**: help +**Format**: `help` **Expected Output**: ~~~ here's all the valid commands i recognise: From 70edbabb57bd3147979d668c775d89d38c7fad8b Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 20:09:34 +0800 Subject: [PATCH 160/274] Add newMeal and newDrink feature Adds new meal to available meals and new drink to available drinks --- db/Drink_db.csv | 39 +++---- db/Meal_db.csv | 44 ++++---- src/main/java/seedu/fitnus/Drink.java | 7 -- src/main/java/seedu/fitnus/Meal.java | 6 -- src/main/java/seedu/fitnus/Ui.java | 2 + src/main/java/seedu/fitnus/parser/Parser.java | 83 +++++++++++--- src/main/java/seedu/fitnus/user/User.java | 102 +++++++++++++++--- 7 files changed, 199 insertions(+), 84 deletions(-) diff --git a/db/Drink_db.csv b/db/Drink_db.csv index e978823846..7cea40c5af 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -1,19 +1,20 @@ -Teh C Bing,231,24,15,1,1 -Teh,151,29,4,1,1 -Kopi,141,26,2,3,1 -Milo,124,20,3,3,1 -Milo Dinosaur,270,42,7,8,2 -Sugarcane juice ,192,52,0,0,1 -Bandung,153,32,1,2,1 -Teh Tarik,124,21,3,3,0 -100 plus,72,18,0,0,0 -Tiger Beer,42,3,1,0,0 -Kopi O,67,15,1,0,0 -Kopi C,117,20,1,4,0 -Iced Lemon Tea,95,21,1,1,1 -Honey Lemon Tea,134,36,2,0,0 -Soursop Juice ,117,25,3,1,1 -Kalamansi Juice,168,42,0,0,1 -Chrysanthemun Juice ,12,2,3,1,0 -Guava Juice ,143,38,0,0,1 -Plum Juice ,57,13,1,0,1 \ No newline at end of file +milo dinosaur,270,42,7,8,2 +chrysanthemun juice,12,2,3,1,0 +honey lemon tea,134,36,2,0,0 +soursop juice,117,25,3,1,1 +kopi c,117,20,1,4,0 +kalamansi juice,168,42,0,0,1 +kopi o,67,15,1,0,0 +milo,124,20,3,3,1 +plum juice,57,13,1,0,1 +100 plus,72,18,0,0,0 +teh c bing,231,24,15,1,1 +kopi,141,26,2,3,1 +guava juice,143,38,0,0,1 +tiger beer,42,3,1,0,0 +teh tarik,124,21,3,3,0 +sugarcane juice,192,52,0,0,1 +teh,151,29,4,1,1 +iced lemon tea,95,21,1,1,1 +bandung,153,32,1,2,1 + diff --git a/db/Meal_db.csv b/db/Meal_db.csv index e8b89e4989..4dff766b0e 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,21 +1,23 @@ -Chicken Rice,607,75,25,23,2,10 -Char Kway Teow,744,76,23,29,7,10 -Laksa,377,71,18,2,4,10 -Hokkien Prawn Mee,522,69,18,19,4,10 -Kaya Toast,459,44,8,27,10,1 -Mee Goreng,500,61,18,20,4,5 -Char Siew Rice,605,91,24,16,6,10 -Nasi lemak,494,80,13,14,6,5 -roti prata ,209,32,5,7,2,10 -Pork Satay with Satay Sauce ,36,1,5,2,10,0 -Nasi Goreng,346,45,13,12,10,2 -Wanton Mee,555,97,15,14,13,10 -Mala ,583,72,12,30,10,7 -Oyster Omlette ,467,40,19,24,10,1 -Pepper lunch ,500,50,40,11,4,5 -Ban Mian,475,48,22,22,3,10 -Soup Kambeng,203,6,28,7,2,5 -Durian,147,27,2,5,3,5 -Ice KaChang,257,58,6,1,10,2 -Tau Huay,153,32,14,1,5,1 -Chendol,386,59,6,15,7,2 \ No newline at end of file +char kway teow,744,76,23,29,7,10 +ban mian,475,48,22,22,3,10 +tau huay,153,32,14,1,5,1 +nasi goreng,346,45,13,12,10,2 +babi kecap,607,75,25,23,2,10 +soup kambeng,203,6,28,7,2,5 +nasi lemak,494,80,13,14,6,5 +pepper lunch,500,50,40,11,4,5 +char siew rice,605,91,24,16,6,10 +pork satay with satay sauce,36,1,5,2,10,0 +roti prata,209,32,5,7,2,10 +mee goreng,500,61,18,20,4,5 +chendol,386,59,6,15,7,2 +wanton mee,555,97,15,14,13,10 +oyster omlette,467,40,19,24,10,1 +ice kachang,257,58,6,1,10,2 +chicken rice,607,75,25,23,2,10 +kaya toast,459,44,8,27,10,1 +mala,583,72,12,30,10,7 +laksa,377,71,18,2,4,10 +hokkien prawn mee,522,69,18,19,4,10 +durian,147,27,2,5,3,5 + diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index d6ce811bb3..dcafdcab34 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -26,13 +26,6 @@ public Drink(String name, int volume, String currentDate) { this.dateAdded = currentDate; } - static { - nutrientDetails.put("water", new int[]{0, 0, 0, 0, 0}); - nutrientDetails.put("sprite", new int[]{40, 50, 30, 20, 2}); - nutrientDetails.put("lemon tea", new int[]{150, 30, 25, 1, 20}); - nutrientDetails.put("milk coffee", new int[]{20, 27, 25, 4, 3}); - } - private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); calories = nutrients[0] * drinkVolume / 100; diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index 2aa963dd92..5046d38ada 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -27,12 +27,6 @@ public Meal(String name, int servingSize, String currentDate) { this.dateAdded = currentDate; } - static { - nutrientDetails.put("chicken rice", new int[]{400, 50, 30, 20, 10, 5}); - nutrientDetails.put("fried rice", new int[]{500, 60, 25, 15, 20, 3}); - nutrientDetails.put("pizza", new int[]{600, 70, 20, 25, 30, 2}); - } - private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); calories = nutrients[0] * servingSize; diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 9bc76c5c3b..242a2b9f28 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -40,6 +40,8 @@ public void handleExit() { user.saveMeal(mealStorage); user.saveDrink(drinkStorage); user.saveExercise(exerciseStorage); + user.saveMealNutrients(mealNutrientStorage); + user.saveDrinkNutrients(drinkNutrientStorage); } public static void showLine() { diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 616b0f61ba..bc214c9a89 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -91,6 +91,10 @@ public void handleCommand(String command) { user.handleDrink(command); } else if (command.startsWith("exercise")) { user.handleExercise(command); + } else if (command.startsWith("newMeal")) { + user.handleAddNewMealNutrient(command); + } else if (command.startsWith("newDrink")) { + user.handleAddNewDrinkNutrient(command); } else if (command.startsWith("infoMeal")) { Meal.handleInfoMeal(command); } else if (command.startsWith("infoDrink")) { @@ -192,6 +196,8 @@ public void handleCommand(String command) { System.out.println("Your serving size/exercise duration must be at least 0!"); } catch (InvalidDateException e) { System.out.println("Invalid date provided. Your date must be in the format of dd-MM-yyyy."); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); } } @@ -231,6 +237,10 @@ public static void handleHelp() { System.out.println("- Delete certain meal entry: deleteMeal INDEX"); System.out.println("- Delete certain drink entry: deleteDrink INDEX"); System.out.println("- Delete certain exercise entry: deleteExercise INDEX"); + System.out.println("- Add a new meal to available meals: newMeal MEAL_NAME,CALORIES," + + "CARBS,PROTEIN,FAT,FIBER,SUGAR"); + System.out.println("- Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES," + + "CARBS,SUGAR,PROTEIN,FAT"); System.out.println("- Clear all entries: clear"); System.out.println("- Exit the app: exit "); } @@ -402,27 +412,60 @@ public static void parseExercise(String command) throws IncompleteExerciseExcept } } - public static void parseMealNutrient(String data) { + public static void parseMealNutrient(String data) throws IllegalArgumentException, NegativeValueException{ String delimiter = ","; String[] arrayOfMealNutrient = data.split(delimiter); - mealNutrientDescription = arrayOfMealNutrient[0].trim().toLowerCase(); - mealNutrientCalories = Integer.parseInt(arrayOfMealNutrient[1]); - mealNutrientCarbs = Integer.parseInt(arrayOfMealNutrient[2]); - mealNutrientProtein = Integer.parseInt(arrayOfMealNutrient[3]); - mealNutrientFat = Integer.parseInt(arrayOfMealNutrient[4]); - mealNutrientFiber = Integer.parseInt(arrayOfMealNutrient[5]); - mealNutrientSugar = Integer.parseInt(arrayOfMealNutrient[6]); + + if (arrayOfMealNutrient.length != 7) { + throw new IllegalArgumentException("Invalid number of arguments provided. Expected 7, got " + + arrayOfMealNutrient.length); + } + + try { + mealNutrientDescription = arrayOfMealNutrient[0].trim().toLowerCase(); + mealNutrientCalories = Integer.parseInt(arrayOfMealNutrient[1]); + mealNutrientCarbs = Integer.parseInt(arrayOfMealNutrient[2]); + mealNutrientProtein = Integer.parseInt(arrayOfMealNutrient[3]); + mealNutrientFat = Integer.parseInt(arrayOfMealNutrient[4]); + mealNutrientFiber = Integer.parseInt(arrayOfMealNutrient[5]); + mealNutrientSugar = Integer.parseInt(arrayOfMealNutrient[6]); + + IntegerValidation.checkIntegerGreaterThanZero(mealNutrientCalories); + IntegerValidation.checkIntegerGreaterThanZero(mealNutrientCarbs); + IntegerValidation.checkIntegerGreaterThanZero(mealNutrientProtein); + IntegerValidation.checkIntegerGreaterThanZero(mealNutrientFat); + IntegerValidation.checkIntegerGreaterThanZero(mealNutrientFiber); + IntegerValidation.checkIntegerGreaterThanZero(mealNutrientSugar); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid numeric format, please input an integer"); + } } - public static void parseDrinkNutrient(String data) { + public static void parseDrinkNutrient(String data) throws IllegalArgumentException, NegativeValueException { String delimiter = ","; String[] arrayOfDrinkNutrient = data.split(delimiter); - drinkNutrientDescription = arrayOfDrinkNutrient[0].trim().toLowerCase(); - drinkNutrientCalories = Integer.parseInt(arrayOfDrinkNutrient[1]); - drinkNutrientCarbs = Integer.parseInt(arrayOfDrinkNutrient[2]); - drinkNutrientSugar = Integer.parseInt(arrayOfDrinkNutrient[3]); - drinkNutrientProtein = Integer.parseInt(arrayOfDrinkNutrient[4]); - drinkNutrientFat = Integer.parseInt(arrayOfDrinkNutrient[5]); + + if (arrayOfDrinkNutrient.length != 6) { + throw new IllegalArgumentException("Invalid number of arguments provided. Expected 6, got " + + arrayOfDrinkNutrient.length); + } + + try { + drinkNutrientDescription = arrayOfDrinkNutrient[0].trim().toLowerCase(); + drinkNutrientCalories = Integer.parseInt(arrayOfDrinkNutrient[1]); + drinkNutrientCarbs = Integer.parseInt(arrayOfDrinkNutrient[2]); + drinkNutrientSugar = Integer.parseInt(arrayOfDrinkNutrient[3]); + drinkNutrientProtein = Integer.parseInt(arrayOfDrinkNutrient[4]); + drinkNutrientFat = Integer.parseInt(arrayOfDrinkNutrient[5]); + + IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientCalories); + IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientCarbs); + IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientSugar); + IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientProtein); + IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientFat); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid numeric format, please input an integer"); + } } public static void parseExerciseCalories(String data) { @@ -442,4 +485,14 @@ public static String parseListDate(String command) throws InvalidDateException { } throw new InvalidDateException(); } + + public static void parseNewMeal(String command) throws NegativeValueException { + String mealNutrients = command.substring(8).trim(); + parseMealNutrient(mealNutrients); + } + + public static void parseNewDrink(String command) throws NegativeValueException { + String drinkNutrients = command.substring(9).trim(); + parseDrinkNutrient(drinkNutrients); + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f98edd40eb..5ca52709ee 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -24,6 +24,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; +import java.util.Map; public class User { // list for today @@ -39,20 +40,24 @@ public class User { public User(Storage mealStorage, Storage drinkStorage, Storage exerciseStorage, Storage mealNutrientStorage, Storage drinkNutrientStorage, Storage exerciseCaloriesStorage) { - mealList = new ArrayList<>(); - drinkList = new ArrayList<>(); - exerciseList = new ArrayList<>(); - waterList = new ArrayList<>(); - mealListAll = new ArrayList<>(); - drinkListAll = new ArrayList<>(); - exerciseListAll = new ArrayList<>(); - waterListAll = new ArrayList<>(); - loadMealNutrient(mealNutrientStorage); - loadDrinkNutrient(drinkNutrientStorage); - loadExerciseCalories(exerciseCaloriesStorage); - loadMeal(mealStorage); - loadDrink(drinkStorage); - loadExercise(exerciseStorage); + try { + mealList = new ArrayList<>(); + drinkList = new ArrayList<>(); + exerciseList = new ArrayList<>(); + waterList = new ArrayList<>(); + mealListAll = new ArrayList<>(); + drinkListAll = new ArrayList<>(); + exerciseListAll = new ArrayList<>(); + waterListAll = new ArrayList<>(); + loadMealNutrient(mealNutrientStorage); + loadDrinkNutrient(drinkNutrientStorage); + loadExerciseCalories(exerciseCaloriesStorage); + loadMeal(mealStorage); + loadDrink(drinkStorage); + loadExercise(exerciseStorage); + } catch (NegativeValueException e) { + System.out.println("Nutrient details must be greater than 0"); + } } public void loadMeal(Storage mealStorage) { @@ -145,7 +150,7 @@ public void loadExercise(Storage exerciseStorage) { } } - public void loadMealNutrient(Storage mealNutrientStorage) { + public void loadMealNutrient(Storage mealNutrientStorage) throws NegativeValueException{ try { ArrayList mealNutrientList = mealNutrientStorage.readFile(); if (!mealNutrientList.isEmpty()) { @@ -166,7 +171,7 @@ public void loadMealNutrient(Storage mealNutrientStorage) { } } - public void loadDrinkNutrient(Storage drinkNutrientStorage) { + public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValueException{ try { ArrayList drinkNutrientList = drinkNutrientStorage.readFile(); if (!drinkNutrientList.isEmpty()) { @@ -262,6 +267,71 @@ public void saveExercise(Storage exerciseStorage) { } } + public void saveMealNutrients(Storage mealNutrientStorage) { + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : Meal.nutrientDetails.entrySet()) { + result.append(entry.getKey()).append(","); + int[] values = entry.getValue(); + for (int value : values) { + result.append(value).append(","); + } + result = new StringBuilder(result.substring(0, result.length() - 1)); + result.append("\n"); + } + mealNutrientStorage.appendTextContent(result.toString()); + System.out.println(mealNutrientStorage.textContent); + try { + mealNutrientStorage.writeFile(mealNutrientStorage.textContent); + } catch (IOException e) { + System.out.println("Failed adding meal nutrients: " + e.getMessage()); + } + } + + public void saveDrinkNutrients(Storage drinkNutrientStorage) { + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : Drink.nutrientDetails.entrySet()) { + result.append(entry.getKey()).append(","); + int[] values = entry.getValue(); + for (int value : values) { + result.append(value).append(","); + } + result = new StringBuilder(result.substring(0, result.length() - 1)); + result.append("\n"); + } + drinkNutrientStorage.appendTextContent(result.toString()); + try { + drinkNutrientStorage.writeFile(drinkNutrientStorage.textContent); + } catch (IOException e) { + System.out.println("Failed adding drink nutrients: " + e.getMessage()); + } + } + + public void handleAddNewMealNutrient(String command) throws NegativeValueException{ + Parser.parseNewMeal(command); + String description = Parser.mealNutrientDescription; + int calories = Parser.mealNutrientCalories; + int carbs = Parser.mealNutrientCarbs; + int protein = Parser.mealNutrientProtein; + int fat = Parser.mealNutrientFat; + int fiber = Parser.mealNutrientFiber; + int sugar = Parser.mealNutrientSugar; + Meal.nutrientDetails.put(description, new int[]{calories, carbs, protein, fat, fiber, sugar}); + + System.out.println("Added " + description + " to available meals"); + } + + public void handleAddNewDrinkNutrient(String command) throws NegativeValueException{ + Parser.parseNewDrink(command); + String description = Parser.drinkNutrientDescription; + int calories = Parser.drinkNutrientCalories; + int carbs = Parser.drinkNutrientCarbs; + int sugar = Parser.drinkNutrientSugar; + int protein = Parser.drinkNutrientProtein; + int fat = Parser.drinkNutrientFat; + Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); + + System.out.println("Added " + description + " to available drinks"); + } public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, NegativeValueException { From cacaec77a5c83f08507b12ea6a58556706a46d4d Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 20:27:58 +0800 Subject: [PATCH 161/274] Add greater or equal to check in validator --- src/main/java/seedu/fitnus/parser/Parser.java | 22 +++++++++---------- .../fitnus/validator/IntegerValidation.java | 6 +++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index bc214c9a89..a1009aa047 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -430,12 +430,12 @@ public static void parseMealNutrient(String data) throws IllegalArgumentExcepti mealNutrientFiber = Integer.parseInt(arrayOfMealNutrient[5]); mealNutrientSugar = Integer.parseInt(arrayOfMealNutrient[6]); - IntegerValidation.checkIntegerGreaterThanZero(mealNutrientCalories); - IntegerValidation.checkIntegerGreaterThanZero(mealNutrientCarbs); - IntegerValidation.checkIntegerGreaterThanZero(mealNutrientProtein); - IntegerValidation.checkIntegerGreaterThanZero(mealNutrientFat); - IntegerValidation.checkIntegerGreaterThanZero(mealNutrientFiber); - IntegerValidation.checkIntegerGreaterThanZero(mealNutrientSugar); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(mealNutrientCalories); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(mealNutrientCarbs); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(mealNutrientProtein); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(mealNutrientFat); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(mealNutrientFiber); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(mealNutrientSugar); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid numeric format, please input an integer"); } @@ -458,11 +458,11 @@ public static void parseDrinkNutrient(String data) throws IllegalArgumentExcept drinkNutrientProtein = Integer.parseInt(arrayOfDrinkNutrient[4]); drinkNutrientFat = Integer.parseInt(arrayOfDrinkNutrient[5]); - IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientCalories); - IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientCarbs); - IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientSugar); - IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientProtein); - IntegerValidation.checkIntegerGreaterThanZero(drinkNutrientFat); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(drinkNutrientCalories); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(drinkNutrientCarbs); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(drinkNutrientSugar); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(drinkNutrientProtein); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(drinkNutrientFat); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid numeric format, please input an integer"); } diff --git a/src/main/java/seedu/fitnus/validator/IntegerValidation.java b/src/main/java/seedu/fitnus/validator/IntegerValidation.java index c1778218f3..1fadd79764 100644 --- a/src/main/java/seedu/fitnus/validator/IntegerValidation.java +++ b/src/main/java/seedu/fitnus/validator/IntegerValidation.java @@ -9,4 +9,10 @@ public static void checkIntegerGreaterThanZero (int value) throws NegativeValueE throw new NegativeValueException(); } } + + public static void checkIntegerGreaterOrEqualThanZero (int value) throws NegativeValueException { + if (value < 0) { + throw new NegativeValueException(); + } + } } From c9bbf68675cd9e756e92cc7493f4bc0e790dde39 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 20:35:04 +0800 Subject: [PATCH 162/274] Merge with master --- .../java/seedu/fitnus/parser/ParserTest.java | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 86f964f0bc..3b32479c61 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -1,9 +1,7 @@ package seedu.fitnus.parser; import org.junit.jupiter.api.Test; -import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.NegativeValueException; @@ -19,24 +17,6 @@ public class ParserTest { - @Test - public void parseMeal_validInputs_success() throws IncompleteMealException, UnregisteredMealException, - NegativeValueException { - String command = "eat m/chicken rice s/1"; - Parser.parseMeal(command); - assertEquals("chicken rice", Parser.mealDescription); - assertEquals(1, Parser.mealSize); - } - - @Test - public void parseDrink_validInputs_success() throws IncompleteDrinkException, UnregisteredDrinkException, - NegativeValueException { - String command = "drink d/sprite s/300"; - Parser.parseDrink(command); - assertEquals("sprite", Parser.drinkDescription); - assertEquals(300, Parser.drinkSize); - } - @Test public void parseInfoMeal_unregisteredMeal_exceptionThrown() throws IncompleteInfoException { String command = "infoMeal blablabla"; @@ -141,7 +121,7 @@ public void parseExercise_validInputs_success() throws IncompleteExerciseExcepti } @Test - public void parseMealNutrient_validInputs_success() { + public void parseMealNutrient_validInputs_success() throws NegativeValueException { String data = "fried rice,100,10,9,8,7,6"; Parser.parseMealNutrient(data); assertEquals("fried rice", Parser.mealNutrientDescription); @@ -154,7 +134,7 @@ public void parseMealNutrient_validInputs_success() { } @Test - public void parseDrinkNutrient_validInputs_success() { + public void parseDrinkNutrient_validInputs_success() throws NegativeValueException { String data = "Guava Juice,143,38,10,9,5"; Parser.parseDrinkNutrient(data); assertEquals("guava juice", Parser.drinkNutrientDescription); From 58fcdd2c46318c5f93f012b7ee220e6a9eb0f0bc Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 20:51:45 +0800 Subject: [PATCH 163/274] Update UserGuide --- db/Drink_db.csv | 1 + db/Meal_db.csv | 1 + docs/UserGuide.md | 22 +++++++++++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/db/Drink_db.csv b/db/Drink_db.csv index 7cea40c5af..09f3f296ca 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -4,6 +4,7 @@ honey lemon tea,134,36,2,0,0 soursop juice,117,25,3,1,1 kopi c,117,20,1,4,0 kalamansi juice,168,42,0,0,1 +coke,153,32,1,2,1 kopi o,67,15,1,0,0 milo,124,20,3,3,1 plum juice,57,13,1,0,1 diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 4dff766b0e..90cc76311b 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -4,6 +4,7 @@ tau huay,153,32,14,1,5,1 nasi goreng,346,45,13,12,10,2 babi kecap,607,75,25,23,2,10 soup kambeng,203,6,28,7,2,5 +mie,607,75,25,23,2,10 nasi lemak,494,80,13,14,6,5 pepper lunch,500,50,40,11,4,5 char siew rice,605,91,24,16,6,10 diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 506bdcd6d7..f97a26af4d 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -68,6 +68,8 @@ here's all the valid commands i recognise: - Add a meal eaten: eat m/MEAL s/SERVING_SIZE - Add a drink: drink d/DRINK s/VOLUME(ML) - Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, LOW) +- Add a new meal to available meals: newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR +- Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT - View all meals that you can input: allMeals - View all drinks that you can input: allDrinks - View all exercises that you can input: allExercises @@ -171,7 +173,7 @@ Available drinks: You may also input a drink that isn't here. ~~~ -### 1.1.3 Viewing all pre-defined exercises: `allExercises` +### 1.1.4 Viewing all pre-defined exercises: `allExercises` Shows a list of all pre-defined exercises. These exercises will have the number of calories burnt for a high/medium/low intensity workout defined per minute and can be inputted immediately. **Format**: allExercises @@ -234,6 +236,24 @@ Adds exercise to the list of exercises done Tracked 30 minutes of swimming ~~~ +### 1.2.4 Add new meal to available meals: `newMeal` +Adds a new meal to available meals +**Format**: `newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR` +**Sample Input**: `newMeal mie,607,75,25,23,2,10` +**Expected Output**: +~~~ +Added mie to available meals +~~~ + +### 1.2.4 Add new meal to available meals: `newDrink` +Adds a new drink to available drinks +**Format**: `newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT` +**Sample Input**: `newDrink coke,153,32,1,2,1` +**Expected Output**: +~~~ +Added coke to available drinks +~~~ + ## 1.3 For data retrieval ### 1.3.1 Find the information about a certain meal: `infoMeal` For the specified meal, display its nutritional content to the user From 4e439db232f28c21ac238ddde77f78e799ee4d99 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 20:53:18 +0800 Subject: [PATCH 164/274] update db --- db/Drink_db.csv | 1 - db/Meal_db.csv | 2 -- 2 files changed, 3 deletions(-) diff --git a/db/Drink_db.csv b/db/Drink_db.csv index 09f3f296ca..7cea40c5af 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -4,7 +4,6 @@ honey lemon tea,134,36,2,0,0 soursop juice,117,25,3,1,1 kopi c,117,20,1,4,0 kalamansi juice,168,42,0,0,1 -coke,153,32,1,2,1 kopi o,67,15,1,0,0 milo,124,20,3,3,1 plum juice,57,13,1,0,1 diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 90cc76311b..ad26c56595 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -2,9 +2,7 @@ char kway teow,744,76,23,29,7,10 ban mian,475,48,22,22,3,10 tau huay,153,32,14,1,5,1 nasi goreng,346,45,13,12,10,2 -babi kecap,607,75,25,23,2,10 soup kambeng,203,6,28,7,2,5 -mie,607,75,25,23,2,10 nasi lemak,494,80,13,14,6,5 pepper lunch,500,50,40,11,4,5 char siew rice,605,91,24,16,6,10 From 10055ad6aec8f1457dcda6f7aee93749fed85038 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 21:00:36 +0800 Subject: [PATCH 165/274] Update userguide and db --- db/Output_Drink_2024-03-26.csv | 1 - db/Output_Food_2024-03-26.csv | 1 - docs/UserGuide.md | 9 ++++++++- 3 files changed, 8 insertions(+), 3 deletions(-) delete mode 100644 db/Output_Drink_2024-03-26.csv delete mode 100644 db/Output_Food_2024-03-26.csv diff --git a/db/Output_Drink_2024-03-26.csv b/db/Output_Drink_2024-03-26.csv deleted file mode 100644 index 45b983be36..0000000000 --- a/db/Output_Drink_2024-03-26.csv +++ /dev/null @@ -1 +0,0 @@ -hi diff --git a/db/Output_Food_2024-03-26.csv b/db/Output_Food_2024-03-26.csv deleted file mode 100644 index 45b983be36..0000000000 --- a/db/Output_Food_2024-03-26.csv +++ /dev/null @@ -1 +0,0 @@ -hi diff --git a/docs/UserGuide.md b/docs/UserGuide.md index f97a26af4d..49eab57e71 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -5,6 +5,8 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even past records. +Note: To use the app please download the JAR file and 'db' folder. Place them into an empty folder and run the JAR file. + ## Table of Contents * [User Guide: FitNUS](#user-guide-fitnus) @@ -12,12 +14,17 @@ Users are able to track the meals, drinks, and exercises they have in a day and * [Table of Contents](#table-of-contents) * [1) Features List](#1-features-list) * [1.1 Information for users](#11-information-for-users) - * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help) + * [1.1.1 Viewing all commands: `help`](#111-viewing-all-commands-help) + * [1.1.2 Viewing all pre-defined meals: `allMeals`](#112-viewing-all-pre-defined-meals-allmeals) + * [1.1.3 Viewing all pre-defined drinks: `allDrinks`](#113-viewing-all-pre-defined-drinks-alldrinks) + * [1.1.4 Viewing all pre-defined exercises: `allExercises`](#114-viewing-all-pre-defined-exercises-allexercises) * [1.2 For user to add data](#12-for-user-to-add-data) * [1.2.1 Add a meal eaten: `eat`](#121-add-a-meal-eaten-eat) * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) * [1.2.2.1 Add water: `drink d/water`](#1221-add-water-drink-dwater) * [1.2.3 Add exercise: `exercise`](#123-add-exercise-exercise) + * [1.2.4 Add new meal to available meals: `newMeal`](#124-add-new-meal-to-available-meals-newmeal) + * [1.2.4 Add new meal to available meals: `newDrink`](#124-add-new-meal-to-available-meals-newdrink) * [1.3 For data retrieval](#13-for-data-retrieval) * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) From 38020ab0544b543faf10c6164b5631d0c340f6e1 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 21:03:05 +0800 Subject: [PATCH 166/274] Update UserGuide --- docs/UserGuide.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 49eab57e71..9d3f103a20 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -5,7 +5,12 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even past records. -Note: To use the app please download the JAR file and 'db' folder. Place them into an empty folder and run the JAR file. +## Setup +To use the app please follow the setup procedures below: +1. Download the JAR file and 'db' folder. +2. Place them into an empty folder. +3. Navigate to the folder you just created. +4. Run the JAR file. ## Table of Contents From 7ec3eba4cc9d1feb3a9a44177652ace10a3bc1f9 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Tue, 2 Apr 2024 21:29:41 +0800 Subject: [PATCH 167/274] Update UserGuide --- docs/UserGuide.md | 34 +++++++++++------------ src/main/java/seedu/fitnus/user/User.java | 1 - 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 9d3f103a20..8d4d50a565 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -218,16 +218,16 @@ Adds a meal to the list of meals **Sample Input**: `eat m/Chicken Rice s/1` **Expected Output**: ~~~ -Added 1 serving of Chicken Rice +Added 1 serving of chicken rice ~~~ ### 1.2.2 Add a drink: `drink` Adds a drink to the list of drinks **Format**: `drink d/DRINK s/SERVING_SIZE` -**Sample Input**: `drink d/Lemon Tea s/100` +**Sample Input**: `drink d/Iced Lemon Tea s/200` **Expected Output**: ~~~ -Added 100ml of Lemon Tea +Added 200 ml of iced lemon tea ~~~ ### 1.2.2.1 Add water: `drink d/water` @@ -241,7 +241,7 @@ Added 100ml of water ### 1.2.3 Add exercise: `exercise` Adds exercise to the list of exercises done -**Format**: `exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM,` +**Format**: `exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, LOW)` **Sample Input**: `exercise e/swimming d/30 i/HIGH` **Expected Output**: ~~~ @@ -285,15 +285,15 @@ Sugar: 10 ### 1.3.2 Find the information about a certain drink: `infoDrink` For the inputted drink, display its nutritional content to the user **Format**: `infoDrink DRINK` -**Sample input**: `infoDrink sprite` +**Sample input**: `infoDrink milo` **Expected output**: ~~~ -Drink: sprite (100 ml) -Calories: 40 -Carbs: 50 -Sugar: 30 -Protein: 20 -Fat: 2 +Drink: milo (100 ml) +Calories: 124 +Carbs: 20 +Sugar: 3 +Protein: 3 +Fat: 1 ~~~ ### 1.3.3 Find the information about a certain exercise: `infoExercise` @@ -314,7 +314,7 @@ Display current total calorie intake for the day **Format**: `calories` **Expected output**: ~~~ -Total calories: 100 cal +Total Calories: 100 ~~~ ### 1.3.5 View daily carbohydrates consumed: `carbs` @@ -330,7 +330,7 @@ Display current total protein intake for the day **Format**: `protein` **Expected output**: ~~~ -Total proteins: 100 grams +Total Proteins: 100 grams ~~~ ### 1.3.7 View daily fat consumed: `fat` @@ -338,7 +338,7 @@ Display current total fat intake for the day **Format**: `fat` **Expected output**: ~~~ -Total fat: 50 grams +Total Fat: 50 grams ~~~ ### 1.3.8 View daily sugar consumed: `sugar` @@ -346,7 +346,7 @@ Display current total sugar intake for the day **Format**: `sugar` **Expected output**: ~~~ -Total sugar: 20 grams +Total Sugar: 20 grams ~~~ ### 1.3.9 View daily fiber consumed: `fiber` @@ -354,7 +354,7 @@ Display current total fiber intake (g) for the day **Format**: `fiber` **Expected output**: ~~~ -Total fiber: 20 grams +Total Fiber: 20 grams ~~~ ### 1.3.10 View daily water consumption: `viewWater` @@ -362,7 +362,7 @@ Display current total water intake (in ml) for the day **Format**: `viewWater` **Expected output**: ~~~ -Total water intake: 0 ml +Total water intake today: 0 ml ~~~ ### 1.3.11 View daily calories consumed: `caloriesBurnt` diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index b5614bf6ea..f531688c4e 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -336,7 +336,6 @@ public void saveMealNutrients(Storage mealNutrientStorage) { result.append("\n"); } mealNutrientStorage.appendTextContent(result.toString()); - System.out.println(mealNutrientStorage.textContent); try { mealNutrientStorage.writeFile(mealNutrientStorage.textContent); } catch (IOException e) { From 27eb25211f3d1068a49fc4d115f9d49b91a8b791 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Tue, 2 Apr 2024 22:02:58 +0800 Subject: [PATCH 168/274] Fix CSV reader --- src/main/java/seedu/fitnus/Drink.java | 6 ++++++ src/main/java/seedu/fitnus/Meal.java | 6 ++++++ src/main/java/seedu/fitnus/user/User.java | 6 +++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 39fc4f5b01..f7e6515f29 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -34,6 +34,12 @@ public Drink(String name, int volume, String currentDate) { this.dateAdded = currentDate; } + static { + nutrientDetails.put("sprite", new int[]{270, 42, 7, 8, 2}); + nutrientDetails.put("iced lemon tea", new int[]{95, 21, 1, 1, 1}); + nutrientDetails.put("milo", new int[]{124, 20, 3, 3, 1}); + } + private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); calories = nutrients[0] * drinkVolume / 100; diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index f27f44d3b6..b68441b165 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -35,6 +35,12 @@ public Meal(String name, int servingSize, String currentDate) { this.dateAdded = currentDate; } + static { + nutrientDetails.put("chicken rice", new int[]{400, 50, 30, 20, 10, 5}); + nutrientDetails.put("fried rice", new int[]{500, 60, 25, 15, 15, 5}); + nutrientDetails.put("pizza", new int[]{600, 80, 50, 40, 30, 20}); + } + private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); calories = nutrients[0] * servingSize; diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f531688c4e..d75f1d7303 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -195,7 +195,7 @@ public void loadMealNutrient(Storage mealNutrientStorage) throws NegativeValueEx } } } catch (FileNotFoundException e) { - System.out.println("Meal nutrient database not found"); + mealNutrientStorage.createFile(); } } @@ -220,7 +220,7 @@ public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValue } } } catch (FileNotFoundException e) { - System.out.println("Drink nutrient database not found"); + drinkNutrientStorage.createFile(); } } @@ -244,7 +244,7 @@ public void loadExerciseCalories(Storage exerciseCaloriesStorage) { } } } catch (FileNotFoundException e) { - System.out.println("Exercise calories database not found"); + exerciseCaloriesStorage.createFile(); } } From b548bb5324ff002448454ac83803a2d4b4b283a8 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Tue, 2 Apr 2024 22:20:48 +0800 Subject: [PATCH 169/274] Fix testing errors --- src/main/java/seedu/fitnus/Drink.java | 1 + src/main/java/seedu/fitnus/Exercise.java | 6 +++--- src/main/java/seedu/fitnus/Meal.java | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index f7e6515f29..0644fec117 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -38,6 +38,7 @@ public Drink(String name, int volume, String currentDate) { nutrientDetails.put("sprite", new int[]{270, 42, 7, 8, 2}); nutrientDetails.put("iced lemon tea", new int[]{95, 21, 1, 1, 1}); nutrientDetails.put("milo", new int[]{124, 20, 3, 3, 1}); + nutrientDetails.put("kopi", new int[]{141, 26, 2, 3, 1}); } private void setNutrientValues(String name) { diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/Exercise.java index a0be350572..a4ddf37d49 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/Exercise.java @@ -36,9 +36,9 @@ public Exercise(String name, int duration, ExerciseIntensity intensity, String c } static { - exerciseDetails.put("running", new int[]{8, 5, 3}); - exerciseDetails.put("cycling", new int[]{6, 4, 2}); - exerciseDetails.put("swimming", new int[]{10, 7, 4}); + exerciseDetails.put("running", new int[]{14, 10, 7}); + exerciseDetails.put("cycling", new int[]{10, 7, 4}); + exerciseDetails.put("swimming", new int[]{12, 8, 5}); } /** diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/Meal.java index b68441b165..2a490bbc12 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/Meal.java @@ -39,6 +39,8 @@ public Meal(String name, int servingSize, String currentDate) { nutrientDetails.put("chicken rice", new int[]{400, 50, 30, 20, 10, 5}); nutrientDetails.put("fried rice", new int[]{500, 60, 25, 15, 15, 5}); nutrientDetails.put("pizza", new int[]{600, 80, 50, 40, 30, 20}); + nutrientDetails.put("kaya toast", new int[]{459, 44, 8, 27, 10, 1}); + nutrientDetails.put("laksa", new int[]{377, 71, 18, 2, 4, 10}); } private void setNutrientValues(String name) { From 1e5d042494c5e83771154e21c9bbd9faffee0147 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 22:44:54 +0800 Subject: [PATCH 170/274] Add New Exercise Feature --- data/ExerciseList.txt | 7 +--- db/Drink_db.csv | 19 ++-------- db/Exercise_db.csv | 20 +++-------- db/Meal_db.csv | 22 ++---------- src/main/java/seedu/fitnus/Ui.java | 1 + src/main/java/seedu/fitnus/parser/Parser.java | 35 +++++++++++++++---- src/main/java/seedu/fitnus/user/User.java | 32 ++++++++++++++++- .../java/seedu/fitnus/parser/ParserTest.java | 2 +- 8 files changed, 73 insertions(+), 65 deletions(-) diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt index b59a7f81d2..21b6f74f86 100644 --- a/data/ExerciseList.txt +++ b/data/ExerciseList.txt @@ -1,6 +1 @@ -cycling,100,LOW,29-02-2024 -swimming,100,HIGH,30-03-2024 -running,50,MEDIUM,30-03-2024 -cycling,100,LOW,31-03-2024 -running,20,HIGH,31-03-2024 -boxing,10,LOW,01-04-2024 +badminton,20,HIGH,02-04-2024 diff --git a/db/Drink_db.csv b/db/Drink_db.csv index 7cea40c5af..2dff4e01fa 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -1,20 +1,5 @@ -milo dinosaur,270,42,7,8,2 -chrysanthemun juice,12,2,3,1,0 -honey lemon tea,134,36,2,0,0 -soursop juice,117,25,3,1,1 -kopi c,117,20,1,4,0 -kalamansi juice,168,42,0,0,1 -kopi o,67,15,1,0,0 +sprite,270,42,7,8,2 milo,124,20,3,3,1 -plum juice,57,13,1,0,1 -100 plus,72,18,0,0,0 -teh c bing,231,24,15,1,1 -kopi,141,26,2,3,1 -guava juice,143,38,0,0,1 -tiger beer,42,3,1,0,0 -teh tarik,124,21,3,3,0 -sugarcane juice,192,52,0,0,1 -teh,151,29,4,1,1 iced lemon tea,95,21,1,1,1 -bandung,153,32,1,2,1 +kopi,141,26,2,3,1 diff --git a/db/Exercise_db.csv b/db/Exercise_db.csv index 4db59301d7..d37c5c8a88 100644 --- a/db/Exercise_db.csv +++ b/db/Exercise_db.csv @@ -1,15 +1,5 @@ -Running,14,10,7 -Swimming,12,8,5 -Cycling,10,7,4 -Skipping,16,12,8 -Weightlifting,7,5,3 -Yoga,5,3,2 -Rowing,13,9,6 -Boxing,15,11,7 -Badminton,14,10,6 -Soccer,15,11,8 -Basketball,16,12,8 -Tennis,14,10,7 -Volleyball,12,8,5 -Rugby,18,14,10 -Hiking,12,8,6 \ No newline at end of file +running,14,10,7 +swimming,12,8,5 +badminton,100,50,5 +cycling,10,7,4 + diff --git a/db/Meal_db.csv b/db/Meal_db.csv index ad26c56595..85a5213ee8 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,22 +1,6 @@ -char kway teow,744,76,23,29,7,10 -ban mian,475,48,22,22,3,10 -tau huay,153,32,14,1,5,1 -nasi goreng,346,45,13,12,10,2 -soup kambeng,203,6,28,7,2,5 -nasi lemak,494,80,13,14,6,5 -pepper lunch,500,50,40,11,4,5 -char siew rice,605,91,24,16,6,10 -pork satay with satay sauce,36,1,5,2,10,0 -roti prata,209,32,5,7,2,10 -mee goreng,500,61,18,20,4,5 -chendol,386,59,6,15,7,2 -wanton mee,555,97,15,14,13,10 -oyster omlette,467,40,19,24,10,1 -ice kachang,257,58,6,1,10,2 -chicken rice,607,75,25,23,2,10 +pizza,600,80,50,40,30,20 +chicken rice,400,50,30,20,10,5 +fried rice,500,60,25,15,15,5 kaya toast,459,44,8,27,10,1 -mala,583,72,12,30,10,7 laksa,377,71,18,2,4,10 -hokkien prawn mee,522,69,18,19,4,10 -durian,147,27,2,5,3,5 diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 13fa93ccdb..e0206f31e9 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -48,6 +48,7 @@ public void handleExit() { user.saveExercise(exerciseStorage); user.saveMealNutrients(mealNutrientStorage); user.saveDrinkNutrients(drinkNutrientStorage); + user.saveExerciseCalories(exerciseCaloriesStorage); } /** diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index ab7088529e..1a2e58fc8e 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -109,7 +109,9 @@ public void handleCommand(String command) { user.handleAddNewMealNutrient(command); } else if (command.startsWith("newDrink")) { user.handleAddNewDrinkNutrient(command); - } else if (command.equals("allMeals")) { + } else if (command.startsWith("newExercise")) { + user.handleAddNewExerciseCalories(command); + }else if (command.equals("allMeals")) { Meal.listAvailableMeals(); } else if (command.equals("allDrinks")) { Drink.listAvailableDrinks(); @@ -271,6 +273,8 @@ public static void handleHelp() { "CARBS,PROTEIN,FAT,FIBER,SUGAR"); System.out.println("- Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES," + "CARBS,SUGAR,PROTEIN,FAT"); + System.out.println("- Add a new exercise to available exercises: newExercise CALORIES_BURNT_HIGH," + + "CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW"); System.out.println("- Clear all entries: clear"); System.out.println("- Exit the app: exit "); } @@ -600,13 +604,27 @@ public static void parseDrinkNutrient(String data) throws IllegalArgumentExcept * * @param data The calorie data string to be parsed. */ - public static void parseExerciseCalories(String data) { + public static void parseExerciseCalories(String data) throws IllegalArgumentException, NegativeValueException { String delimiter = ","; String[] arrayOfExerciseCalories = data.split(delimiter); - exerciseCaloriesDescription = arrayOfExerciseCalories[0].trim().toLowerCase(); - exerciseCaloriesHigh = Integer.parseInt(arrayOfExerciseCalories[1]); - exerciseCaloriesMedium = Integer.parseInt(arrayOfExerciseCalories[2]); - exerciseCaloriesLow = Integer.parseInt(arrayOfExerciseCalories[3]); + + if (arrayOfExerciseCalories.length != 4) { + throw new IllegalArgumentException("Invalid number of arguments provided. Expected 4, got " + + arrayOfExerciseCalories.length); + } + + try { + exerciseCaloriesDescription = arrayOfExerciseCalories[0].trim().toLowerCase(); + exerciseCaloriesHigh = Integer.parseInt(arrayOfExerciseCalories[1]); + exerciseCaloriesMedium = Integer.parseInt(arrayOfExerciseCalories[2]); + exerciseCaloriesLow = Integer.parseInt(arrayOfExerciseCalories[3]); + + IntegerValidation.checkIntegerGreaterOrEqualThanZero(exerciseCaloriesHigh); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(exerciseCaloriesMedium); + IntegerValidation.checkIntegerGreaterOrEqualThanZero(exerciseCaloriesLow); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid numeric format, please input an integer"); + } } /** @@ -634,4 +652,9 @@ public static void parseNewDrink(String command) throws NegativeValueException { String drinkNutrients = command.substring(9).trim(); parseDrinkNutrient(drinkNutrients); } + + public static void parseNewExercise(String command) throws NegativeValueException{ + String exerciseDetails = command.substring(12).trim(); + parseExerciseCalories(exerciseDetails); + } } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index d75f1d7303..8b075b5067 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -230,7 +230,7 @@ public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValue * * @param exerciseCaloriesStorage contains filePath and folderPath of where the pre-defined exercises are stored. */ - public void loadExerciseCalories(Storage exerciseCaloriesStorage) { + public void loadExerciseCalories(Storage exerciseCaloriesStorage) throws NegativeValueException { try { ArrayList exerciseCaloriesList = exerciseCaloriesStorage.readFile(); if (!exerciseCaloriesList.isEmpty()) { @@ -389,6 +389,36 @@ public void handleAddNewDrinkNutrient(String command) throws NegativeValueExcept System.out.println("Added " + description + " to available drinks"); } + public void saveExerciseCalories(Storage exerciseCaloriesStorage) { + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : Exercise.exerciseDetails.entrySet()) { + result.append(entry.getKey()).append(","); + int[] values = entry.getValue(); + for (int value : values) { + result.append(value).append(","); + } + result = new StringBuilder(result.substring(0, result.length() - 1)); + result.append("\n"); + } + exerciseCaloriesStorage.appendTextContent(result.toString()); + try { + exerciseCaloriesStorage.writeFile(exerciseCaloriesStorage.textContent); + } catch (IOException e) { + System.out.println("Failed adding exercise calories: " + e.getMessage()); + } + } + + public void handleAddNewExerciseCalories(String command) throws NegativeValueException{ + Parser.parseNewExercise(command); + String description = Parser.exerciseCaloriesDescription; + int high = Parser.exerciseCaloriesHigh; + int medium = Parser.exerciseCaloriesMedium; + int low = Parser.exerciseCaloriesLow; + Exercise.exerciseDetails.put(description, new int[]{high, medium, low}); + + System.out.println("Added " + description + " to available exercises"); + } + /** * Adds a meal to the user's current mealList, based on what the user has eaten and the serving size consumed. * diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 3b32479c61..b3672fdff5 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -146,7 +146,7 @@ public void parseDrinkNutrient_validInputs_success() throws NegativeValueExcepti } @Test - public void parseExerciseCalories_validInputs_success() { + public void parseExerciseCalories_validInputs_success() throws NegativeValueException { String data = "Running,14,10,7"; Parser.parseExerciseCalories(data); assertEquals("running", Parser.exerciseCaloriesDescription); From afe419d2d44d2265423c948630b58068cb3c334f Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Tue, 2 Apr 2024 22:49:20 +0800 Subject: [PATCH 171/274] Update UserGuide --- docs/UserGuide.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 8d4d50a565..87d3ccd106 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -7,8 +7,8 @@ Users are able to track the meals, drinks, and exercises they have in a day and ## Setup To use the app please follow the setup procedures below: -1. Download the JAR file and 'db' folder. -2. Place them into an empty folder. +1. Download the JAR file. +2. Place it into an empty folder. 3. Navigate to the folder you just created. 4. Run the JAR file. @@ -16,6 +16,7 @@ To use the app please follow the setup procedures below: * [User Guide: FitNUS](#user-guide-fitnus) * [Project Introduction](#project-introduction) + * [Setup](#setup-) * [Table of Contents](#table-of-contents) * [1) Features List](#1-features-list) * [1.1 Information for users](#11-information-for-users) @@ -30,6 +31,7 @@ To use the app please follow the setup procedures below: * [1.2.3 Add exercise: `exercise`](#123-add-exercise-exercise) * [1.2.4 Add new meal to available meals: `newMeal`](#124-add-new-meal-to-available-meals-newmeal) * [1.2.4 Add new meal to available meals: `newDrink`](#124-add-new-meal-to-available-meals-newdrink) + * [1.2.5 Add new exercise to available exercises: `newExercise`](#125-add-new-exercise-to-available-exercises-newexercise) * [1.3 For data retrieval](#13-for-data-retrieval) * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) @@ -82,6 +84,8 @@ here's all the valid commands i recognise: - Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, LOW) - Add a new meal to available meals: newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR - Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT +- Add a new exercise to available exercises: newExercise CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM, +CALORIES_BURNT_LOW" - View all meals that you can input: allMeals - View all drinks that you can input: allDrinks - View all exercises that you can input: allExercises @@ -265,6 +269,15 @@ Adds a new drink to available drinks ~~~ Added coke to available drinks ~~~ + +### 1.2.5 Add new exercise to available exercises: `newExercise` +Adds a new exercise to available exercises +**Format**: `newExercise CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW` +**Sample Input**: `newExercise badminton,20,10,5` +**Expected Output**: +~~~ +Added badminton to available exercises +~~~ ## 1.3 For data retrieval ### 1.3.1 Find the information about a certain meal: `infoMeal` From 662d526fa3a88b2f0a04ef8ad614af0f9350998c Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Tue, 2 Apr 2024 23:53:01 +0800 Subject: [PATCH 172/274] Update README.md --- README.md | 287 +++++++++++++----------------------------------------- 1 file changed, 70 insertions(+), 217 deletions(-) diff --git a/README.md b/README.md index ed30464514..3765ab3b26 100644 --- a/README.md +++ b/README.md @@ -1,219 +1,72 @@ -# FitNUS +# User Guide: FitNUS ## Project Introduction FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and -carbohydrates. Promote healthy lifestyle. - -Users are able to track the meals and drinks they have in a day. - -## Table of Contents - -[1) Features List](#1-features-list) -* [1.1 Information for users](#11-information-for-users) - * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help-) -* [1.2 For user to add data](#12-for-user-to-add-data) - * [1.2.1 Add a meal eaten: `ate`](#121-add-a-meal-eaten-ate) - * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) - * [1.2.3 Add water: `water`](#123-add-water-water) -* [1.3 For data retrieval](#13-for-data-retrieval) - * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) - * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) - * [1.3.3 View daily calories consumed: `calories`](#133-view-daily-calories-consumed-calories) - * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-carbohydrates-consumed-carbs) - * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-proteins-consumed-protein) - * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-fat-consumed-fat) - * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-sugar-consumed-sugar) - * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-fiber-consumed-fiber) - * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-water-consumption-viewwater) -* [1.4 For listing arrays](#14-for-listing-arrays) - * [1.4.1 List meal intake: `listMeals`](#141-list-meal-intake-listmeals) - * [1.4.2 List drink intake: `listDrinks`](#142-list-drink-intake-listdrinks) - * [1.4.3 List entire food intake for the day: `listEverything`](#143-list-entire-food-intake-for-the-day-listeverything) -* [1.5 For editing existing data](#15-for-editing-existing-data) - * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) - * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) - * [1.5.3 Edit water intake after inserted: `editWater`](#153-edit-water-intake-after-inserted-editwater) -* [1.6 For deleting data](#16-for-deleting-data) - * [1.6.1 Delete certain meal entry: `deleteMeal`](#161-delete-certain-meal-entry-deletemeal) - * [1.6.2 Delete certain drink entry: `deleteDrink`](#162-delete-certain-drink-entry-deletedrink) -* [1.7 For clearing data](#17-for-clearing-data-) - * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) -* [1.8: Exit program](#18-exit-program) - * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) - - -## 1) Features List -### 1.1 Information for users -### 1.1.1 Viewing all commands:** `help` -Shows a list of all possible command inputs. -**Format**: help -**Sample Input**: help -**Expected Output**: -here's all the valid commands i recognise: -- Add a meal eaten: ate m/MEAL s/SERVING_SIZE -- Add a drink: drink d/DRINK s/SERVING_SIZE -- Add water: water s/SERVING_SIZE -- Find the information about a certain meal: infoMeal MEAL -- Find the information about a certain drink: infoDrink DRINK -- View daily calories consumed: calories -- View daily carbohydrates consumed: carbs -- View daily proteins consumed: protein -- View daily fat consumed: fat -- View daily sugar consumed: sugar -- View daily fiber consumed: fiber -- View daily water consumption: viewWater -- List meal intake: listMeals -- List drink intake: listDrinks -- List entire food intake for the day: listEverything -- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE -- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE -- Delete certain meal entry: deleteMeal INDEX -- Delete certain drink entry: deleteDrink INDEX -- Clear all entries: clear -- Exit the app: exit - -### 1.2 For user to add data -### 1.2.1 Add a meal eaten: `ate` -Adds a meal to the list of meals -**Format**: ate m/MEAL s/SERVING_SIZE -**Sample Input**: ate m/Chicken Rice s/1 -**Expected Output**: Added 1 serving of Chicken Rice - -### 1.2.2 Add a drink: `drink` -Adds a drink to the list of drinks -**Format**: drink d/DRINK s/SERVING_SIZE -**Sample Input**: drink d/Lemon Tea s/100 -**Expected Output**: Added 100ml of Lemon Tea - -### 1.2.3 Add water: `water` -Adds water (in ml) to the daily water intake count -**Format**: water s/SERVING_SIZE -**Sample Input**: water s/200 -**Expected Output**: Added 200ml of water - -## 1.3 For data retrieval -### 1.3.1 Find the information about a certain meal: `infoMeal` -For the specified meal, display its nutritional content to the user -**Format**: infoMeal MEAL -**Sample Input**: infoMeal chicken rice -**Expected Output**: -Meal: chicken rice (per serving) -Calories: 400 -Carbs: 50 -Protein: 30 -Fat: 20 -Fiber: 10 -Sugar: 5 - -### 1.3.2 Find the information about a certain drink: `infoDrink` -For the inputed drink, display its nutritional content to the user -**Format**: infoDrink DRINK -**Sample input**: infoDrink sprite -**Expected output**: -SPRITE (473 ml) -Calories: 194 kcal -Carbs: 50g -Protein: 0.2g -Fat: 0.1g - -### 1.3.3 View daily calories consumed: `calories` -Display current total calorie intake for the day -**Format**: calories -**Expected output**: Total calories: 100 cal - -### 1.3.4 View daily carbohydrates consumed: `carbs` -Display current total carbohydrates intake for the day -**Format**: carbs -**Expected output**: Total Carbohydrates: 150 grams - -### 1.3.5 View daily proteins consumed: `protein` -Display current total protein intake for the day -**Format**: protein -**Expected output**: Total proteins: 100 grams - -### 1.3.6 View daily fat consumed: `fat` -Display current total fat intake for the day -**Format**: fat -**Expected output**: Total fat: 50 grams - -### 1.3.7 View daily sugar consumed: `sugar` -Display current total sugar intake for the day -**Format**: sugar -**Expected output**: Total sugar: 20 grams - -### 1.3.8 View daily fiber consumed: `fiber` -Display current total fiber intake (g) for the day -**Format**: viewFiber -**Expected output**: Total fiber: 20 grams - -### 1.3.9 View daily water consumption: `viewWater` -Display current total water intake (in ml) for the day -**Format**: viewWater -**Expected output**: Total water intake: 0 ml - -## 1.4 For listing arrays -### 1.4.1 List meal intake: `listMeals` -List all the meals user inputted today -**Format**: listMeals -**Expected output**: -here's what you have eaten today -1.pizza (serving size: 1) - -### 1.4.2 List drink intake: `listDrinks` -List all the drinks user inputted today -**Format**: listDrinks -**Expected output**: -here's what you have drank today -1.sprite (serving size: 1) -Total water intake: 0 ml - -### 1.4.3 List entire food intake for the day: `listEverything` -List all the drinks and meals inputted today -**Format**: listEverything -**Expected output**: -here's what you have consumed today -1.pizza (serving size: 1) -2.sprite (serving size: 1) -Total water intake: 0 ml - -## 1.5 For editing existing data -### 1.5.1 Edit an existing meal after inserted: `editMeal` -For a meal that was inputted in the day, edit its serving size -**Format**: editMealServingSize INDEX s/NEW_SERVING_SIZE -**Sample input**: editMeal 2 s/2 -**Expected output**: Pizza has been edited to 2 servings - -### 1.5.2 Edit an existing drink after inserted: `editDrink` -For a drink that was inputted in the day, edit its serving size -**Format**: editDrinkServingSize INDEX s/NEW_SERVING_SIZE -**Sample input**: editDrink 1 s/200 -**Expected output**: Sprite has been edited to 200 ml - -### 1.5.3 Edit water intake after inserted: `editWater` -Edit serving size of total water intake -**Format**: editWaterIntake s/TOTAL_WATER_INTAKE -**Sample input**: editWaterIntake 200 -**Expected output**: Total water has been edited to 200 ml - -## 1.6 For deleting data -### 1.6.1 Delete certain meal entry: `deleteMeal` -For a meal that was inputted in the day, delete its input based on its index in the meal list -**Format**: deleteMeal INDEX -**Sample Input**: deleteMeal 1 -**Expected output**: Removed Chicken Rice From Meals - -### 1.6.2 Delete certain drink entry: `deleteDrink` -For a drink that was inputted in the day, delete its input based on its index in the drink list -**Format**: deleteDrink INDEX -**Sample input**: deleteDrink 1 -**Expected output:** Removed Iced Lemon Tea From Drinks - -## 1.7 For clearing data -### 1.7.1 Clear all entries: `clear` -Clear all entries in mealList and drinkList -**Format**: clear -**Expected output**: All entries have been deleted - -## 1.8: Exit program -### 1.8.1 Exit the app: `exit` -**Format**: exit -**Expected output**: Bye. Hope to see you again soon! +carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. + +Users are able to track the meals, drinks, and exercises they have in a day and even past records. +*** +## Setup +To use the app please follow the setup procedures below: +1. Download the JAR file. +2. Place it into an empty folder. +3. Navigate to the folder you just created. +4. Run the JAR file. +*** +## Features List +### 1 Information for users +1. View all possible commands: `help` +2. View all pre-defined meals. These meals will have their nutritional content defined per serving size and can +be inputted immediately: `allMeals` +3. View all pre-defined drinks. These drinks will have their nutritional content defined per 100ml +and can be inputted immediately: `allDrinks` +4 Viewing all pre-defined exercises. These exercises will have the number of calories burnt for a +high/medium/low intensity workout defined per minute and can be inputted immediately: `allExercises` + +### 2 For user to add data +1. Adds a meal to the list of meals eaten today: `eat` +2. Add a drink list of drinks drank today: `drink` +3. Add exercise to the list of exercises done : `exercise` +4. Add a custom new meal on top of pre-defined meals: `newMeal` +5. Add a custom new drink on top of pre-defined drink: `newDrink` +6. Add a custom new exercise on top of pre-defined exercises: `newExercise` + +### 3 For user to retrieve data +1. Find nutritional content about a certain meal: `infoMeal` +2. Find nutritional content about a certain drink: `infoDrink` +3. Find the calories burnt per minute from a certain exercise: `infoExercise` +4. View daily calories consumed: `calories` +5. View daily carbohydrates consumed: `carbs` +6. View daily proteins consumed: `protein` +7. View daily fat consumed: `fat` +8. View daily sugar consumed: `sugar` +9. View daily fiber consumed: `fiber` +10. View daily water consumption: `viewWater` +11. View daily calories consumed: `caloriesBurnt` +12. View daily calories and water intake recommendation, based on current intake: `recommend` + +### 4 For users to view their lists and data +1. List today's meal intakes: `listMeals` +2. List today's drink intake: `listDrinks` +3. List today's exercises done: `listExercises` +4. List everything inputted today, inclusive of all meals, drinks and exercises: `listEverything` +5. List entire app's lifecycle meals intake, inclusive of previously inputted meals and their dates: `listMealsAll` +6. List entire app's lifecycle drinks intake, inclusive of previously inputted drinks and their dates: `listDrinksAll` +7. List entire app's lifecycle exercises done, inclusive of previously inputted exercises and their dates: `listExercisesAll` +8. List everything inputted for the entire app's lifecycle: `listEverythingAll` +9. List meal intake for a certain date: `listMeals d/[DATE]` +10. List drink intake for a certain date: `listDrinks d/[DATE]` +11. List exercise done for a certain date: `listExercises d/[DATE]` +12. List entire food intake and exercise done for a certain date: `listEverything d/[DATE]` + +### 5 For users to edit existing data +1. Edit the serving size of a meal that was inputted in the day: `editMeal` +2. Edit the serving size of a drink that was inputted in the day: `editDrink` +3. Edit total water intake of the day: `editWater` + +### 6 For users to delete existing data +1. Delete a meal entry: `deleteMeal` +2. Delete a drink entry: `deleteDrink` +3. Clear all entries of meals, drinks and exercise: `clear` +*** +## Exit the program +Close the appplication: `exit` From 11847d2508115999bfdd143e227685b72b10c99d Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Tue, 2 Apr 2024 23:53:48 +0800 Subject: [PATCH 173/274] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3765ab3b26..7e9489fa5a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# User Guide: FitNUS +# FitNUS ## Project Introduction FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. From d2120ecf2c6496eecd47540099ab6797857caf2c Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Tue, 2 Apr 2024 23:57:01 +0800 Subject: [PATCH 174/274] Update README.md --- docs/README.md | 287 ++++++++++++------------------------------------- 1 file changed, 70 insertions(+), 217 deletions(-) diff --git a/docs/README.md b/docs/README.md index 1351409705..7e9489fa5a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,219 +1,72 @@ # FitNUS ## Project Introduction -FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and -carbohydrates. Promote healthy lifestyle. - -Users are able to track the meals and drinks they have in a day. - -## Table of Contents - -[1) Features List](#1-features-list) - * [1.1 Information for users](#11-information-for-users) - * [1.1.1 Viewing all commands:** `help`](#111-viewing-all-commands-help-) - * [1.2 For user to add data](#12-for-user-to-add-data) - * [1.2.1 Add a meal eaten: `ate`](#121-add-a-meal-eaten-ate) - * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) - * [1.2.3 Add water: `water`](#123-add-water-water) - * [1.3 For data retrieval](#13-for-data-retrieval) - * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) - * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) - * [1.3.3 View daily calories consumed: `calories`](#133-view-daily-calories-consumed-calories) - * [1.3.4 View daily carbohydrates consumed: `carbs`](#134-view-daily-carbohydrates-consumed-carbs) - * [1.3.5 View daily proteins consumed: `protein`](#135-view-daily-proteins-consumed-protein) - * [1.3.6 View daily fat consumed: `fat`](#136-view-daily-fat-consumed-fat) - * [1.3.7 View daily sugar consumed: `sugar`](#137-view-daily-sugar-consumed-sugar) - * [1.3.8 View daily fiber consumed: `fiber`](#138-view-daily-fiber-consumed-fiber) - * [1.3.9 View daily water consumption: `viewWater`](#139-view-daily-water-consumption-viewwater) - * [1.4 For listing arrays](#14-for-listing-arrays) - * [1.4.1 List meal intake: `listMeals`](#141-list-meal-intake-listmeals) - * [1.4.2 List drink intake: `listDrinks`](#142-list-drink-intake-listdrinks) - * [1.4.3 List entire food intake for the day: `listEverything`](#143-list-entire-food-intake-for-the-day-listeverything) - * [1.5 For editing existing data](#15-for-editing-existing-data) - * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) - * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) - * [1.5.3 Edit water intake after inserted: `editWater`](#153-edit-water-intake-after-inserted-editwater) - * [1.6 For deleting data](#16-for-deleting-data) - * [1.6.1 Delete certain meal entry: `deleteMeal`](#161-delete-certain-meal-entry-deletemeal) - * [1.6.2 Delete certain drink entry: `deleteDrink`](#162-delete-certain-drink-entry-deletedrink) - * [1.7 For clearing data](#17-for-clearing-data-) - * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) - * [1.8: Exit program](#18-exit-program) - * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) - - -## 1) Features List -### 1.1 Information for users -### 1.1.1 Viewing all commands:** `help` -Shows a list of all possible command inputs. -**Format**: help -**Sample Input**: help -**Expected Output**: -here's all the valid commands i recognise: -- Add a meal eaten: ate m/MEAL s/SERVING_SIZE -- Add a drink: drink d/DRINK s/SERVING_SIZE -- Add water: water s/SERVING_SIZE -- Find the information about a certain meal: infoMeal MEAL -- Find the information about a certain drink: infoDrink DRINK -- View daily calories consumed: calories -- View daily carbohydrates consumed: carbs -- View daily proteins consumed: protein -- View daily fat consumed: fat -- View daily sugar consumed: sugar -- View daily fiber consumed: fiber -- View daily water consumption: viewWater -- List meal intake: listMeals -- List drink intake: listDrinks -- List entire food intake for the day: listEverything -- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE -- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE -- Delete certain meal entry: deleteMeal INDEX -- Delete certain drink entry: deleteDrink INDEX -- Clear all entries: clear -- Exit the app: exit - -### 1.2 For user to add data -### 1.2.1 Add a meal eaten: `ate` -Adds a meal to the list of meals -**Format**: ate m/MEAL s/SERVING_SIZE -**Sample Input**: ate m/Chicken Rice s/1 -**Expected Output**: Added 1 serving of Chicken Rice - -### 1.2.2 Add a drink: `drink` -Adds a drink to the list of drinks -**Format**: drink d/DRINK s/SERVING_SIZE -**Sample Input**: drink d/Lemon Tea s/100 -**Expected Output**: Added 100ml of Lemon Tea - -### 1.2.3 Add water: `water` -Adds water (in ml) to the daily water intake count -**Format**: water s/SERVING_SIZE -**Sample Input**: water s/200 -**Expected Output**: Added 200ml of water - -## 1.3 For data retrieval -### 1.3.1 Find the information about a certain meal: `infoMeal` -For the specified meal, display its nutritional content to the user -**Format**: infoMeal MEAL -**Sample Input**: infoMeal chicken rice -**Expected Output**: -Meal: chicken rice (per serving) -Calories: 400 -Carbs: 50 -Protein: 30 -Fat: 20 -Fiber: 10 -Sugar: 5 - -### 1.3.2 Find the information about a certain drink: `infoDrink` -For the inputed drink, display its nutritional content to the user -**Format**: infoDrink DRINK -**Sample input**: infoDrink sprite -**Expected output**: -SPRITE (473 ml) -Calories: 194 kcal -Carbs: 50g -Protein: 0.2g -Fat: 0.1g - -### 1.3.3 View daily calories consumed: `calories` -Display current total calorie intake for the day -**Format**: calories -**Expected output**: Total calories: 100 cal - -### 1.3.4 View daily carbohydrates consumed: `carbs` -Display current total carbohydrates intake for the day -**Format**: carbs -**Expected output**: Total Carbohydrates: 150 grams - -### 1.3.5 View daily proteins consumed: `protein` -Display current total protein intake for the day -**Format**: protein -**Expected output**: Total proteins: 100 grams - -### 1.3.6 View daily fat consumed: `fat` -Display current total fat intake for the day -**Format**: fat -**Expected output**: Total fat: 50 grams - -### 1.3.7 View daily sugar consumed: `sugar` -Display current total sugar intake for the day -**Format**: sugar -**Expected output**: Total sugar: 20 grams - -### 1.3.8 View daily fiber consumed: `fiber` -Display current total fiber intake (g) for the day -**Format**: viewFiber -**Expected output**: Total fiber: 20 grams - -### 1.3.9 View daily water consumption: `viewWater` -Display current total water intake (in ml) for the day -**Format**: viewWater -**Expected output**: Total water intake: 0 ml - -## 1.4 For listing arrays -### 1.4.1 List meal intake: `listMeals` -List all the meals user inputted today -**Format**: listMeals -**Expected output**: -here's what you have eaten today -1.pizza (serving size: 1) - -### 1.4.2 List drink intake: `listDrinks` -List all the drinks user inputted today -**Format**: listDrinks -**Expected output**: -here's what you have drank today -1.sprite (serving size: 1) -Total water intake: 0 ml - -### 1.4.3 List entire food intake for the day: `listEverything` -List all the drinks and meals inputted today -**Format**: listEverything -**Expected output**: -here's what you have consumed today -1.pizza (serving size: 1) -2.sprite (serving size: 1) -Total water intake: 0 ml - -## 1.5 For editing existing data -### 1.5.1 Edit an existing meal after inserted: `editMeal` -For a meal that was inputted in the day, edit its serving size -**Format**: editMealServingSize INDEX s/NEW_SERVING_SIZE -**Sample input**: editMeal 2 s/2 -**Expected output**: Pizza has been edited to 2 servings - -### 1.5.2 Edit an existing drink after inserted: `editDrink` -For a drink that was inputted in the day, edit its serving size -**Format**: editDrinkServingSize INDEX s/NEW_SERVING_SIZE -**Sample input**: editDrink 1 s/200 -**Expected output**: Sprite has been edited to 200 ml - -### 1.5.3 Edit water intake after inserted: `editWater` -Edit serving size of total water intake -**Format**: editWaterIntake s/TOTAL_WATER_INTAKE -**Sample input**: editWaterIntake 200 -**Expected output**: Total water has been edited to 200 ml - -## 1.6 For deleting data -### 1.6.1 Delete certain meal entry: `deleteMeal` -For a meal that was inputted in the day, delete its input based on its index in the meal list -**Format**: deleteMeal INDEX -**Sample Input**: deleteMeal 1 -**Expected output**: Removed Chicken Rice From Meals - -### 1.6.2 Delete certain drink entry: `deleteDrink` -For a drink that was inputted in the day, delete its input based on its index in the drink list -**Format**: deleteDrink INDEX -**Sample input**: deleteDrink 1 -**Expected output:** Removed Iced Lemon Tea From Drinks - -## 1.7 For clearing data -### 1.7.1 Clear all entries: `clear` -Clear all entries in mealList and drinkList -**Format**: clear -**Expected output**: All entries have been deleted - -## 1.8: Exit program -### 1.8.1 Exit the app: `exit` -**Format**: exit -**Expected output**: Bye. Hope to see you again soon! +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. + +Users are able to track the meals, drinks, and exercises they have in a day and even past records. +*** +## Setup +To use the app please follow the setup procedures below: +1. Download the JAR file. +2. Place it into an empty folder. +3. Navigate to the folder you just created. +4. Run the JAR file. +*** +## Features List +### 1 Information for users +1. View all possible commands: `help` +2. View all pre-defined meals. These meals will have their nutritional content defined per serving size and can +be inputted immediately: `allMeals` +3. View all pre-defined drinks. These drinks will have their nutritional content defined per 100ml +and can be inputted immediately: `allDrinks` +4 Viewing all pre-defined exercises. These exercises will have the number of calories burnt for a +high/medium/low intensity workout defined per minute and can be inputted immediately: `allExercises` + +### 2 For user to add data +1. Adds a meal to the list of meals eaten today: `eat` +2. Add a drink list of drinks drank today: `drink` +3. Add exercise to the list of exercises done : `exercise` +4. Add a custom new meal on top of pre-defined meals: `newMeal` +5. Add a custom new drink on top of pre-defined drink: `newDrink` +6. Add a custom new exercise on top of pre-defined exercises: `newExercise` + +### 3 For user to retrieve data +1. Find nutritional content about a certain meal: `infoMeal` +2. Find nutritional content about a certain drink: `infoDrink` +3. Find the calories burnt per minute from a certain exercise: `infoExercise` +4. View daily calories consumed: `calories` +5. View daily carbohydrates consumed: `carbs` +6. View daily proteins consumed: `protein` +7. View daily fat consumed: `fat` +8. View daily sugar consumed: `sugar` +9. View daily fiber consumed: `fiber` +10. View daily water consumption: `viewWater` +11. View daily calories consumed: `caloriesBurnt` +12. View daily calories and water intake recommendation, based on current intake: `recommend` + +### 4 For users to view their lists and data +1. List today's meal intakes: `listMeals` +2. List today's drink intake: `listDrinks` +3. List today's exercises done: `listExercises` +4. List everything inputted today, inclusive of all meals, drinks and exercises: `listEverything` +5. List entire app's lifecycle meals intake, inclusive of previously inputted meals and their dates: `listMealsAll` +6. List entire app's lifecycle drinks intake, inclusive of previously inputted drinks and their dates: `listDrinksAll` +7. List entire app's lifecycle exercises done, inclusive of previously inputted exercises and their dates: `listExercisesAll` +8. List everything inputted for the entire app's lifecycle: `listEverythingAll` +9. List meal intake for a certain date: `listMeals d/[DATE]` +10. List drink intake for a certain date: `listDrinks d/[DATE]` +11. List exercise done for a certain date: `listExercises d/[DATE]` +12. List entire food intake and exercise done for a certain date: `listEverything d/[DATE]` + +### 5 For users to edit existing data +1. Edit the serving size of a meal that was inputted in the day: `editMeal` +2. Edit the serving size of a drink that was inputted in the day: `editDrink` +3. Edit total water intake of the day: `editWater` + +### 6 For users to delete existing data +1. Delete a meal entry: `deleteMeal` +2. Delete a drink entry: `deleteDrink` +3. Clear all entries of meals, drinks and exercise: `clear` +*** +## Exit the program +Close the appplication: `exit` From 6fb5484bca450b270174220630ca4f51c6adfd81 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 3 Apr 2024 07:21:18 +0800 Subject: [PATCH 175/274] Update developer guide and add diagrams --- docs/DeveloperGuide.md | 37 +++++- docs/diagrams/ArchitectureDiagram.puml | 44 +++++++ docs/diagrams/ExerciseClassDiagram.puml | 56 +++++++++ docs/diagrams/Style.puml | 119 ++++++++++++++++++ docs/diagrams/WaterClassDiagram.puml | 56 +++++++++ .../diagrams_png/ArchitectureDiagram.png | Bin 0 -> 23124 bytes .../diagrams_png/ExerciseClassDiagram.png | Bin 0 -> 43505 bytes 7 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 docs/diagrams/ArchitectureDiagram.puml create mode 100644 docs/diagrams/ExerciseClassDiagram.puml create mode 100644 docs/diagrams/Style.puml create mode 100644 docs/diagrams/WaterClassDiagram.puml create mode 100644 docs/diagrams/diagrams_png/ArchitectureDiagram.png create mode 100644 docs/diagrams/diagrams_png/ExerciseClassDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 6a7dce3a24..bdc4b562d0 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -2,11 +2,44 @@ ## Acknowledgements -{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} +Below are the references used on the project: +1. [Developer Guide](https://se-education.org/addressbook-level3/DeveloperGuide.html) +2. [User Guide](https://se-education.org/addressbook-level3/UserGuide.html) ## Design & implementation -{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +### Architecture + +The architecture diagram belows shows the overall design of our FitNUS CLI app and how each component interact with each other. + +![Architecture Diagram](../docs/diagrams/diagrams_png/ArchitectureDiagram.png) + +**Main Components of The Architecture** + +- `FitNUS`: FitNUS main code which runs the program until termination +- `Ui`: The user interface of the app that reads in user input +- `Storage`: Handles stored all `recipe`, `ingredient` and `shortcut` that the user has input +- `Parser`: Parses user input +- `User`: Handles user input and stores the `Exercise`, `Drink`, `Meal`, and `Water` created by user +- `Date`: Handles user's local machine date +- `Exercise`: Exercises completed and its duration created by user +- `Drink`: Drinks intake and its nutritional values created by user +- `Meal`: Meals intake and its nutritional values created by user +- `Water`: Water intake created by user + +### Exercise Component +![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseClassDiagram.png) + +1. Upon starting up the application, User will call `loadExercises` to fetch all data from `ExerciseList.txt` and add it into `exerciseListAll`. +2. A `User` class consists of zero to as many `Exercise` objects in the ArrayList. +3. Each `Exercise` contains exactly one enumeration of `ExerciseIntensity`. +### Drink Component + +### Water Component + +### Storage Component + +## Implementation ### Tracking Exercise Feature - Create a CSV which stores data regarding how many calories are burnt per hour for each exercise type (eg. swimming, running, cycling). diff --git a/docs/diagrams/ArchitectureDiagram.puml b/docs/diagrams/ArchitectureDiagram.puml new file mode 100644 index 0000000000..8d00a4bfda --- /dev/null +++ b/docs/diagrams/ArchitectureDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include Style.puml + +!include +!include + +hide footbox +hide members + +Package " "{ + Class Ui UI_COLOR + Class FitNUS MAIN_COLOR + Class Storage STORAGE_COLOR + Class Parser PARSER_COLOR + Class User COMMAND_COLOR + Class Date INGREDIENT_COLOR + Class Exercise RECIPE_COLOR + Class Drink RECIPE_COLOR + Class Meal RECIPE_COLOR + Class Water RECIPE_COLOR +} + +Class "<$user>" as Icon PERSON_COLOR +Class "<$documents>" as File PERSON_COLOR + +Icon .> Ui +FitNUS -> Ui + +Ui -> Parser +Ui --> User +Ui --> Storage + +User -> Date +User .> Parser +User .> Storage +User --> Exercise +User --> Meal +User --> Drink +User --> Water + +Parser -> User +Storage .> File + +@enduml \ No newline at end of file diff --git a/docs/diagrams/ExerciseClassDiagram.puml b/docs/diagrams/ExerciseClassDiagram.puml new file mode 100644 index 0000000000..9c6f7d5b5e --- /dev/null +++ b/docs/diagrams/ExerciseClassDiagram.puml @@ -0,0 +1,56 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor CLASS_ARROW_COLOR +skinparam classBackgroundColor CLASS_DIAGRAM_COLOR + +Class User { + # exerciseList: ArrayList + # exerciseListAll: ArrayList + # etc... + + + loadExercise (exerciseStorage: Storage): void + + loadExerciseCalories (exerciseCaloriesStorage: Storage): void + + saveExercise (exerciseStorage: Storage): void + + saveExerciseCalories (exerciseCaloriesStorage: Storage): void + + printExerciseList (exerciseListToPrint: ArrayList): void + + handleListExercises (): void + + handleListExercisesAll (): void + + handleListExercisesDate (command: String): void + + handleDeleteExercisesDate (command: String): void + + handleExercises (command: String): void + + handleCaloriesBurnt(): void + + etc()... +} + +Class Exercise { + - name: String + - duration: int + - intensity: ExerciseIntensity + - caloriesBurnt: int + - dateAdded: String + + exerciseDetails: HashMap + + Exercise(name: String, duration: int, intensity: ExerciseIntensity, currentDate: String) + + getName(): String + + getDuration(): int + + getIntensity(): ExerciseIntensity + + getDate(): String + + getCaloriesBurnt(): int + + handleInfoExercise(command: String): void + + printAvailableExercises(): void + + listAvailableExercises(): void + + getExerciseDetails(): HashMap + - setCaloriesBurnt(): void + - isValidIntensity(intensity: ExerciseIntensity): boolean +} + +Class "<>\nExerciseIntensity" as ExerciseIntensity { + HIGH + MEDIUM + LOW +} + +User -down-> "*" Exercise + +Exercise "*" *-down-> "1" ExerciseIntensity +@enduml \ No newline at end of file diff --git a/docs/diagrams/Style.puml b/docs/diagrams/Style.puml new file mode 100644 index 0000000000..7a868797d4 --- /dev/null +++ b/docs/diagrams/Style.puml @@ -0,0 +1,119 @@ +/' + '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 MAIN_COLOR #DBA800 + +!define PERSON_COLOR #ffb6c1 + +!define COMMAND_COLOR #728FCE + +!define PARSER_COLOR #00A36C +!define RECIPE_PARSER_COLOR #34A56F +!define INGREDIENT_PARSER_COLOR #1AA260 +!define SHORTCUT_PARSER_COLOR #A43A7C + +!define RECIPE_COLOR #C6DEFF +!define INGREDIENT_COLOR #5D3FD3 +!define SHORTCUT_COLOR #58699A + +!define RECIPE_LIST_COLOR #B0CFDE +!define RECIPE_LIST_COLOR_T1 #C9DFEC +!define INGREDIENT_LIST_COLOR #C9DFEC +!define SHORTCUT_LIST_COLOR #3A7CA4 + +!define STORAGE_COLOR #E69598 + +!define FILE_WRITER_COLOR #CBE57C + +!define FILE_COLOR #8B1EC4 + +!define SCANNER_COLOR #3E732E + +!define LOGGER_COLOR #FCBE85 + +!define UI_COLOR #C24641 +!define UI_COLOR_T1 #C11B17 + + +!define UI_COLOR_T2 #3FC71B +!define UI_COLOR_T3 #166800 +!define UI_COLOR_T4 #0E4100 + +!define CLASS_DIAGRAM_COLOR #ADD8E6 +!define CLASS_ARROW_COLOR #3E4255 + +!define OBJECT_DIAGRAM_COLOR #D0D7FE +!define OBJECT_ARROW_COLOR # + +!define INTERFACE_COLOR #C24641 +!define INTERFACE_COLOR_T1 #C11B17 + + +!define INTERFACE_COLOR_T2 #3FC71B +!define INTERFACE_COLOR_T3 #166800 +!define INTERFACE_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 USER_COLOR #000000 + +skinparam Package { + BackgroundColor #FFFFFF + BorderThickness 1 + FontSize 16 +} + +skinparam Class { + FontColor #000000 + FontSize 15 + BorderThickness 1 + BorderColor #000000 + 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 ArrowFontStyle bold +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/diagrams/WaterClassDiagram.puml b/docs/diagrams/WaterClassDiagram.puml new file mode 100644 index 0000000000..e4ba2bb9ca --- /dev/null +++ b/docs/diagrams/WaterClassDiagram.puml @@ -0,0 +1,56 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor CLASS_ARROW_COLOR +skinparam classBackgroundColor CLASS_DIAGRAM_COLOR + +Class User { + # exerciseList: ArrayList + # exerciseListAll: ArrayList + # etc + + + loadExercise (exerciseStorage: Storage): void + + loadExerciseCalories (exerciseCaloriesStorage: Storage): void + + saveExercise (exerciseStorage: Storage): void + + saveExerciseCalories (exerciseCaloriesStorage: Storage): void + + printExerciseList (exerciseListToPrint: ArrayList): void + + handleListExercises (): void + + handleListExercisesAll (): void + + handleListExercisesDate (command: String): void + + handleDeleteExercisesDate (command: String): void + + handleExercises (command: String): void + + handleCaloriesBurnt(): void + + etc() +} + +Class Exercise { + - name: String + - duration: int + - intensity: ExerciseIntensity + - caloriesBurnt: int + - dateAdded: String + + exerciseDetails: HashMap + + Exercise(name: String, duration: int, intensity: ExerciseIntensity, currentDate: String) + + getName(): String + + getDuration(): int + + getIntensity(): ExerciseIntensity + + getDate(): String + + getCaloriesBurnt(): int + + handleInfoExercise(command: String): void + + printAvailableExercises(): void + + listAvailableExercises(): void + + getExerciseDetails(): HashMap + - setCaloriesBurnt(): void + - isValidIntensity(intensity: ExerciseIntensity): boolean +} + +Class "<>\nExerciseIntensity" as ExerciseIntensity { + HIGH + MEDIUM + LOW +} + +User -down-> "*" Exercise + +Exercise "*" *-down-> "1" ExerciseIntensity +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/ArchitectureDiagram.png b/docs/diagrams/diagrams_png/ArchitectureDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..8ef492389cbc17ebdc0eecaea3e1284103db701f GIT binary patch literal 23124 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�G{dd)Rbf-(}s$RE1Pv1*!7u5W)NqiI~{@Z2I9 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 literal 0 HcmV?d00001 diff --git a/docs/diagrams/diagrams_png/ExerciseClassDiagram.png b/docs/diagrams/diagrams_png/ExerciseClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..c3db6d88f6854d01f66b78c880fdfe9e57ba2f57 GIT binary patch literal 43505 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 literal 0 HcmV?d00001 From 95be90d735d2a7d9683d84b22a8ffc1aee26ab8e Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 3 Apr 2024 08:15:16 +0800 Subject: [PATCH 176/274] Add sequence diagram --- docs/DeveloperGuide.md | 7 +++++ docs/diagrams/ArchitectureDiagram.puml | 12 ++++---- docs/diagrams/InfoMealSequenceDiagram.puml | 29 ++++++++++++++++++ docs/diagrams/Style.puml | 7 ++--- .../diagrams_png/ArchitectureDiagram.png | Bin 23124 -> 23068 bytes .../diagrams_png/InfoMealSequenceDiagram.png | Bin 0 -> 22036 bytes 6 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 docs/diagrams/InfoMealSequenceDiagram.puml create mode 100644 docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index bdc4b562d0..e2fee1e6f9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -41,6 +41,13 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a ## Implementation +### Information on a Particular Meal Feature +The `infoMeal` feature is executed on the `User` class. Let's say we want to find out about the nutrient values of chicken rice. +**Sample Input**: `infoMeal chicken rice` + +![InfoMeal Sequence Diagram](../docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png) + + ### Tracking Exercise Feature - Create a CSV which stores data regarding how many calories are burnt per hour for each exercise type (eg. swimming, running, cycling). - Implement a 'track exercise' function which will be parsed with the format: diff --git a/docs/diagrams/ArchitectureDiagram.puml b/docs/diagrams/ArchitectureDiagram.puml index 8d00a4bfda..dd1ecacd63 100644 --- a/docs/diagrams/ArchitectureDiagram.puml +++ b/docs/diagrams/ArchitectureDiagram.puml @@ -12,12 +12,12 @@ Package " "{ Class FitNUS MAIN_COLOR Class Storage STORAGE_COLOR Class Parser PARSER_COLOR - Class User COMMAND_COLOR - Class Date INGREDIENT_COLOR - Class Exercise RECIPE_COLOR - Class Drink RECIPE_COLOR - Class Meal RECIPE_COLOR - Class Water RECIPE_COLOR + Class User USER_COLOR + Class Date DATE_COLOR + Class Exercise LIST_COLOR + Class Drink LIST_COLOR + Class Meal LIST_COLOR + Class Water LIST_COLOR } Class "<$user>" as Icon PERSON_COLOR diff --git a/docs/diagrams/InfoMealSequenceDiagram.puml b/docs/diagrams/InfoMealSequenceDiagram.puml new file mode 100644 index 0000000000..9efe726cb3 --- /dev/null +++ b/docs/diagrams/InfoMealSequenceDiagram.puml @@ -0,0 +1,29 @@ +@startuml +!include Style.puml +skinparam ArrowFontStyle plain + +actor User + +participant ":Ui" as Ui MAIN_COLOR +participant ":Parser" as Parser PARSER_COLOR +participant "<>\nMeal" as Meal INTERFACE_COLOR + +User-> Ui : input: infoMeal chicken rice +activate Ui + +Ui -> Parser : handleCommand("infoMeal chicken rice") +activate Parser + +Parser -> Meal : handleInfoMeal("infoMeal chicken rice") +activate Meal +Meal --> Parser : parseInfoMeal("infoMeal chicken rice") +Parser -> Meal : return name +deactivate Parser + +Meal -> Meal : printNutrientDetails(name) +Meal --> Ui +deactivate Meal + +Ui --> User + +@enduml \ No newline at end of file diff --git a/docs/diagrams/Style.puml b/docs/diagrams/Style.puml index 7a868797d4..0a45a4699a 100644 --- a/docs/diagrams/Style.puml +++ b/docs/diagrams/Style.puml @@ -11,15 +11,15 @@ !define PERSON_COLOR #ffb6c1 -!define COMMAND_COLOR #728FCE +!define USER_COLOR #808080 !define PARSER_COLOR #00A36C !define RECIPE_PARSER_COLOR #34A56F !define INGREDIENT_PARSER_COLOR #1AA260 !define SHORTCUT_PARSER_COLOR #A43A7C -!define RECIPE_COLOR #C6DEFF -!define INGREDIENT_COLOR #5D3FD3 +!define LIST_COLOR #C6DEFF +!define DATE_COLOR #5D3FD3 !define SHORTCUT_COLOR #58699A !define RECIPE_LIST_COLOR #B0CFDE @@ -71,7 +71,6 @@ !define MODEL_COLOR_T3 #7B000E !define MODEL_COLOR_T4 #51000A -!define USER_COLOR #000000 skinparam Package { BackgroundColor #FFFFFF diff --git a/docs/diagrams/diagrams_png/ArchitectureDiagram.png b/docs/diagrams/diagrams_png/ArchitectureDiagram.png index 8ef492389cbc17ebdc0eecaea3e1284103db701f..49d782a3eef9bc5cc327a8b0d3f12ceb7d196bf0 100644 GIT binary patch literal 23068 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 T(+LOTo`1NerGEvdc{}t^#f8mT literal 23124 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�G{dd)Rbf-(}s$RE1Pv1*!7u5W)NqiI~{@Z2I9 z9!@L}jI9X6!pBOS{G|1X&BWB{m6t*gJ3+Qhzo9=S|AE=w_(KgA3(LY4Do(a?siLw5 zU8Q{0dmE!Pm(cmE|JjFKp>|QjH9IBsp4TL%i)Z$plTUR{DGN-BUi~-|&-aLPEY;-} zcX0X}hms04tA!J$Y!O{~&2brSwwta56(8A%p6ws@vNYYVtfS-#(N^O3I-9Z>%4_s2 zPD;{g4#0t0uwbduQ7@2tLz?ti{=m=c6o%QNt5!>2ew*D@`6#bdd;)YUHb`1g=(923 z-BS(uvmN=V+I~spj>>BS)t*h|%Ff(hXYc)fh_qbpa#LELjapgXf!OvVjp{*pqUWE! zABoecj~B`avbWwf#D!RtIEvj8OWTS`r9&V@%mt zC4Sn3G3@3;sk;H8*ITNjhw(EHw1+y4-JevYSr6}ot>+u6dnyQK8Tl4`TMK?^=03No zDCM^2nK=KN9F3kU31^M(EI4AJ`H1HfNX1-0IMW@HgH4mh{_+fDKVkUO zJ@ml+eRo^Sx3r8URmED}43lH7kxDS;u4ck@YmF3h^IA#}qxZ@YXIs@MHn^9n^!;M1 z2h%Yu8hQufZtVI;V+MA4Td@x;pQ+@O&|5Sdc0Ac^yT{FIsx48B8p-EmnBJG_yEHIJ z#>!u7uXd`IMHfu?qvc(_konNk{xSy6!CBq))-wwS1LNZ58P%=0a8`o|txpz-o|@Ur z(}Crc;I(IWG^YK__i}XtwW2`iCg6I$qn$$BlXoblxfQKqutC>ZWs3-X|6ESpo2Lnm z8o|+zVzTzFw>R|-i{kJ@j1~&=C*#(W^GelP3wlr8p9G;j8I1o>Zanck7UhiNG|f8i zg)VQ?a!MHp_(^JfnMq@lDoU`M$=qd;UVkVraFeQ|9r4w1U#NU7S^vHH-kZNLm@u#s z{F20*>E0tp7d|J_%Cu7bVnwP4&%Z<60C`i0&?kRPnM>}x*(>_p+9NTHkCFYTI40Yy z$ba`Wz;H8rr#`rd^wg|o~a$=g+&vY z^Gfmv@@BYnU3>Ie`S!`eS7!W}v&8toR$PlQ3V~ZQZ{oRm>?!%HjqQHgi+;Piu6y5M zS@9miWffrBvv77)od%S?_s{BFkstQVQ&j1;ivKMwC&zEUC|ks}ID{|GmBjhssg&Le zhhzR!#Mh`&dL%%eaP|F?$k&_R`adb?BMq+GY0;5>cZ^Q}?*+;yDZi@&pm>nZ3qRyj zr-oh{kU&TBZ?3V}O_pz}4;$^rdovuLPO`+2( zHI{->0D<#D5rM!xauge3G6K3z#<;FtrOe7IWeK;xAs)M)-6*P)r~Ik><6WJd;Hguj ziAS88f1eusT%*l?EkM|5ft!$VEhe%$3fKV<*MOroLG&qQ9XbsHk@-uIbaK9U~4}TI0|= zi^ym8ho=oe;RbbFV`F2w_?xj3gXU-^HJBv{`d{m1lRMuqENx_3akvanP+Sy&w0Mo7 z>9H|#^50uqHp`>J!?m@wFZb4^id;<>L8@ye->Mv+?conWQ5E#+)r~e2(>mAPRTxCb zPz!&XbNawqFs(|4)=iA_X%v5&W^ihO*$pU9P&#AUt8OXf6fTxs^A$lv^&zcVSI(EC zpP*p_fT4ZSOH*m-&gSRWu3eKiwf{BS3f-h@%^wxFyI%84Sdsu+pir(?O8e+bmU_5! zA^!_3D0YW4Hk2bXH>XpCwJWGZ$W-E!NV)1XGo=w3>;+ue)}Nv9uHZUj`~tqDh}KZ@ zE6k%bhYp||+C6h#8@>lq4Nxb#y1Lp4`mq!0y!0?qt5~RDm&aI$E@|Wq>9X=l{@{*s>gYprtcPNT6%>h7vO*WH(-+h5GxV(*riNuNI2H|392!}Je$oX^mj2eT{yOhPt_P07@#$K z-F2_he(Bl`e(xPo%?cKCognS#M0HI~AlcCC)wuyZr6eF@japw<{qkLjWvCC=Mr6IB zRfMgn1r3hAAP?YKO{J!&Fs~$_GIjajtR`@re0^@R|9iW%yz_K7@n#3~w${R~<`7n{ zRyMX11)eAM`Arita-~$?QkfX5H|X8SIU%Z)GG&Vc;xs!mv$fn$%cgIPDE5E+_yA=j z8%@L1lx`Oue<%gdEcCuljvVWL1A__K$`_kd({E{90e&>@`fJzgow-raRR&n> z%?^3w;NT$fJy3{ed(=2E7>`A+DT0*!&`dHyF> zhvh!lVYu#nLn9+m5fL#@jz9Aqkw9r_Xb>XsbO}=YPay-%mjGky<79wwC8R>xL~dK) zzh|hyFc0_9;U>Rf3Y-;1IQ89j6uz-n%4lC-v}@i-ZS-XNGc=roKe!Fd7YW*Q)Sm}Ei^yN6rZ zS*3w(LK)r+nwOz_Bw{o71xHX&a3CKU_z$}~I}@L6Y027Qs;v{m3;>xur+-Qh%#dZMaY082?>A^$0yg?*7*3&h3^=;@9~RBgCHn0Oxjm#vqI!frS#IU}kIz+$028 zud@faMd#peI|%p3rF#L3BZ~V0A3uFMpR^l_gEno0a5HqWI=o0>z-(>0zCJs92^6@4 zG-3%(>H$$*)h9z=MXhf0XX35bUi^6X7gqH%f_WLB>eANQ*}ixI#NhiY(M{kpp<`i< z=umRl93T8bv`?4&=ip;w?2hJk;=tHO(VLeO=r+HzM5%q#>I_AGCJ}o3j|tiAmE6A# zs2g`-=ms&_fYfVr1r=5L#4;}o+B4|ZJ30O!oT6-oB(M2YAXZ5E?!Pw?>(D|UDNr8~& z>^uGNf?m_(3{;|a+Oc~8 z5!KPrNq*=ef{NV+{wB4IzSb2vSrq!K|MDOI}QVOU8CjYWduP2n|AerA7sWDfJaS5 zM)ov5_;{+`Q!iZ{XW*Hl)l|*O`nucJj4&Hb5)d|kA_8-P{#Ycl7%w{iQzSoXkAoXD zG!0RBmkYHkOFz(U1L-9+G!({mfKvx#wZOOhEG#T!3JcP^m%L{v75^&C!JWrB zSs@z;vr?`&-OyHBou9u|gA(yPlv=Roz0Js(s!7nbi+8Pb03IQHAfGHChZ+*{_ASJS z7m~&J->YA+xS7LOZ?W6`J)0)4B+CXVU2t$#nt=*aQ(FsFBoM+BfaZ^woOFHD9CJ?# zu%7*Mb`8Izv@{$nT*m+2Mve1Ac}9gsMxm^NeY5Fb1KJo&G7GuB`2tDekAsF8wK5xq z2^>dJ>6VrY%`s-T7|ekYzxc%gk{ifqxW|V}$x_Al;{@DYVWJi>Ux~W2c<^fun0TqF zsW3E2V{|@lc0OR&VFV8S&2_E^0bf?yf#aiEpf2qC2HP#d-`}5Xu3vI%<+Di_F~kZa zWYpM$E;BLe3!(}ex65`0P+F|(Pk{H-4)NHmJN}XD8(A2|rl50xgbNW#$$aMLjU_vK zdaOF5Zkryri#c2zKLe4XJpwFb)7OL6fyTJ;*uCudZ-nfF}p8!3mH_I=qA{oqlRUHgKKO!no5q z06+IaSPp1M-#}KO(D!BjDs8ZWyXE_{b zyyuJ~jYBY0Xm&^y^GM3d`r*X_GcOvO6vw#@czh5}X1~4rdf{#5`D|*auU_41#uE%f zLQ#a)vwvc!S2~%5gapBvIH7=fDhH?$@C#{;f^sj6GRlAtTo@t{8k61^xKR0fvT-F{ZQ_`6Kj01N( zAz>V-OzmFbQgU)hT-NV_0uJ0BL>D6f-w5VA|B}vHz;Qu7afYB!rjX9iE`j^Y7%3>w zs_5zJS_3a;+;AY2`6YzR$l98kgydaBgh&AX+y!TiU;)^L;5X<6GHIgWFn^Ag1@6RO zH%|nA*X>BR49ZPRM1+Ed1NQu2>L<=s+za0q28Z_<#yIC!zKYZF^14F)n4yLgLM>Pa zt$S(#HyY%u%L38BKbTuu3gn_c^Fo<~w7wt*@u53Euj6f6K>#Y0F9 zVv6l=1K0bUO564U8b?s@)w&%;cVvqj(f%)aPU=1KfY)W223k1&v z_<9irVmB`&H3MqDv9Xa?-6&~jXsEAGv!X%;`Ni+;?Z-`J65LkPb(Cae8c?r8`8(?v zc64#5GE!1cr)m!2WIMcOU5*bv1O}q5sN6!ZhVAXgKNz8ru`-$UzPJ3A^`^LZ6B3nn z(zNRrb^|#K4h47EPM$YJ5twC)(9N`igcK;Ipxcp1_V&wtsX((03k!o$|M2^_xc<7O z3OkS$4lb@d(5H~^q(Ue14zDocw*w$}K{6PIWFHwG-Z;gS22_*RRo$W6sp=FkxHr`P zx3I`xWtsvG>EJHKXQQ@I9v+_CPk4a{_Ytxh?hH~^{Yz7Lk0s2B(1?Lp{lN}+R{lLo zaYt!<@UsM5RueR}ou~qGkUS9OCxGe&1qb`O8_l*LXMH$XBz@nCzkWHEi5c-Y_@<7 z+u?=zDkOws)LsmyYqm8QNX7;8f2hn%^$vLrThNy$Qa!omlDeX>O=g84-a4pQ0qYbT zEJN+8@%IvgzQYLJXjYTXD5wb;=PTVcKf~`Uth4v@^f0LwD0aP}lSTb|<7&YKK#G!T zrt}|mXy{gJcl?Dq5P8?KKcB;L%Ijbk$X37(_NyG%tj0ce)aqjMr0{N4C(I=3d0Y#{Rl{pAu3mNH6JY2~!{2_TlH*KQUN9 zBs`hYL>qKa=Ya~ihz@ol=e4=O~Hp%u*9IPA%hexPyn^ zs$76dFs*vg1G+~L?QFgdLKe#RVq;4bP940w@_S>oByLHc)rmn>IIkY>uOB3S9n0v= zP;Uao3#Lf>bQcmu-S7UtVy-+M%5{%dIEq49CWD5w*oh%@Gj_5ovW!VtvMa+VSteu) zQzSBWN|sLcbwrr5PuA>Y%QhHGgF)_7=bn4c`P_T{z4zbe{e0f%`91G%f4{%4W$EFe zbzs6OW=Qaj02KqklA)h61s)2NE_WY=7Slz9U5yot(+4H#53Dt@ZjU-Vj@?heoI7*o z{n!Awxnx@>Wy~c15%8^%GqpR*gtb8sEP{6R)0FsdIM8MTT`48EA-E%^h1*0M&|1Jt zT=B}v%I`r6(4w+1O&%o6IZ7k1wcX#jL^JBb0 zg;-$3dZhGIz=_krbU}X-^bhg!9;cIHblP4X>5B+HlS9%seGYKu$6p^${|azqj)TRo zD3M}{l-1Qhc!sDKz!r8nISK%!#LGDR5R5?Z1y`@&|N0AaFbEU?Y0F8yLM>_i{5c*s zrNM=X2sZioPGqg0g6~J}IF<(kAj-!I3QYot!c$jm?Qly8Xcq}I3PAFFl&`v^#1j~S zGCe5#O&|EMI&K;w_UMCHnj)XF?3d{Dh4IrboM6laYM&?4|Hh&OjOD1(5d!ueOc-|0 zXMvm|o!nYSM4kY3{Sw$<$+e-Op}DZQ3bS|}lsY@FE+1G5si?TT8{1_4nVBPPK0F4USrY%?%;WkV?Ar7Z zUW29aIxI*X!0ZN8&edF9T^*$Cz>&MTxmCFD8T-=CY2Khkse2efOlHp&p_eW_y6Dn_ zSr6n{-IURHB^V+`F|>%zf-Lg-7#F~v)kAtg0(2sZy2mmM(F0e;C(Q8Y@ z6fa#}U1?YrAka9nB4l+;W~hhn{L zfgVULVNlx*{1OQ}#O?2JVJ}K?V=&Uc7 zn-Y_4{GMOz%1FSZ$_J6Y?NbfeVuR%CC?P&XYhg zTgsK+=F`(vQ~563`p!j?2^hp-Edl4@A4gy^0rxs-49}E&^0%p ztBdEMqGrZ)y|&3Uc1oIRZSh?kle@(1FFQ>g7W<~0!ypu`e;TGh2C&n;%__E!m}fO( zMV)!!GtJh|ULjH_E@Qa$Ejean<*F1`vrEzavLC_N$T4w^Q(XMlyuQMuTEFuZ$`b^( z+iy3p3Y(dB^Tp>^>DCC&L4|z%sP#LPh)6eQ#lisn zHiy}>>ldJw#&T?>NPEMjLvtw&a-8ss|N`FJ@m@xZSH}}ugqO(u>EwxC>y`aa@WS#CU zV@pf%)xyd+U-$E#WpUdos6f=i{i5nug?5AA!_@^dHJSP?uHo?ItVQc!e*Of zu6-1pS_EZ5Y&+OK<`S)^6pA=@h%?bx++P6W>+CoJX?{1=4)d;u!<9Nq46Vxr`)5kl zW4BKpbH5ytElk`_Oil_~L3l4_Y}O}1L*TetPF)I94NzobTDr^mX=qyj>ZH4=4z zoh=$!k+wdI&&pnEoF4JnIw$L&JJrX~S9RqLFShA4RmPakBCH%Qxfl}ZCr~|nJW_GW*tD6CN2K3*Zkj_9hhX{Z(c9OJmBmGL}NRIZ ztD{-Q2xCF*%_Jxj25NH;~kpzArX0heXwFF*SH`oMnT@5e{Y5ZXna7${&78zBJyM~fqc*K`5{M==T;Eq^T zmVaSx;-+=)yT&1WXi+(BpXB*(HP2jZ`8Bk&C4f#$QF)^dPbtxo8`npvSjlMpIJ6^< zh%aQ14pLQX^zFYh5=C*zv(1%k+Z)eC49rLG>-PRQY|T93fn2BrvA!dc(uidgs?-WT zK+4huD)D3v=_!ELC_9a*`7NFadPBu`*x)wl^W>^8`a1=~g!{$TiMSV)FUP}$!%mE= zJmCVSf?84T(okuX_USV0tRoXB&RfI}ol|U$%A56{%J28YyU)Und)5YhTKu9yfBJG7 z5+c$LMBwG8S&J_)dW3Z}AodM@2q2|30R+g(E@)3fAmU=d`2|ah_7mT+Kux#A3U1Aw z9yx5;UNgUWO8OMk+sL~Cf$qLaQ7cZ?x`xwu%oR*^?4N(Vim&(&LD)qig;ob4^0?F@ zJdeWduTbhCt*5E(d$qx8B-M~e8ht2PXAAsaAX_D;)Fd2NaMX*qYJbz5u8!-jkj~Lz z^j!RFL-v8LM6$IL8lU6zo4XCx4!fgJZX&n)&4H0^3bXkMiG6rEOw>6lxBNg+p6b*u zWQCo7U;__bnu4(h=wqykznLZBSt!DXA6#@_{-rBAy`??rdvTf}SE+>87o8ImjI3K` z%kqsr@EQ4=)9?W(@cI$`HU8@3c;*<3)Q0YOg_ZuNA?%vPv zwY{sqr4$BR?_;d2=Rp>6lg9B<(v-LNr^#EP z(QEGo1oH=a?MyVlR2^Tkl_41F|7r^lxa^UK3l^=BtP;7MndjCqHzAne_XESDmlm|a z9Wj{>qVeC;qx}tQ+W%nr>xh_`Sa(kk;DF=zNs5c(aB*?z);<1{`mO`CX#hnUSO+Yb z^b8C!Kl$yz&<|*GzZ?taR$;RYRPqPqIG~CICAtWA)?vIopUwaPc!Fz}IUK}))Yi?7 r@8n7C3NYI*z6ch4*!~M^=oXgD99SI+Wk>_`&Ihh&7^uHhy&3dRbk8LI diff --git a/docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png b/docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..3b34fd8f59b39483fdda0eff74cb85f5ac54afdf GIT binary patch literal 22036 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 oy$GKIzXu=xt|cK!# Date: Tue, 9 Apr 2024 19:13:35 +0800 Subject: [PATCH 177/274] Add PPP Draft --- docs/team/jasonlienardi.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 docs/team/jasonlienardi.md diff --git a/docs/team/jasonlienardi.md b/docs/team/jasonlienardi.md new file mode 100644 index 0000000000..63a0683abe --- /dev/null +++ b/docs/team/jasonlienardi.md @@ -0,0 +1,10 @@ +# Jason Lienardi's Project Portfolio Page + +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. + +Given below are my contributioins to the project. +* New Feature: added a newMeal command which allows users to store the nutrient details of their favorite meals in the app. +* New Feature: added a newDrink command which allows users to store the nutrient details of their favorite drinks in the app. +* New Feature: added a newExercise command which allows users to store the details regarding the calories burnt for a certian exercise. +* Code contributed: https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23 From 72908041466c39ca6f1ed9586926d944507ab045 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 15:06:28 +0800 Subject: [PATCH 178/274] Add PPP document --- docs/team/claribelho.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/team/claribelho.md b/docs/team/claribelho.md index e69de29bb2..2f78cfd3ff 100644 --- a/docs/team/claribelho.md +++ b/docs/team/claribelho.md @@ -0,0 +1,11 @@ +# Claribel Ho Jia Huan's Project Portfolio Page + +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. + +Given below are my contributions to the project: +* Code Contribution: [Individual Reposense](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=w14&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=claribelho&tabRepo=AY2324S2-CS2113-W14-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false) +* Feature: User Class + * Methods to handle View, List and Add commands +* Feature: Date Class + * Gets System Date and Time for use when storing data From 95068aa28c545cb1f23a6620721fdb0558c7a7e0 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 10 Apr 2024 15:15:18 +0800 Subject: [PATCH 179/274] Add PPP for bryancastorius --- docs/team/bryancastorius.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 docs/team/bryancastorius.md diff --git a/docs/team/bryancastorius.md b/docs/team/bryancastorius.md new file mode 100644 index 0000000000..c1e13a345d --- /dev/null +++ b/docs/team/bryancastorius.md @@ -0,0 +1,16 @@ +# Bryan Castorius' Project Portfolio Page + +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. + +Given below are my contributions to the project. +* Code contributed: [Individual Reposense](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=w14&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23) +* Feature: Drink and Water Class + * Methods to handle inserting water and drink volume and viewing the intakes. +* Feature: Recommendations + * Method to provide the recommended amount of water and calories intake. +* Add Developer Guide + * Architecture diagrams + * Class diagrams + * Object diagrams + * Sequence diagramsS \ No newline at end of file From d0fea39f36bd7b4d4a094891fb440c0002bce31b Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 10 Apr 2024 15:16:46 +0800 Subject: [PATCH 180/274] Update PPP for bryancastorius --- docs/team/bryancastorius.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/team/bryancastorius.md b/docs/team/bryancastorius.md index c1e13a345d..30ad788668 100644 --- a/docs/team/bryancastorius.md +++ b/docs/team/bryancastorius.md @@ -13,4 +13,4 @@ Given below are my contributions to the project. * Architecture diagrams * Class diagrams * Object diagrams - * Sequence diagramsS \ No newline at end of file + * Sequence diagrams \ No newline at end of file From 881e1058d344ada38f95ef596922323708dc078b Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 10 Apr 2024 15:33:11 +0800 Subject: [PATCH 181/274] Reorganize StorageManager --- META-INF/MANIFEST.MF | 3 + data/ExerciseList.txt | 1 + src/main/java/seedu/fitnus/Ui.java | 16 +- .../seedu/fitnus/storage/StorageManager.java | 347 +++++++++++++++++ src/main/java/seedu/fitnus/user/User.java | 363 +----------------- src/test/java/seedu/fitnus/user/UserTest.java | 5 +- 6 files changed, 382 insertions(+), 353 deletions(-) create mode 100644 META-INF/MANIFEST.MF create mode 100644 src/main/java/seedu/fitnus/storage/StorageManager.java diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..3a22cf9875 --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: seedu.fitnus.FitNus + diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt index 21b6f74f86..f7416e52ee 100644 --- a/data/ExerciseList.txt +++ b/data/ExerciseList.txt @@ -1 +1,2 @@ badminton,20,HIGH,02-04-2024 +running,10,HIGH,10-04-2024 diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index e0206f31e9..e49748d358 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -2,6 +2,7 @@ import seedu.fitnus.parser.Parser; import seedu.fitnus.storage.Storage; +import seedu.fitnus.storage.StorageManager; import seedu.fitnus.user.User; import java.util.Scanner; @@ -17,7 +18,8 @@ public class Ui { private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); - private User user = new User(mealStorage, drinkStorage, exerciseStorage, + private User user = new User(); + private StorageManager storageManager = new StorageManager(mealStorage, drinkStorage, exerciseStorage, mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); private Parser parser = new Parser(user); @@ -43,12 +45,12 @@ public void handleExit() { System.out.println("Bye. Hope to see you again soon!"); input.close(); isExit = true; - user.saveMeal(mealStorage); - user.saveDrink(drinkStorage); - user.saveExercise(exerciseStorage); - user.saveMealNutrients(mealNutrientStorage); - user.saveDrinkNutrients(drinkNutrientStorage); - user.saveExerciseCalories(exerciseCaloriesStorage); + storageManager.saveMeal(mealStorage); + storageManager.saveDrink(drinkStorage); + storageManager.saveExercise(exerciseStorage); + storageManager.saveMealNutrients(mealNutrientStorage); + storageManager.saveDrinkNutrients(drinkNutrientStorage); + storageManager.saveExerciseCalories(exerciseCaloriesStorage); } /** diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java new file mode 100644 index 0000000000..3c890ea54c --- /dev/null +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -0,0 +1,347 @@ +package seedu.fitnus.storage; + +import seedu.fitnus.*; +import seedu.fitnus.user.User; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.parser.Parser; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Map; + +public class StorageManager { + public StorageManager(Storage mealStorage, Storage drinkStorage, Storage exerciseStorage, + Storage mealNutrientStorage, Storage drinkNutrientStorage, Storage exerciseCaloriesStorage) { + try { + loadMealNutrient(mealNutrientStorage); + loadDrinkNutrient(drinkNutrientStorage); + loadExerciseCalories(exerciseCaloriesStorage); + loadMeal(mealStorage); + loadDrink(drinkStorage); + loadExercise(exerciseStorage); + } catch (NegativeValueException e) { + System.out.println("Nutrient details must be greater than 0"); + } + } + + /** + * Loads any previously stored mealList from the user and + * adds the saved meals into the ArrayList mealListAll. + * + * @param mealStorage contains filePath and folderPath of where the saved meals are stored. + */ + public void loadMeal(Storage mealStorage) { + try { + ArrayList mealStorageList = mealStorage.readFile(); + if (!mealStorageList.isEmpty()) { + for (String s : mealStorageList) { + Parser.parseMealStorage(s); + String mealDescription = Parser.mealStorageDescription; + int mealSize = Parser.mealStorageSize; + String currentDate = Parser.mealStorageDate; + User.mealListAll.add(new Meal(mealDescription, mealSize, currentDate)); + } + } + Date currentDate = new Date(); + String todayDate = currentDate.getDate(); + for (Meal m : User.mealListAll) { + if (m.getDate().equals(todayDate)) { + User.mealList.add(m); + } + } + User.mealListAll.removeAll(User.mealList); + } catch (FileNotFoundException e) { + mealStorage.createFile(); + } + } + + /** + * Loads any previously stored drinkList from the user and + * adds the saved drinks into the ArrayList drinkListAll. + * + * @param drinkStorage contains filePath and folderPath of where the saved drinks are stored. + */ + public void loadDrink(Storage drinkStorage) { + try { + ArrayList drinkStorageList = drinkStorage.readFile(); + if (!drinkStorageList.isEmpty()) { + for (String s : drinkStorageList) { + Parser.parseDrinkStorage(s); + String drinkDescription = Parser.drinkStorageDescription; + String drinkDate = Parser.drinkStorageDate; + int drinkSize = Parser.drinkStorageSize; + if (drinkDescription.equals("water")) { + User.waterListAll.add(new Water(drinkSize, drinkDate)); + } else { + User.drinkListAll.add(new Drink(drinkDescription, drinkSize, drinkDate)); + } + } + } + Date currentDate = new Date(); + String todayDate = currentDate.getDate(); + for (Drink d : User.drinkListAll) { + if (d.getDate().equals(todayDate)) { + User.drinkList.add(d); + } + } + User.drinkListAll.removeAll(User.drinkList); + for (Water w : User.waterListAll) { + if (w.getDate().equals(todayDate)) { + User.waterList.add(w); + } + } + User.waterListAll.removeAll(User.waterList); + } catch (FileNotFoundException e) { + drinkStorage.createFile(); + } + } + + /** + * Loads any previously stored exerciseList from the user and + * adds the saved exercises into the ArrayList exerciseListAll. + * + * @param exerciseStorage contains filePath and folderPath of where the saved exerciseList was stored. + */ + public void loadExercise(Storage exerciseStorage) { + try { + ArrayList exerciseStorageList = exerciseStorage.readFile(); + if (!exerciseStorageList.isEmpty()) { + for (String s : exerciseStorageList) { + Parser.parseExerciseStorage(s); + String exerciseDescription = Parser.exerciseStorageDescription; + int exerciseDuration = Parser.exerciseStorageDuration; + ExerciseIntensity exerciseIntensity = Parser.exerciseStorageIntensity; + String currentDate = Parser.exerciseStorageDate; + User.exerciseListAll.add(new Exercise(exerciseDescription, exerciseDuration, exerciseIntensity, + currentDate)); + } + } + Date currentDate = new Date(); + String todayDate = currentDate.getDate(); + for (Exercise e : User.exerciseListAll) { + if (e.getDate().equals(todayDate)) { + User.exerciseList.add(e); + } + } + User.exerciseListAll.removeAll(User.exerciseList); + } catch (FileNotFoundException e) { + exerciseStorage.createFile(); + } catch (UnregisteredExerciseException e) { + System.out.println("Sorry that meal is not registered in the database. Please check the spelling and " + + "try again"); + } + } + + /** + * Loads the file where pre-defined meals and their nutrient counts are stored. + * + * @param mealNutrientStorage contains filePath and folderPath of where the pre-defined meals are stored. + */ + public void loadMealNutrient(Storage mealNutrientStorage) throws NegativeValueException{ + try { + ArrayList mealNutrientList = mealNutrientStorage.readFile(); + if (!mealNutrientList.isEmpty()) { + for (String s : mealNutrientList) { + Parser.parseMealNutrient(s); + String description = Parser.mealNutrientDescription; + int calories = Parser.mealNutrientCalories; + int carbs = Parser.mealNutrientCarbs; + int protein = Parser.mealNutrientProtein; + int fat = Parser.mealNutrientFat; + int fiber = Parser.mealNutrientFiber; + int sugar = Parser.mealNutrientSugar; + Meal.nutrientDetails.put(description, new int[]{calories, carbs, protein, fat, fiber, sugar}); + } + } + } catch (FileNotFoundException e) { + mealNutrientStorage.createFile(); + } + } + + /** + * Loads the file where pre-defined drinks and their nutrient counts are stored. + * + * @param drinkNutrientStorage contains filePath and folderPath of where the pre-defined drinks are stored. + */ + public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValueException{ + try { + ArrayList drinkNutrientList = drinkNutrientStorage.readFile(); + if (!drinkNutrientList.isEmpty()) { + for (String s : drinkNutrientList) { + Parser.parseDrinkNutrient(s); + String description = Parser.drinkNutrientDescription; + int calories = Parser.drinkNutrientCalories; + int carbs = Parser.drinkNutrientCarbs; + int sugar = Parser.drinkNutrientSugar; + int protein = Parser.drinkNutrientProtein; + int fat = Parser.drinkNutrientFat; + Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); + } + } + } catch (FileNotFoundException e) { + drinkNutrientStorage.createFile(); + } + } + + /** + * Loads the file where pre-defined exercises and the number of calories burnt per minute for + * respective intensities (HIGH, MEDIUM, LOW) are stored. + * + * @param exerciseCaloriesStorage contains filePath and folderPath of where the pre-defined exercises are stored. + */ + public void loadExerciseCalories(Storage exerciseCaloriesStorage) throws NegativeValueException { + try { + ArrayList exerciseCaloriesList = exerciseCaloriesStorage.readFile(); + if (!exerciseCaloriesList.isEmpty()) { + for (String s : exerciseCaloriesList) { + Parser.parseExerciseCalories(s); + String description = Parser.exerciseCaloriesDescription; + int caloriesHigh = Parser.exerciseCaloriesHigh; + int caloriesMedium = Parser.exerciseCaloriesMedium; + int caloriesLow = Parser.exerciseCaloriesLow; + Exercise.exerciseDetails.put(description, new int[]{caloriesHigh, caloriesMedium, caloriesLow}); + } + } + } catch (FileNotFoundException e) { + exerciseCaloriesStorage.createFile(); + } + } + + /** + * Saves the user's meals when the user exits the program. + * Meals from the current day is saved with the date into the .txt file. + * + * @param mealStorage contains filePath and folderPath of where the saved meals are stored. + */ + public void saveMeal(Storage mealStorage) { + for (Meal meal : User.mealListAll) { + String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); + mealStorage.appendTextContent(mealSavedData); + } + for (Meal meal : User.mealList) { + String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); + mealStorage.appendTextContent(mealSavedData); + } + try { + mealStorage.writeFile(mealStorage.textContent); + } catch (IOException e) { + System.out.println("Failed saving meal: " + e.getMessage()); + } + } + + /** + * Saves the user's drinks when the user exits the program. + * MealDrinkss from the current day is saved with the date into the .txt file. + * + * @param drinkStorage contains filePath and folderPath of where the saved drinksList are stored. + */ + public void saveDrink(Storage drinkStorage) { + for (Water water : User.waterListAll) { + String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); + drinkStorage.appendTextContent(waterSavedData); + } + for (Water water : User.waterList) { + String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); + drinkStorage.appendTextContent(waterSavedData); + } + for (Drink drink : User.drinkListAll) { + String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); + drinkStorage.appendTextContent(drinkSavedData); + } + for (Drink drink : User.drinkList) { + String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); + drinkStorage.appendTextContent(drinkSavedData); + } + try { + drinkStorage.writeFile(drinkStorage.textContent); + } catch (IOException e) { + System.out.println("Failed saving drink: " + e.getMessage()); + } + } + + /** + * Saves the user's exercises when the user exits the program. + * Exercises from the current day is saved with the date into the .txt file. + * + * @param exerciseStorage contains filePath and folderPath of where the saved exerciseList are stored. + */ + public void saveExercise(Storage exerciseStorage) { + for (Exercise exercise : User.exerciseListAll) { + String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," + + exercise.getIntensity() + "," + exercise.getDate(); + exerciseStorage.appendTextContent(exerciseSavedData); + } + for (Exercise exercise : User.exerciseList) { + String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," + + exercise.getIntensity() + "," + exercise.getDate(); + exerciseStorage.appendTextContent(exerciseSavedData); + } + try { + exerciseStorage.writeFile(exerciseStorage.textContent); + } catch (IOException e) { + System.out.println("Failed saving drink: " + e.getMessage()); + } + } + + //@@author jasonlienardi + public void saveMealNutrients(Storage mealNutrientStorage) { + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : Meal.nutrientDetails.entrySet()) { + result.append(entry.getKey()).append(","); + int[] values = entry.getValue(); + for (int value : values) { + result.append(value).append(","); + } + result = new StringBuilder(result.substring(0, result.length() - 1)); + result.append("\n"); + } + mealNutrientStorage.appendTextContent(result.toString()); + try { + mealNutrientStorage.writeFile(mealNutrientStorage.textContent); + } catch (IOException e) { + System.out.println("Failed adding meal nutrients: " + e.getMessage()); + } + } + + //@@author jasonlienardi + public void saveDrinkNutrients(Storage drinkNutrientStorage) { + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : Drink.nutrientDetails.entrySet()) { + result.append(entry.getKey()).append(","); + int[] values = entry.getValue(); + for (int value : values) { + result.append(value).append(","); + } + result = new StringBuilder(result.substring(0, result.length() - 1)); + result.append("\n"); + } + drinkNutrientStorage.appendTextContent(result.toString()); + try { + drinkNutrientStorage.writeFile(drinkNutrientStorage.textContent); + } catch (IOException e) { + System.out.println("Failed adding drink nutrients: " + e.getMessage()); + } + } + + //@@author jasonlienardi + public void saveExerciseCalories(Storage exerciseCaloriesStorage) { + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : Exercise.exerciseDetails.entrySet()) { + result.append(entry.getKey()).append(","); + int[] values = entry.getValue(); + for (int value : values) { + result.append(value).append(","); + } + result = new StringBuilder(result.substring(0, result.length() - 1)); + result.append("\n"); + } + exerciseCaloriesStorage.appendTextContent(result.toString()); + try { + exerciseCaloriesStorage.writeFile(exerciseCaloriesStorage.textContent); + } catch (IOException e) { + System.out.println("Failed adding exercise calories: " + e.getMessage()); + } + } +} diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 8b075b5067..4b7f1f7a3b 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -33,333 +33,25 @@ public class User { public static final int RECOMMEND_WATER_INTAKE = 2600; public static final int RECOMMEND_CALORIE_INTAKE = 2200; // list for today - protected static ArrayList mealList; - protected static ArrayList drinkList; - protected static ArrayList waterList; - protected static ArrayList exerciseList; + public static ArrayList mealList; + public static ArrayList drinkList; + public static ArrayList waterList; + public static ArrayList exerciseList; // list for all dates except today - protected static ArrayList mealListAll; - protected static ArrayList drinkListAll; - protected static ArrayList waterListAll; - protected static ArrayList exerciseListAll; - - public User(Storage mealStorage, Storage drinkStorage, Storage exerciseStorage, - Storage mealNutrientStorage, Storage drinkNutrientStorage, Storage exerciseCaloriesStorage) { - try { - mealList = new ArrayList<>(); - drinkList = new ArrayList<>(); - exerciseList = new ArrayList<>(); - waterList = new ArrayList<>(); - mealListAll = new ArrayList<>(); - drinkListAll = new ArrayList<>(); - exerciseListAll = new ArrayList<>(); - waterListAll = new ArrayList<>(); - loadMealNutrient(mealNutrientStorage); - loadDrinkNutrient(drinkNutrientStorage); - loadExerciseCalories(exerciseCaloriesStorage); - loadMeal(mealStorage); - loadDrink(drinkStorage); - loadExercise(exerciseStorage); - } catch (NegativeValueException e) { - System.out.println("Nutrient details must be greater than 0"); - } - } - - /** - * Loads any previously stored mealList from the user and - * adds the saved meals into the ArrayList mealListAll. - * - * @param mealStorage contains filePath and folderPath of where the saved meals are stored. - */ - public void loadMeal(Storage mealStorage) { - try { - ArrayList mealStorageList = mealStorage.readFile(); - if (!mealStorageList.isEmpty()) { - for (String s : mealStorageList) { - Parser.parseMealStorage(s); - String mealDescription = Parser.mealStorageDescription; - int mealSize = Parser.mealStorageSize; - String currentDate = Parser.mealStorageDate; - mealListAll.add(new Meal(mealDescription, mealSize, currentDate)); - } - } - Date currentDate = new Date(); - String todayDate = currentDate.getDate(); - for (Meal m : mealListAll) { - if (m.getDate().equals(todayDate)) { - mealList.add(m); - } - } - mealListAll.removeAll(mealList); - } catch (FileNotFoundException e) { - mealStorage.createFile(); - } - } - - /** - * Loads any previously stored drinkList from the user and - * adds the saved drinks into the ArrayList drinkListAll. - * - * @param drinkStorage contains filePath and folderPath of where the saved drinks are stored. - */ - public void loadDrink(Storage drinkStorage) { - try { - ArrayList drinkStorageList = drinkStorage.readFile(); - if (!drinkStorageList.isEmpty()) { - for (String s : drinkStorageList) { - Parser.parseDrinkStorage(s); - String drinkDescription = Parser.drinkStorageDescription; - String drinkDate = Parser.drinkStorageDate; - int drinkSize = Parser.drinkStorageSize; - if (drinkDescription.equals("water")) { - waterListAll.add(new Water (drinkSize, drinkDate)); - } else { - drinkListAll.add(new Drink(drinkDescription, drinkSize, drinkDate)); - } - } - } - Date currentDate = new Date(); - String todayDate = currentDate.getDate(); - for (Drink d : drinkListAll) { - if (d.getDate().equals(todayDate)) { - drinkList.add(d); - } - } - drinkListAll.removeAll(drinkList); - for (Water w : waterListAll) { - if (w.getDate().equals(todayDate)) { - waterList.add(w); - } - } - waterListAll.removeAll(waterList); - } catch (FileNotFoundException e) { - drinkStorage.createFile(); - } - } - - /** - * Loads any previously stored exerciseList from the user and - * adds the saved exercises into the ArrayList exerciseListAll. - * - * @param exerciseStorage contains filePath and folderPath of where the saved exerciseList was stored. - */ - public void loadExercise(Storage exerciseStorage) { - try { - ArrayList exerciseStorageList = exerciseStorage.readFile(); - if (!exerciseStorageList.isEmpty()) { - for (String s : exerciseStorageList) { - Parser.parseExerciseStorage(s); - String exerciseDescription = Parser.exerciseStorageDescription; - int exerciseDuration = Parser.exerciseStorageDuration; - ExerciseIntensity exerciseIntensity = Parser.exerciseStorageIntensity; - String currentDate = Parser.exerciseStorageDate; - exerciseListAll.add(new Exercise(exerciseDescription, exerciseDuration, exerciseIntensity, - currentDate)); - } - } - Date currentDate = new Date(); - String todayDate = currentDate.getDate(); - for (Exercise e : exerciseListAll) { - if (e.getDate().equals(todayDate)) { - exerciseList.add(e); - } - } - exerciseListAll.removeAll(exerciseList); - } catch (FileNotFoundException e) { - exerciseStorage.createFile(); - } catch (UnregisteredExerciseException e) { - System.out.println("Sorry that meal is not registered in the database. Please check the spelling and " + - "try again"); - } - } - - /** - * Loads the file where pre-defined meals and their nutrient counts are stored. - * - * @param mealNutrientStorage contains filePath and folderPath of where the pre-defined meals are stored. - */ - public void loadMealNutrient(Storage mealNutrientStorage) throws NegativeValueException{ - try { - ArrayList mealNutrientList = mealNutrientStorage.readFile(); - if (!mealNutrientList.isEmpty()) { - for (String s : mealNutrientList) { - Parser.parseMealNutrient(s); - String description = Parser.mealNutrientDescription; - int calories = Parser.mealNutrientCalories; - int carbs = Parser.mealNutrientCarbs; - int protein = Parser.mealNutrientProtein; - int fat = Parser.mealNutrientFat; - int fiber = Parser.mealNutrientFiber; - int sugar = Parser.mealNutrientSugar; - Meal.nutrientDetails.put(description, new int[]{calories, carbs, protein, fat, fiber, sugar}); - } - } - } catch (FileNotFoundException e) { - mealNutrientStorage.createFile(); - } - } - - /** - * Loads the file where pre-defined drinks and their nutrient counts are stored. - * - * @param drinkNutrientStorage contains filePath and folderPath of where the pre-defined drinks are stored. - */ - public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValueException{ - try { - ArrayList drinkNutrientList = drinkNutrientStorage.readFile(); - if (!drinkNutrientList.isEmpty()) { - for (String s : drinkNutrientList) { - Parser.parseDrinkNutrient(s); - String description = Parser.drinkNutrientDescription; - int calories = Parser.drinkNutrientCalories; - int carbs = Parser.drinkNutrientCarbs; - int sugar = Parser.drinkNutrientSugar; - int protein = Parser.drinkNutrientProtein; - int fat = Parser.drinkNutrientFat; - Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); - } - } - } catch (FileNotFoundException e) { - drinkNutrientStorage.createFile(); - } - } - - /** - * Loads the file where pre-defined exercises and the number of calories burnt per minute for - * respective intensities (HIGH, MEDIUM, LOW) are stored. - * - * @param exerciseCaloriesStorage contains filePath and folderPath of where the pre-defined exercises are stored. - */ - public void loadExerciseCalories(Storage exerciseCaloriesStorage) throws NegativeValueException { - try { - ArrayList exerciseCaloriesList = exerciseCaloriesStorage.readFile(); - if (!exerciseCaloriesList.isEmpty()) { - for (String s : exerciseCaloriesList) { - Parser.parseExerciseCalories(s); - String description = Parser.exerciseCaloriesDescription; - int caloriesHigh = Parser.exerciseCaloriesHigh; - int caloriesMedium = Parser.exerciseCaloriesMedium; - int caloriesLow = Parser.exerciseCaloriesLow; - Exercise.exerciseDetails.put(description, new int[]{caloriesHigh, caloriesMedium, caloriesLow}); - } - } - } catch (FileNotFoundException e) { - exerciseCaloriesStorage.createFile(); - } - } - - /** - * Saves the user's meals when the user exits the program. - * Meals from the current day is saved with the date into the .txt file. - * - * @param mealStorage contains filePath and folderPath of where the saved meals are stored. - */ - public void saveMeal(Storage mealStorage) { - for (Meal meal : mealListAll) { - String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); - mealStorage.appendTextContent(mealSavedData); - } - for (Meal meal : mealList) { - String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); - mealStorage.appendTextContent(mealSavedData); - } - try { - mealStorage.writeFile(mealStorage.textContent); - } catch (IOException e) { - System.out.println("Failed saving meal: " + e.getMessage()); - } - } - - /** - * Saves the user's drinks when the user exits the program. - * MealDrinkss from the current day is saved with the date into the .txt file. - * - * @param drinkStorage contains filePath and folderPath of where the saved drinksList are stored. - */ - public void saveDrink(Storage drinkStorage) { - for (Water water : waterListAll) { - String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); - drinkStorage.appendTextContent(waterSavedData); - } - for (Water water : waterList) { - String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); - drinkStorage.appendTextContent(waterSavedData); - } - for (Drink drink : drinkListAll) { - String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); - drinkStorage.appendTextContent(drinkSavedData); - } - for (Drink drink : drinkList) { - String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); - drinkStorage.appendTextContent(drinkSavedData); - } - try { - drinkStorage.writeFile(drinkStorage.textContent); - } catch (IOException e) { - System.out.println("Failed saving drink: " + e.getMessage()); - } - } - - /** - * Saves the user's exercises when the user exits the program. - * Exercises from the current day is saved with the date into the .txt file. - * - * @param exerciseStorage contains filePath and folderPath of where the saved exerciseList are stored. - */ - public void saveExercise(Storage exerciseStorage) { - for (Exercise exercise : exerciseListAll) { - String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," - + exercise.getIntensity() + "," + exercise.getDate(); - exerciseStorage.appendTextContent(exerciseSavedData); - } - for (Exercise exercise : exerciseList) { - String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," - + exercise.getIntensity() + "," + exercise.getDate(); - exerciseStorage.appendTextContent(exerciseSavedData); - } - try { - exerciseStorage.writeFile(exerciseStorage.textContent); - } catch (IOException e) { - System.out.println("Failed saving drink: " + e.getMessage()); - } - } - - public void saveMealNutrients(Storage mealNutrientStorage) { - StringBuilder result = new StringBuilder(); - for (Map.Entry entry : Meal.nutrientDetails.entrySet()) { - result.append(entry.getKey()).append(","); - int[] values = entry.getValue(); - for (int value : values) { - result.append(value).append(","); - } - result = new StringBuilder(result.substring(0, result.length() - 1)); - result.append("\n"); - } - mealNutrientStorage.appendTextContent(result.toString()); - try { - mealNutrientStorage.writeFile(mealNutrientStorage.textContent); - } catch (IOException e) { - System.out.println("Failed adding meal nutrients: " + e.getMessage()); - } - } - - public void saveDrinkNutrients(Storage drinkNutrientStorage) { - StringBuilder result = new StringBuilder(); - for (Map.Entry entry : Drink.nutrientDetails.entrySet()) { - result.append(entry.getKey()).append(","); - int[] values = entry.getValue(); - for (int value : values) { - result.append(value).append(","); - } - result = new StringBuilder(result.substring(0, result.length() - 1)); - result.append("\n"); - } - drinkNutrientStorage.appendTextContent(result.toString()); - try { - drinkNutrientStorage.writeFile(drinkNutrientStorage.textContent); - } catch (IOException e) { - System.out.println("Failed adding drink nutrients: " + e.getMessage()); - } + public static ArrayList mealListAll; + public static ArrayList drinkListAll; + public static ArrayList waterListAll; + public static ArrayList exerciseListAll; + + public User() { + mealList = new ArrayList<>(); + drinkList = new ArrayList<>(); + exerciseList = new ArrayList<>(); + waterList = new ArrayList<>(); + mealListAll = new ArrayList<>(); + drinkListAll = new ArrayList<>(); + exerciseListAll = new ArrayList<>(); + waterListAll = new ArrayList<>(); } public void handleAddNewMealNutrient(String command) throws NegativeValueException{ @@ -389,25 +81,6 @@ public void handleAddNewDrinkNutrient(String command) throws NegativeValueExcept System.out.println("Added " + description + " to available drinks"); } - public void saveExerciseCalories(Storage exerciseCaloriesStorage) { - StringBuilder result = new StringBuilder(); - for (Map.Entry entry : Exercise.exerciseDetails.entrySet()) { - result.append(entry.getKey()).append(","); - int[] values = entry.getValue(); - for (int value : values) { - result.append(value).append(","); - } - result = new StringBuilder(result.substring(0, result.length() - 1)); - result.append("\n"); - } - exerciseCaloriesStorage.appendTextContent(result.toString()); - try { - exerciseCaloriesStorage.writeFile(exerciseCaloriesStorage.textContent); - } catch (IOException e) { - System.out.println("Failed adding exercise calories: " + e.getMessage()); - } - } - public void handleAddNewExerciseCalories(String command) throws NegativeValueException{ Parser.parseNewExercise(command); String description = Parser.exerciseCaloriesDescription; diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index a0863849fc..d744566398 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import seedu.fitnus.storage.StorageManager; //import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -44,6 +45,7 @@ public class UserTest { private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); + StorageManager testStorageManager; private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -53,7 +55,8 @@ public void setUp() throws UnregisteredExerciseException { testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); - testUser = new User(testMealStorage, testDrinkStorage, testExerciseStorage, mealNutrientStorage, + testUser = new User(); + testStorageManager = new StorageManager(testMealStorage, testDrinkStorage, testExerciseStorage, mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); testMealList = testUser.mealList; From 4c3c2dd45ecbb199b2ac2832e25cd412e9f3d768 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 10 Apr 2024 15:38:18 +0800 Subject: [PATCH 182/274] Fix checkstyle --- src/main/java/seedu/fitnus/storage/StorageManager.java | 7 ++++++- src/main/java/seedu/fitnus/user/User.java | 4 ---- src/test/java/seedu/fitnus/user/UserTest.java | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index 3c890ea54c..14302fbc14 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -1,6 +1,11 @@ package seedu.fitnus.storage; -import seedu.fitnus.*; +import seedu.fitnus.Date; +import seedu.fitnus.Meal; +import seedu.fitnus.Drink; +import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.Exercise; +import seedu.fitnus.Water; import seedu.fitnus.user.User; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredExerciseException; diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 4b7f1f7a3b..2a72b54d57 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -7,7 +7,6 @@ import seedu.fitnus.Meal; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; -import seedu.fitnus.storage.Storage; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; @@ -21,10 +20,7 @@ import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.InvalidDateException; -import java.io.FileNotFoundException; -import java.io.IOException; import java.util.ArrayList; -import java.util.Map; /** * Handles all methods related to the user's meals, drinks and exercise. diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index d744566398..46e9c84e98 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -35,6 +35,7 @@ public class UserTest { User testUser; String todayDate; + StorageManager testStorageManager; ArrayList testMealList; ArrayList testDrinkList; ArrayList testWaterList; @@ -45,7 +46,6 @@ public class UserTest { private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); - StorageManager testStorageManager; private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -56,8 +56,8 @@ public void setUp() throws UnregisteredExerciseException { testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); testUser = new User(); - testStorageManager = new StorageManager(testMealStorage, testDrinkStorage, testExerciseStorage, mealNutrientStorage, - drinkNutrientStorage, exerciseCaloriesStorage); + testStorageManager = new StorageManager(testMealStorage, testDrinkStorage, testExerciseStorage, + mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); testMealList = testUser.mealList; testDrinkList = testUser.drinkList; From ecade622e607149deb7bbf6c65060ee543966c1c Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Wed, 10 Apr 2024 16:02:56 +0800 Subject: [PATCH 183/274] Add Edward's PPP --- docs/team/edwardhumi.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs/team/edwardhumi.md diff --git a/docs/team/edwardhumi.md b/docs/team/edwardhumi.md new file mode 100644 index 0000000000..eace2dbe40 --- /dev/null +++ b/docs/team/edwardhumi.md @@ -0,0 +1,15 @@ +# Edward Humianto's Project Portfolio Page + +FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and +carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. + +Given below are my contributions to the project. +* Feature: Storage Class + * storage system to save user's meal, drinks, and exercises list in .txt format + * csv storage to keep track the nutrients and calories details of known meals, drinks, and exercises +* Feature: User Class + * added `listMealsAll`, `listDrinksAll`, `listExercisesAll`, `listEverythingAll` command which allows user to view the list for all dates + * added `listMeals d/dd-MM-yyyy`, `listDrinks d/dd-MM-yyyy`, `listExercises d/dd-MM-yyyy`, `listEverything d/dd-MM-yyyy` command which allows user to view the list for certain date +* Feature: Parser Class + * created parser for parsing commands and storage files +* Code contributed: https://nus-cs2113-ay2324s2.github.io/tp-dashboard/#/widget/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&chartGroupIndex=31&chartIndex=2 From 9f0c6025252c84cd0bb4b5ffe9acbe4627141923 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Wed, 10 Apr 2024 16:22:22 +0800 Subject: [PATCH 184/274] Refactor ExerciseList --- src/main/java/seedu/fitnus/Ui.java | 1 + .../seedu/fitnus/{ => exercise}/Exercise.java | 2 +- .../{ => exercise}/ExerciseIntensity.java | 2 +- .../seedu/fitnus/exercise/ExerciseList.java | 163 +++++++++++++++++ src/main/java/seedu/fitnus/parser/Parser.java | 22 +-- .../seedu/fitnus/storage/StorageManager.java | 17 +- src/main/java/seedu/fitnus/user/User.java | 167 ++---------------- .../java/seedu/fitnus/parser/ParserTest.java | 2 +- src/test/java/seedu/fitnus/user/UserTest.java | 16 +- 9 files changed, 207 insertions(+), 185 deletions(-) rename src/main/java/seedu/fitnus/{ => exercise}/Exercise.java (99%) rename src/main/java/seedu/fitnus/{ => exercise}/ExerciseIntensity.java (67%) create mode 100644 src/main/java/seedu/fitnus/exercise/ExerciseList.java diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index e49748d358..cc1294f785 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import seedu.fitnus.exercise.Exercise; import seedu.fitnus.parser.Parser; import seedu.fitnus.storage.Storage; import seedu.fitnus.storage.StorageManager; diff --git a/src/main/java/seedu/fitnus/Exercise.java b/src/main/java/seedu/fitnus/exercise/Exercise.java similarity index 99% rename from src/main/java/seedu/fitnus/Exercise.java rename to src/main/java/seedu/fitnus/exercise/Exercise.java index a4ddf37d49..522b1f2e2d 100644 --- a/src/main/java/seedu/fitnus/Exercise.java +++ b/src/main/java/seedu/fitnus/exercise/Exercise.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.exercise; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredExerciseException; diff --git a/src/main/java/seedu/fitnus/ExerciseIntensity.java b/src/main/java/seedu/fitnus/exercise/ExerciseIntensity.java similarity index 67% rename from src/main/java/seedu/fitnus/ExerciseIntensity.java rename to src/main/java/seedu/fitnus/exercise/ExerciseIntensity.java index f274be48e1..35832072ea 100644 --- a/src/main/java/seedu/fitnus/ExerciseIntensity.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseIntensity.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.exercise; public enum ExerciseIntensity { HIGH, MEDIUM, diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java new file mode 100644 index 0000000000..cdf332b13d --- /dev/null +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -0,0 +1,163 @@ +package seedu.fitnus.exercise; + +import seedu.fitnus.Date; +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.parser.Parser; + +import java.util.ArrayList; + +public class ExerciseList { + public ArrayList exerciseList; + public ArrayList exerciseListAll; + + public ExerciseList() { + exerciseList = new ArrayList<>(); + exerciseListAll = new ArrayList<>(); + } + + public void handleAddNewExerciseCalories(String command) throws NegativeValueException { + Parser.parseNewExercise(command); + String description = Parser.exerciseCaloriesDescription; + int high = Parser.exerciseCaloriesHigh; + int medium = Parser.exerciseCaloriesMedium; + int low = Parser.exerciseCaloriesLow; + Exercise.exerciseDetails.put(description, new int[]{high, medium, low}); + + System.out.println("Added " + description + " to available exercises"); + } + + /** + * Prints all the exercises in the exerciseListToPrint, + * inclusive of the duration, intensity and date. + * + * @param exerciseListToPrint arraylist containing the exercises that should be printed + */ + public void printExerciseList(ArrayList exerciseListToPrint) { + for (int i = 0; i < exerciseListToPrint.size(); i++) { + Exercise currentExercise = exerciseListToPrint.get(i); + System.out.println((i+1) + ". " + currentExercise.getName() + " | duration: " + + currentExercise.getDuration() + " | intensity: " + currentExercise.getIntensity() + + " | date: " + currentExercise.getDate()); + } + } + + /** + * Handles when the user is listing the exercises they have done today. + * Method first checks if the list is empty. + */ + public void handleListExercises() { + System.out.println("here's the exercises you've done today"); + if (exerciseList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printExerciseList(exerciseList); + } + } + + /** + * Handles when the user is listing all exercises they have done, inclusive of previously saved exercises. + * Method first checks if the list is empty. + */ + + public void handleListExercisesAll() { + System.out.println("here's the exercises you've done so far"); + if (exerciseListAll.isEmpty() && exerciseList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + ArrayList appendedExerciseList = new ArrayList<>(); + appendedExerciseList.addAll(exerciseListAll); + appendedExerciseList.addAll(exerciseList); + printExerciseList(appendedExerciseList); + } + } + + /** + * Handles when the user is listing the exercises they have done on a certain date. + * Method will first extract all exercises that have this corresponding date, + * before printing. + * + * @param command string inputted by the user, containing the date of which they would like to list exercises of + * @throws InvalidDateException if the date inputted by user is invalid + */ + public void handleListExercisesDate(String command) throws InvalidDateException { + String date = Parser.parseListDate(command); + ArrayList exercisesListDate = new ArrayList<>(); + for (Exercise e : exerciseListAll) { + if (e.getDate().equals(date)) { + exercisesListDate.add(e); + } + } + for (Exercise e : exerciseList) { + if (e.getDate().equals(date)) { + exercisesListDate.add(e); + } + } + System.out.println("here's the exercises you've done on " + date); + if (exercisesListDate.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printExerciseList(exercisesListDate); + } + } + + /** + * Handles when the user would like to delete a previously inputted exercise. + * + * @param command string inputted by the user, containing the index of the exercise to delete + * @throws InvalidListIndexException if the provided index is not a valid index in exerciseList + * @throws IncompleteDeleteException if the user did not comply with the required command format + */ + public void handleDeleteExercise(String command) throws InvalidListIndexException, IncompleteDeleteException { + if (command.length() < 16) { + throw new IncompleteDeleteException(); + } + + int exerciseIndex = Integer.parseInt(command.substring(15).trim()) - 1; + if (exerciseIndex >= exerciseList.size() || exerciseIndex < 0) { + throw new InvalidListIndexException(); + } + + String exerciseName = exerciseList.get(exerciseIndex).getName(); + exerciseList.remove(exerciseIndex); + System.out.println("Removed " + exerciseName + " from exercises done"); + } + + /** + * Adds an exercise to the user's current exerciseList, based on what exercise the user has done, + * its duration and intensity. + * + * @param command string inputted by the user, containing the exercise they have done, its duration and + * intensity. + * @throws IncompleteExerciseException if the user did not comply with the required format + * @throws UnregisteredExerciseException if the user has inputted an exercise that was not pre-defined + * @throws NegativeValueException if the provided exercise duration is a negative value + */ + public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, + NegativeValueException { + Parser.parseExercise(command); + String exerciseType = Parser.exerciseDescription; + int duration = Parser.exerciseDuration; + ExerciseIntensity intensity = Parser.exerciseIntensity; + Date currentDate = new Date(); + exerciseList.add(new Exercise(exerciseType, duration, intensity, currentDate.getDate())); + assert !exerciseList.isEmpty(): "failed to track exercise"; + + System.out.println("Tracked " + duration + " minutes of " + exerciseType); + } + + /** + * Prints the number of calories the user has burnt today. + */ + public void handleCaloriesBurnt() { + int caloriesBurnt = 0; + for (Exercise exercise: exerciseList) { + caloriesBurnt += exercise.getCaloriesBurnt(); + } + System.out.println("Total calories burnt: " + caloriesBurnt); + } +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 1a2e58fc8e..ca06e3b47f 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,8 +1,8 @@ package seedu.fitnus.parser; import seedu.fitnus.Drink; -import seedu.fitnus.Exercise; -import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.exercise.Exercise; +import seedu.fitnus.exercise.ExerciseIntensity; import seedu.fitnus.Meal; import seedu.fitnus.Date; @@ -104,13 +104,13 @@ public void handleCommand(String command) { } else if (command.startsWith("drink")) { user.handleDrink(command); } else if (command.startsWith("exercise")) { - user.handleExercise(command); + user.myExerciseList.handleExercise(command); } else if (command.startsWith("newMeal")) { user.handleAddNewMealNutrient(command); } else if (command.startsWith("newDrink")) { user.handleAddNewDrinkNutrient(command); } else if (command.startsWith("newExercise")) { - user.handleAddNewExerciseCalories(command); + user.myExerciseList.handleAddNewExerciseCalories(command); }else if (command.equals("allMeals")) { Meal.listAvailableMeals(); } else if (command.equals("allDrinks")) { @@ -126,7 +126,7 @@ public void handleCommand(String command) { } else if (command.equals("calories")) { user.handleViewCalories(); } else if (command.equals("caloriesBurnt")) { - user.handleCaloriesBurnt(); + user.myExerciseList.handleCaloriesBurnt(); } else if (command.equals("carbs")) { user.handleViewCarbohydrates(); } else if (command.equals("protein")) { @@ -152,11 +152,11 @@ public void handleCommand(String command) { } else if (command.startsWith("listDrinks") && command.contains("d/")) { user.handleListDrinksDate(command); } else if (command.equals("listExercises")) { - user.handleListExercises(); + user.myExerciseList.handleListExercises(); } else if (command.equals("listExercisesAll")) { - user.handleListExercisesAll(); + user.myExerciseList.handleListExercisesAll(); } else if (command.startsWith("listExercises") && command.contains("d/")) { - user.handleListExercisesDate(command); + user.myExerciseList.handleListExercisesDate(command); } else if (command.equals("listEverything")) { user.handleListEverything(); } else if (command.equals("listEverythingAll")) { @@ -174,7 +174,7 @@ public void handleCommand(String command) { } else if (command.startsWith("deleteDrink")) { user.handleDeleteDrink(command); } else if (command.startsWith("deleteExercise")) { - user.handleDeleteExercise(command); + user.myExerciseList.handleDeleteExercise(command); } else if (command.equals("clear")) { user.handleClear(); } else if (command.equals("recommend")) { @@ -273,8 +273,8 @@ public static void handleHelp() { "CARBS,PROTEIN,FAT,FIBER,SUGAR"); System.out.println("- Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES," + "CARBS,SUGAR,PROTEIN,FAT"); - System.out.println("- Add a new exercise to available exercises: newExercise CALORIES_BURNT_HIGH," + - "CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW"); + System.out.println("- Add a new exercise to available exercises: newExercise EXERCISE_NAME," + + "CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW"); System.out.println("- Clear all entries: clear"); System.out.println("- Exit the app: exit "); } diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index 14302fbc14..bc0769a158 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -3,8 +3,8 @@ import seedu.fitnus.Date; import seedu.fitnus.Meal; import seedu.fitnus.Drink; -import seedu.fitnus.ExerciseIntensity; -import seedu.fitnus.Exercise; +import seedu.fitnus.exercise.ExerciseIntensity; +import seedu.fitnus.exercise.Exercise; import seedu.fitnus.Water; import seedu.fitnus.user.User; import seedu.fitnus.exception.NegativeValueException; @@ -119,18 +119,19 @@ public void loadExercise(Storage exerciseStorage) { int exerciseDuration = Parser.exerciseStorageDuration; ExerciseIntensity exerciseIntensity = Parser.exerciseStorageIntensity; String currentDate = Parser.exerciseStorageDate; - User.exerciseListAll.add(new Exercise(exerciseDescription, exerciseDuration, exerciseIntensity, + User.myExerciseList.exerciseListAll.add(new Exercise(exerciseDescription, + exerciseDuration, exerciseIntensity, currentDate)); } } Date currentDate = new Date(); String todayDate = currentDate.getDate(); - for (Exercise e : User.exerciseListAll) { + for (Exercise e : User.myExerciseList.exerciseListAll) { if (e.getDate().equals(todayDate)) { - User.exerciseList.add(e); + User.myExerciseList.exerciseList.add(e); } } - User.exerciseListAll.removeAll(User.exerciseList); + User.myExerciseList.exerciseListAll.removeAll(User.myExerciseList.exerciseList); } catch (FileNotFoundException e) { exerciseStorage.createFile(); } catch (UnregisteredExerciseException e) { @@ -273,12 +274,12 @@ public void saveDrink(Storage drinkStorage) { * @param exerciseStorage contains filePath and folderPath of where the saved exerciseList are stored. */ public void saveExercise(Storage exerciseStorage) { - for (Exercise exercise : User.exerciseListAll) { + for (Exercise exercise : User.myExerciseList.exerciseListAll) { String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," + exercise.getIntensity() + "," + exercise.getDate(); exerciseStorage.appendTextContent(exerciseSavedData); } - for (Exercise exercise : User.exerciseList) { + for (Exercise exercise : User.myExerciseList.exerciseList) { String exerciseSavedData = exercise.getName() + "," + exercise.getDuration() + "," + exercise.getIntensity() + "," + exercise.getDate(); exerciseStorage.appendTextContent(exerciseSavedData); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 2a72b54d57..0227cd8283 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -2,21 +2,19 @@ import seedu.fitnus.Date; import seedu.fitnus.Drink; -import seedu.fitnus.Exercise; -import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.exercise.Exercise; import seedu.fitnus.Meal; +import seedu.fitnus.exercise.ExerciseList; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredDrinkException; -import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.InvalidDateException; @@ -32,22 +30,21 @@ public class User { public static ArrayList mealList; public static ArrayList drinkList; public static ArrayList waterList; - public static ArrayList exerciseList; // list for all dates except today public static ArrayList mealListAll; public static ArrayList drinkListAll; public static ArrayList waterListAll; - public static ArrayList exerciseListAll; + public static ExerciseList myExerciseList; public User() { mealList = new ArrayList<>(); drinkList = new ArrayList<>(); - exerciseList = new ArrayList<>(); waterList = new ArrayList<>(); mealListAll = new ArrayList<>(); drinkListAll = new ArrayList<>(); - exerciseListAll = new ArrayList<>(); waterListAll = new ArrayList<>(); + + myExerciseList = new ExerciseList(); } public void handleAddNewMealNutrient(String command) throws NegativeValueException{ @@ -77,17 +74,6 @@ public void handleAddNewDrinkNutrient(String command) throws NegativeValueExcept System.out.println("Added " + description + " to available drinks"); } - public void handleAddNewExerciseCalories(String command) throws NegativeValueException{ - Parser.parseNewExercise(command); - String description = Parser.exerciseCaloriesDescription; - int high = Parser.exerciseCaloriesHigh; - int medium = Parser.exerciseCaloriesMedium; - int low = Parser.exerciseCaloriesLow; - Exercise.exerciseDetails.put(description, new int[]{high, medium, low}); - - System.out.println("Added " + description + " to available exercises"); - } - /** * Adds a meal to the user's current mealList, based on what the user has eaten and the serving size consumed. * @@ -155,7 +141,7 @@ public void handleViewCalories() { for (Drink drink: drinkList) { caloriesCount += drink.getCalories(); } - for (Exercise exercise: exerciseList) { + for (Exercise exercise: myExerciseList.exerciseList) { caloriesCount -= exercise.getCaloriesBurnt(); } System.out.println("Total Calories: " + caloriesCount); @@ -259,21 +245,6 @@ public void printMealList(int startIndex, ArrayList mealListToPrint) { } } - /** - * Prints all the exercises in the exerciseListToPrint, - * inclusive of the duration, intensity and date. - * - * @param exerciseListToPrint arraylist containing the exercises that should be printed - */ - public void printExerciseList(ArrayList exerciseListToPrint) { - for (int i = 0; i < exerciseListToPrint.size(); i++) { - Exercise currentExercise = exerciseListToPrint.get(i); - System.out.println((i+1) + ". " + currentExercise.getName() + " | duration: " + - currentExercise.getDuration() + " | intensity: " + currentExercise.getIntensity() - + " | date: " + currentExercise.getDate()); - } - } - /** * Handles when the user is listing the meals they have eaten today. * Method first checks if the list is empty. @@ -419,65 +390,6 @@ public void handleListDrinksDate(String command) throws InvalidDateException { } } - /** - * Handles when the user is listing the exercises they have done today. - * Method first checks if the list is empty. - */ - public void handleListExercises() { - System.out.println("here's the exercises you've done today"); - if (exerciseList.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - printExerciseList(exerciseList); - } - } - - /** - * Handles when the user is listing all exercises they have done, inclusive of previously saved exercises. - * Method first checks if the list is empty. - */ - - public void handleListExercisesAll() { - System.out.println("here's the exercises you've done so far"); - if (exerciseListAll.isEmpty() && exerciseList.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - ArrayList appendedExerciseList = new ArrayList<>(); - appendedExerciseList.addAll(exerciseListAll); - appendedExerciseList.addAll(exerciseList); - printExerciseList(appendedExerciseList); - } - } - - /** - * Handles when the user is listing the exercises they have done on a certain date. - * Method will first extract all exercises that have this corresponding date, - * before printing. - * - * @param command string inputted by the user, containing the date of which they would like to list exercises of - * @throws InvalidDateException if the date inputted by user is invalid - */ - public void handleListExercisesDate(String command) throws InvalidDateException { - String date = Parser.parseListDate(command); - ArrayList exercisesListDate = new ArrayList<>(); - for (Exercise e : exerciseListAll) { - if (e.getDate().equals(date)) { - exercisesListDate.add(e); - } - } - for (Exercise e : exerciseList) { - if (e.getDate().equals(date)) { - exercisesListDate.add(e); - } - } - System.out.println("here's the exercises you've done on " + date); - if (exercisesListDate.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - printExerciseList(exercisesListDate); - } - } - /** * Handles when the user is listing all meals and drinks they have inputted today. * Method first checks if the lists is empty. @@ -496,7 +408,7 @@ public void handleListEverything() { } System.out.println(" ~~~"); - handleListExercises(); + myExerciseList.handleListExercises(); } /** @@ -520,7 +432,7 @@ public void handleListEverythingAll() { } System.out.println(" ~~~"); - handleListExercisesAll(); + myExerciseList.handleListExercisesAll(); } /** @@ -568,7 +480,7 @@ public void handleListEverythingDate(String command) throws InvalidDateException } System.out.println(" ~~~"); - handleListExercisesDate(command); + myExerciseList.handleListExercisesDate(command); } /** @@ -679,50 +591,6 @@ public void handleDeleteDrink(String command) throws InvalidListIndexException, System.out.println("Removed " + drinkName + " from drinks"); } - /** - * Handles when the user would like to delete a previously inputted exercise. - * - * @param command string inputted by the user, containing the index of the exercise to delete - * @throws InvalidListIndexException if the provided index is not a valid index in exerciseList - * @throws IncompleteDeleteException if the user did not comply with the required command format - */ - public void handleDeleteExercise(String command) throws InvalidListIndexException, IncompleteDeleteException { - if (command.length() < 16) { - throw new IncompleteDeleteException(); - } - - int exerciseIndex = Integer.parseInt(command.substring(15).trim()) - 1; - if (exerciseIndex >= exerciseList.size() || exerciseIndex < 0) { - throw new InvalidListIndexException(); - } - - String exerciseName = exerciseList.get(exerciseIndex).getName(); - exerciseList.remove(exerciseIndex); - System.out.println("Removed " + exerciseName + " from exercises done"); - } - - /** - * Adds an exercise to the user's current exerciseList, based on what exercise the user has done, - * its duration and intensity. - * - * @param command string inputted by the user, containing the exercise they have done, its duration and - * intensity. - * @throws IncompleteExerciseException if the user did not comply with the required format - * @throws UnregisteredExerciseException if the user has inputted an exercise that was not pre-defined - * @throws NegativeValueException if the provided exercise duration is a negative value - */ - public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, - NegativeValueException { - Parser.parseExercise(command); - String exerciseType = Parser.exerciseDescription; - int duration = Parser.exerciseDuration; - ExerciseIntensity intensity = Parser.exerciseIntensity; - Date currentDate = new Date(); - exerciseList.add(new Exercise(exerciseType, duration, intensity, currentDate.getDate())); - assert !exerciseList.isEmpty(): "failed to track exercise"; - - System.out.println("Tracked " + duration + " minutes of " + exerciseType); - } /** * Handle when user would like to clear all entries from today. @@ -732,26 +600,15 @@ public void handleClear() { mealList.clear(); drinkList.clear(); waterList.clear(); - exerciseList.clear(); + myExerciseList.exerciseList.clear(); assert mealList.isEmpty(): "clearing of meal list failed"; assert drinkList.isEmpty(): "clearing of drink list failed"; - assert exerciseList.isEmpty(): "clearing of exercise list failed"; + assert myExerciseList.exerciseList.isEmpty(): "clearing of exercise list failed"; System.out.println("All entries have been deleted"); } - /** - * Prints the number of calories the user has burnt today. - */ - public void handleCaloriesBurnt() { - int caloriesBurnt = 0; - for (Exercise exercise: exerciseList) { - caloriesBurnt += exercise.getCaloriesBurnt(); - } - System.out.println("Total calories burnt: " + caloriesBurnt); - } - /** * Handles when user would like to see what is recommended to them, * only regarding the calorie and water intake. @@ -776,7 +633,7 @@ public void handleRecommendations() { for (Drink drink: drinkList) { caloriesCount += drink.getCalories(); } - for (Exercise exercise: exerciseList) { + for (Exercise exercise: myExerciseList.exerciseList) { caloriesCount -= exercise.getCaloriesBurnt(); } int caloriesDifference = RECOMMEND_CALORIE_INTAKE - caloriesCount; diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index b3672fdff5..55c7c96762 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -9,7 +9,7 @@ import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.InvalidDateException; -import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.exercise.ExerciseIntensity; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 46e9c84e98..1c93b34cd0 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -2,8 +2,8 @@ import seedu.fitnus.Date; import seedu.fitnus.Drink; -import seedu.fitnus.Exercise; -import seedu.fitnus.ExerciseIntensity; +import seedu.fitnus.exercise.Exercise; +import seedu.fitnus.exercise.ExerciseIntensity; import seedu.fitnus.Meal; import seedu.fitnus.Water; @@ -61,7 +61,7 @@ public void setUp() throws UnregisteredExerciseException { testMealList = testUser.mealList; testDrinkList = testUser.drinkList; - testExerciseList = testUser.exerciseList; + testExerciseList = testUser.myExerciseList.exerciseList; testWaterList = testUser.waterList; Date currentDate = new Date(); @@ -103,7 +103,7 @@ public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkEx public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, UnregisteredExerciseException, NegativeValueException { String command = "exercise e/running d/30 i/HIGH"; - testUser.handleExercise(command); + testUser.myExerciseList.handleExercise(command); assertEquals("running", testExerciseList.get(1).getName()); assertEquals(30, testExerciseList.get(1).getDuration()); @@ -183,7 +183,7 @@ public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { @Test public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { - testUser.handleCaloriesBurnt(); + testUser.myExerciseList.handleCaloriesBurnt(); String expectedOutput = "Total calories burnt: 240"; String actualOutput = outputStream.toString().trim(); @@ -243,7 +243,7 @@ public void handleListDrinks_validList_printListAccurate() { @Test public void handleListExercise_emptyList_printListAccurate() { testExerciseList.clear(); - testUser.handleListExercises(); + testUser.myExerciseList.handleListExercises(); String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + " >> nothing so far :o"; @@ -255,7 +255,7 @@ public void handleListExercise_emptyList_printListAccurate() { @Test public void handleListExercise_validList_printListAccurate() { - testUser.handleListExercises(); + testUser.myExerciseList.handleListExercises(); String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; @@ -373,7 +373,7 @@ public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws Invali public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, IncompleteDeleteException { String command = "deleteExercise 1"; - testUser.handleDeleteExercise(command); + testUser.myExerciseList.handleDeleteExercise(command); assertEquals(0, testExerciseList.size()); } From 5b4f83a6a95a6483ea0fc5dfdde590774f686d48 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 16:46:35 +0800 Subject: [PATCH 185/274] Refactor MealList --- src/main/java/seedu/fitnus/Ui.java | 1 + .../java/seedu/fitnus/{ => meal}/Meal.java | 2 +- src/main/java/seedu/fitnus/meal/MealList.java | 166 ++++ src/main/java/seedu/fitnus/parser/Parser.java | 15 +- .../java/seedu/fitnus/storage/Storage.java | 1 - .../seedu/fitnus/storage/StorageManager.java | 14 +- src/main/java/seedu/fitnus/user/User.java | 188 +---- src/test/java/seedu/fitnus/user/UserTest.java | 772 +++++++++--------- 8 files changed, 596 insertions(+), 563 deletions(-) rename src/main/java/seedu/fitnus/{ => meal}/Meal.java (99%) create mode 100644 src/main/java/seedu/fitnus/meal/MealList.java diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index e49748d358..c6f460edb3 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import seedu.fitnus.meal.Meal; import seedu.fitnus.parser.Parser; import seedu.fitnus.storage.Storage; import seedu.fitnus.storage.StorageManager; diff --git a/src/main/java/seedu/fitnus/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java similarity index 99% rename from src/main/java/seedu/fitnus/Meal.java rename to src/main/java/seedu/fitnus/meal/Meal.java index 2a490bbc12..8ba7f0eeba 100644 --- a/src/main/java/seedu/fitnus/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.meal; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredMealException; diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java new file mode 100644 index 0000000000..aeb666b553 --- /dev/null +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -0,0 +1,166 @@ +package seedu.fitnus.meal; + +import seedu.fitnus.Date; +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.parser.Parser; + +import java.util.ArrayList; + +public class MealList { + public static ArrayList mealList; + // list for all dates except today + public static ArrayList mealListAll; + + public MealList() { + mealList = new ArrayList<>(); + mealListAll = new ArrayList<>(); + } + + /** + * Adds a meal to the user's current mealList, based on what the user has eaten and the serving size consumed. + * + * @param command string inputted by the user, containing the meal they ate and its serving size + * @throws IncompleteMealException if the user did not comply with the required format + * @throws UnregisteredMealException if the user has inputted a meal that was not pre-defined + * @throws NegativeValueException if the provided serving size is a negative value + */ + public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, + NegativeValueException { + Parser.parseMeal(command); + String mealName = Parser.mealDescription; + int servingSize = Parser.mealSize; + + Date currentDate = new Date(); + + mealList.add(new Meal(mealName, servingSize, currentDate.getDate())); + assert !mealList.isEmpty(): "failed to add meal"; + + System.out.println("Added " + servingSize + " serving of " + mealName); + } + + + /** + * Prints all the meals in the mealListToPrint, + * inclusive of the serving size and date. + * + * @param startIndex starting integer value when printing the list, where startIndex >= 1 + * @param mealListToPrint arraylist containing the meals that should be printed + */ + public static void printMealList(int startIndex, ArrayList mealListToPrint) { + for (int i = 0; i < mealListToPrint.size(); i++) { + Meal currentMeal = mealListToPrint.get(i); + System.out.println((startIndex+i) + ". " + currentMeal.getName() + " (serving size: " + + currentMeal.getServingSize() + ")" + " | date: " + currentMeal.getDate()); + } + } + + /** + * Handles when the user is listing the meals they have eaten today. + * Method first checks if the list is empty. + */ + public static void handleListMeals() { + System.out.println("here's what you have eaten today"); + if (mealList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printMealList(1, mealList); + } + } + + /** + * Handles when the user is listing all meals they have eaten, inclusive of previously saved meals. + * Method first checks if the list is empty. + */ + //@@author edwardhumi + public static void handleListMealsAll() { + System.out.println("here's what you have eaten so far"); + if (mealListAll.isEmpty() && mealList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printMealList(1, mealListAll); + printMealList(1 + mealListAll.size(), mealList); + } + } + + /** + * Handles when the user is listing the meals they have eaten on a certain date. + * Method will first extract all meals that have this corresponding date, + * before printing. + * + * @param command string inputted by the user, containing the date of which they would like to list meals of + * @throws InvalidDateException if the date inputted by user is invalid + */ + //@@author edwardhumi + public static void handleListMealsDate(String command) throws InvalidDateException { + String date = Parser.parseListDate(command); + ArrayList mealListDate = new ArrayList<>(); + for (Meal m : mealListAll) { + if (m.getDate().equals(date)) { + mealListDate.add(m); + } + } + for (Meal m : mealList) { + if (m.getDate().equals(date)) { + mealListDate.add(m); + } + } + System.out.println("here's what you have eaten on " + date); + if (mealListDate.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printMealList(1, mealListDate); + } + } + + /** + * Handles when the user would like to edit the serving size of a previously inputted meal. + * + * @param command string inputted by the user, containing the index of the meal to edit and the new serving size + * @throws InvalidListIndexException if the provided index is not a valid index in mealList + * @throws NegativeValueException if the provided serving size is a negative value + * @throws IncompleteEditException if the user did not comply with the required command format + */ + public static void handleEditMealServingSize(String command) throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 + if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { + throw new InvalidListIndexException(); + } + + String mealName = mealList.get(Parser.editMealIndex).getName(); + String mealDate = mealList.get(Parser.editMealIndex).getDate(); + + Meal updatedMeal = new Meal(mealName, Parser.editMealSize, mealDate); + mealList.set(Parser.editMealIndex, updatedMeal); + System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); + } + + /** + * Handles when the user would like to delete a previously inputted meal. + * + * @param command string inputted by the user, containing the index of the meal to delete + * @throws InvalidListIndexException if the provided index is not a valid index in mealList + * @throws IncompleteDeleteException if the user did not comply with the required command format + */ + public static void handleDeleteMeal(String command) throws InvalidListIndexException, IncompleteDeleteException { + if (command.length() < 12) { + throw new IncompleteDeleteException(); + } + int mealIndex = Integer.parseInt(command.substring(11).trim()) - 1; + + if (mealIndex >= mealList.size() || mealIndex < 0) { + throw new InvalidListIndexException(); + } + + String mealName = mealList.get(mealIndex).getName(); + mealList.remove(mealIndex); + System.out.println("Removed " + mealName + " from meals"); + } + +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 1a2e58fc8e..12b0ecbe6d 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -3,7 +3,7 @@ import seedu.fitnus.Drink; import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; -import seedu.fitnus.Meal; +import seedu.fitnus.meal.Meal; import seedu.fitnus.Date; import seedu.fitnus.exception.IncompleteDeleteException; @@ -20,6 +20,7 @@ import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.meal.MealList; import seedu.fitnus.user.User; import seedu.fitnus.validator.IntegerValidation; @@ -100,7 +101,7 @@ public void handleCommand(String command) { if (command.equals("help")) { handleHelp(); } else if (command.startsWith("eat")) { - user.handleMeal(command); + user.myMealList.handleMeal(command); } else if (command.startsWith("drink")) { user.handleDrink(command); } else if (command.startsWith("exercise")) { @@ -140,11 +141,11 @@ public void handleCommand(String command) { } else if (command.equals("fiber")) { user.handleViewFiber(); } else if (command.equals("listMeals")) { - user.handleListMeals(); + user.myMealList.handleListMeals(); } else if (command.equals("listMealsAll")) { - user.handleListMealsAll(); + user.myMealList.handleListMealsAll(); } else if (command.startsWith("listMeals") && command.contains("d/")) { - user.handleListMealsDate(command); + user.myMealList.handleListMealsDate(command); } else if (command.equals("listDrinks")) { user.handleListDrinks(); } else if (command.equals("listDrinksAll")) { @@ -164,13 +165,13 @@ public void handleCommand(String command) { } else if (command.startsWith("listEverything") && command.contains("d/")) { user.handleListEverythingDate(command); } else if (command.startsWith("editMeal")) { - user.handleEditMealServingSize(command); + user.myMealList.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { user.handleEditDrinkServingSize(command); } else if (command.startsWith("editWater")) { user.handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { - user.handleDeleteMeal(command); + user.myMealList.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { user.handleDeleteDrink(command); } else if (command.startsWith("deleteExercise")) { diff --git a/src/main/java/seedu/fitnus/storage/Storage.java b/src/main/java/seedu/fitnus/storage/Storage.java index 0dfd52563d..21a8ddaaf5 100644 --- a/src/main/java/seedu/fitnus/storage/Storage.java +++ b/src/main/java/seedu/fitnus/storage/Storage.java @@ -13,7 +13,6 @@ public class Storage { public String textContent; public String folderPath; public String filePath; - private User user; public Storage(String folderPath, String filePath) { this.textContent = ""; diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index 14302fbc14..d4e32e2676 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -1,7 +1,7 @@ package seedu.fitnus.storage; import seedu.fitnus.Date; -import seedu.fitnus.Meal; +import seedu.fitnus.meal.Meal; import seedu.fitnus.Drink; import seedu.fitnus.ExerciseIntensity; import seedu.fitnus.Exercise; @@ -46,17 +46,17 @@ public void loadMeal(Storage mealStorage) { String mealDescription = Parser.mealStorageDescription; int mealSize = Parser.mealStorageSize; String currentDate = Parser.mealStorageDate; - User.mealListAll.add(new Meal(mealDescription, mealSize, currentDate)); + User.myMealList.mealListAll.add(new Meal(mealDescription, mealSize, currentDate)); } } Date currentDate = new Date(); String todayDate = currentDate.getDate(); - for (Meal m : User.mealListAll) { + for (Meal m : User.myMealList.mealListAll) { if (m.getDate().equals(todayDate)) { - User.mealList.add(m); + User.myMealList.mealList.add(m); } } - User.mealListAll.removeAll(User.mealList); + User.myMealList.mealListAll.removeAll(User.myMealList.mealList); } catch (FileNotFoundException e) { mealStorage.createFile(); } @@ -221,11 +221,11 @@ public void loadExerciseCalories(Storage exerciseCaloriesStorage) throws Negativ * @param mealStorage contains filePath and folderPath of where the saved meals are stored. */ public void saveMeal(Storage mealStorage) { - for (Meal meal : User.mealListAll) { + for (Meal meal : User.myMealList.mealListAll) { String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); mealStorage.appendTextContent(mealSavedData); } - for (Meal meal : User.mealList) { + for (Meal meal : User.myMealList.mealList) { String mealSavedData = meal.getName() + "," + meal.getServingSize() + "," + meal.getDate(); mealStorage.appendTextContent(mealSavedData); } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 2a72b54d57..7fe9c1175e 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -4,7 +4,8 @@ import seedu.fitnus.Drink; import seedu.fitnus.Exercise; import seedu.fitnus.ExerciseIntensity; -import seedu.fitnus.Meal; +import seedu.fitnus.meal.Meal; +import seedu.fitnus.meal.MealList; import seedu.fitnus.parser.Parser; import seedu.fitnus.Water; @@ -12,12 +13,10 @@ import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.IncompleteExerciseException; -import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exception.InvalidDateException; import java.util.ArrayList; @@ -28,23 +27,21 @@ public class User { public static final int RECOMMEND_WATER_INTAKE = 2600; public static final int RECOMMEND_CALORIE_INTAKE = 2200; - // list for today - public static ArrayList mealList; public static ArrayList drinkList; public static ArrayList waterList; public static ArrayList exerciseList; - // list for all dates except today - public static ArrayList mealListAll; public static ArrayList drinkListAll; public static ArrayList waterListAll; public static ArrayList exerciseListAll; + public static MealList myMealList; public User() { - mealList = new ArrayList<>(); + myMealList = new MealList(); + drinkList = new ArrayList<>(); exerciseList = new ArrayList<>(); waterList = new ArrayList<>(); - mealListAll = new ArrayList<>(); + drinkListAll = new ArrayList<>(); exerciseListAll = new ArrayList<>(); waterListAll = new ArrayList<>(); @@ -88,28 +85,6 @@ public void handleAddNewExerciseCalories(String command) throws NegativeValueExc System.out.println("Added " + description + " to available exercises"); } - /** - * Adds a meal to the user's current mealList, based on what the user has eaten and the serving size consumed. - * - * @param command string inputted by the user, containing the meal they ate and its serving size - * @throws IncompleteMealException if the user did not comply with the required format - * @throws UnregisteredMealException if the user has inputted a meal that was not pre-defined - * @throws NegativeValueException if the provided serving size is a negative value - */ - public void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, - NegativeValueException { - Parser.parseMeal(command); - String mealName = Parser.mealDescription; - int servingSize = Parser.mealSize; - - Date currentDate = new Date(); - - mealList.add(new Meal(mealName, servingSize, currentDate.getDate())); - assert !mealList.isEmpty(): "failed to add meal"; - - System.out.println("Added " + servingSize + " serving of " + mealName); - } - /** * Adds a drink to the user's current drinkList, based on what the user has drank and the serving size consumed. * @@ -149,7 +124,7 @@ public void handleDrink(String command) throws IncompleteDrinkException, Unregis */ public void handleViewCalories() { int caloriesCount = 0; - for (Meal meal: mealList) { + for (Meal meal: myMealList.mealList) { caloriesCount += meal.getCalories(); } for (Drink drink: drinkList) { @@ -167,7 +142,7 @@ public void handleViewCalories() { */ public void handleViewCarbohydrates() { int carbohydratesCount = 0; - for (Meal meal: mealList) { + for (Meal meal: myMealList.mealList) { carbohydratesCount += meal.getCarbs(); } for (Drink drink: drinkList) { @@ -182,7 +157,7 @@ public void handleViewCarbohydrates() { */ public void handleViewProteins() { int proteinCount = 0; - for (Meal meal: mealList) { + for (Meal meal: myMealList.mealList) { proteinCount += meal.getProtein(); } for (Drink drink: drinkList) { @@ -208,7 +183,7 @@ public void handleViewWaterIntake() { */ public void handleViewFiber() { int fibreCount = 0; - for (Meal meal: mealList) { + for (Meal meal: myMealList.mealList) { fibreCount += meal.getFiber(); } System.out.println("Total Fiber: " + fibreCount + " grams"); @@ -220,7 +195,7 @@ public void handleViewFiber() { */ public void handleViewFat() { int fatCount = 0; - for (Meal meal: mealList) { + for (Meal meal: myMealList.mealList) { fatCount += meal.getFat(); } for (Drink drink: drinkList) { @@ -235,7 +210,7 @@ public void handleViewFat() { */ public void handleViewSugar() { int sugarCount = 0; - for (Meal meal: mealList) { + for (Meal meal: myMealList.mealList) { sugarCount += meal.getSugar(); } for (Drink drink: drinkList) { @@ -244,20 +219,6 @@ public void handleViewSugar() { System.out.println("Total Sugar: " + sugarCount + " grams"); } - /** - * Prints all the meals in the mealListToPrint, - * inclusive of the serving size and date. - * - * @param startIndex starting integer value when printing the list, where startIndex >= 1 - * @param mealListToPrint arraylist containing the meals that should be printed - */ - public void printMealList(int startIndex, ArrayList mealListToPrint) { - for (int i = 0; i < mealListToPrint.size(); i++) { - Meal currentMeal = mealListToPrint.get(i); - System.out.println((startIndex+i) + ". " + currentMeal.getName() + " (serving size: " - + currentMeal.getServingSize() + ")" + " | date: " + currentMeal.getDate()); - } - } /** * Prints all the exercises in the exerciseListToPrint, @@ -274,61 +235,8 @@ public void printExerciseList(ArrayList exerciseListToPrint) { } } - /** - * Handles when the user is listing the meals they have eaten today. - * Method first checks if the list is empty. - */ - public void handleListMeals() { - System.out.println("here's what you have eaten today"); - if (mealList.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - printMealList(1, mealList); - } - } - /** - * Handles when the user is listing all meals they have eaten, inclusive of previously saved meals. - * Method first checks if the list is empty. - */ - public void handleListMealsAll() { - System.out.println("here's what you have eaten so far"); - if (mealListAll.isEmpty() && mealList.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - printMealList(1, mealListAll); - printMealList(1 + mealListAll.size(), mealList); - } - } - /** - * Handles when the user is listing the meals they have eaten on a certain date. - * Method will first extract all meals that have this corresponding date, - * before printing. - * - * @param command string inputted by the user, containing the date of which they would like to list meals of - * @throws InvalidDateException if the date inputted by user is invalid - */ - public void handleListMealsDate(String command) throws InvalidDateException { - String date = Parser.parseListDate(command); - ArrayList mealListDate = new ArrayList<>(); - for (Meal m : mealListAll) { - if (m.getDate().equals(date)) { - mealListDate.add(m); - } - } - for (Meal m : mealList) { - if (m.getDate().equals(date)) { - mealListDate.add(m); - } - } - System.out.println("here's what you have eaten on " + date); - if (mealListDate.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - printMealList(1, mealListDate); - } - } /** * Prints all the drinks in the drinkListToPrint, @@ -484,13 +392,13 @@ public void handleListExercisesDate(String command) throws InvalidDateException */ public void handleListEverything() { System.out.println("here's what you have consumed today"); - if (drinkList.isEmpty() && mealList.isEmpty()) { + if (drinkList.isEmpty() && myMealList.mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); System.out.println(); handleViewWaterIntake(); } else { - printMealList(1, mealList); - printDrinkList(mealList.size()+1, drinkList); + MealList.printMealList(1, myMealList.mealList); + printDrinkList(myMealList.mealList.size()+1, drinkList); System.out.println(); handleViewWaterIntake(); } @@ -506,15 +414,16 @@ public void handleListEverything() { */ public void handleListEverythingAll() { System.out.println("here's what you have consumed so far"); - if (drinkListAll.isEmpty() && mealListAll.isEmpty() && drinkList.isEmpty() && mealList.isEmpty()) { + if (drinkListAll.isEmpty() && myMealList.mealListAll.isEmpty() && drinkList.isEmpty() + && myMealList.mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); System.out.println(); handleViewWaterIntake(); } else { - printMealList(1, mealListAll); - printMealList(mealListAll.size() + 1, mealList); - printDrinkList(mealListAll.size() + mealList.size() + 1, drinkListAll); - printDrinkList(mealListAll.size() + mealList.size() + drinkListAll.size() + 1, drinkList); + MealList.printMealList(1, myMealList.mealListAll); + MealList.printMealList(myMealList.mealListAll.size() + 1, myMealList.mealList); + printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() + 1, drinkListAll); + printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() + drinkListAll.size() + 1, drinkList); System.out.println(); handleViewWaterIntake(); } @@ -534,12 +443,12 @@ public void handleListEverythingAll() { public void handleListEverythingDate(String command) throws InvalidDateException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); - for (Meal m : mealListAll) { + for (Meal m : myMealList.mealListAll) { if (m.getDate().equals(date)) { mealListDate.add(m); } } - for (Meal m : mealList) { + for (Meal m : myMealList.mealList) { if (m.getDate().equals(date)) { mealListDate.add(m); } @@ -562,7 +471,7 @@ public void handleListEverythingDate(String command) throws InvalidDateException System.out.println(" >> nothing so far :o"); System.out.println(); } else { - printMealList(1, mealListDate); + MealList.printMealList(1, mealListDate); printDrinkList(1 + mealListDate.size(), drinkListDate); System.out.println(); } @@ -571,28 +480,6 @@ public void handleListEverythingDate(String command) throws InvalidDateException handleListExercisesDate(command); } - /** - * Handles when the user would like to edit the serving size of a previously inputted meal. - * - * @param command string inputted by the user, containing the index of the meal to edit and the new serving size - * @throws InvalidListIndexException if the provided index is not a valid index in mealList - * @throws NegativeValueException if the provided serving size is a negative value - * @throws IncompleteEditException if the user did not comply with the required command format - */ - public void handleEditMealServingSize(String command) throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 - if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { - throw new InvalidListIndexException(); - } - - String mealName = mealList.get(Parser.editMealIndex).getName(); - String mealDate = mealList.get(Parser.editMealIndex).getDate(); - - Meal updatedMeal = new Meal(mealName, Parser.editMealSize, mealDate); - mealList.set(Parser.editMealIndex, updatedMeal); - System.out.println(mealName + " has been edited to " + Parser.editMealSize + " serving(s)"); - } /** * Handles when the user would like to edit the serving size of a previously inputted drink. @@ -635,27 +522,6 @@ public void handleEditWaterIntake(String command) throws NegativeValueException, System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } - /** - * Handles when the user would like to delete a previously inputted meal. - * - * @param command string inputted by the user, containing the index of the meal to delete - * @throws InvalidListIndexException if the provided index is not a valid index in mealList - * @throws IncompleteDeleteException if the user did not comply with the required command format - */ - public void handleDeleteMeal(String command) throws InvalidListIndexException, IncompleteDeleteException { - if (command.length() < 12) { - throw new IncompleteDeleteException(); - } - int mealIndex = Integer.parseInt(command.substring(11).trim()) - 1; - - if (mealIndex >= mealList.size() || mealIndex < 0) { - throw new InvalidListIndexException(); - } - - String mealName = mealList.get(mealIndex).getName(); - mealList.remove(mealIndex); - System.out.println("Removed " + mealName + " from meals"); - } /** * Handles when the user would like to delete a previously inputted drink. @@ -729,12 +595,12 @@ public void handleExercise(String command) throws IncompleteExerciseException, U * This includes all meals, drinks and exercise. */ public void handleClear() { - mealList.clear(); + myMealList.mealList.clear(); drinkList.clear(); waterList.clear(); exerciseList.clear(); - assert mealList.isEmpty(): "clearing of meal list failed"; + assert myMealList.mealList.isEmpty(): "clearing of meal list failed"; assert drinkList.isEmpty(): "clearing of drink list failed"; assert exerciseList.isEmpty(): "clearing of exercise list failed"; @@ -770,7 +636,7 @@ public void handleRecommendations() { } System.out.println(" ~~"); int caloriesCount = 0; - for (Meal meal: mealList) { + for (Meal meal: myMealList.mealList) { caloriesCount += meal.getCalories(); } for (Drink drink: drinkList) { diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 46e9c84e98..8afde5eb32 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -1,386 +1,386 @@ -package seedu.fitnus.user; - -import seedu.fitnus.Date; -import seedu.fitnus.Drink; -import seedu.fitnus.Exercise; -import seedu.fitnus.ExerciseIntensity; -import seedu.fitnus.Meal; - -import seedu.fitnus.Water; - -import seedu.fitnus.exception.IncompleteDeleteException; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.IncompleteExerciseException; -import seedu.fitnus.exception.IncompleteMealException; -import seedu.fitnus.exception.InvalidListIndexException; -import seedu.fitnus.exception.NegativeValueException; -import seedu.fitnus.exception.UnregisteredDrinkException; -import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.storage.Storage; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.util.ArrayList; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import seedu.fitnus.storage.StorageManager; -//import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class UserTest { - User testUser; - String todayDate; - StorageManager testStorageManager; - ArrayList testMealList; - ArrayList testDrinkList; - ArrayList testWaterList; - ArrayList testExerciseList; - private Storage testMealStorage; - private Storage testDrinkStorage; - private Storage testExerciseStorage; - private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); - private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); - private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); - - private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - @BeforeEach - public void setUp() throws UnregisteredExerciseException { - testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); - testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); - testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); - - testUser = new User(); - testStorageManager = new StorageManager(testMealStorage, testDrinkStorage, testExerciseStorage, - mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); - - testMealList = testUser.mealList; - testDrinkList = testUser.drinkList; - testExerciseList = testUser.exerciseList; - testWaterList = testUser.waterList; - - Date currentDate = new Date(); - todayDate = currentDate.getDate(); - - testMealList.add(new Meal("kaya toast", 4, todayDate)); - testMealList.add(new Meal("laksa", 10, todayDate)); - testDrinkList.add(new Drink("kopi", 100, todayDate)); - testWaterList.add(new Water( 100, todayDate)); - testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH, "30-01-2024")); - - System.setOut(new PrintStream(outputStream)); - } - - @Test - public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, - NegativeValueException { - String command = "eat m/kaya toast s/3"; - testUser.handleMeal(command); - - assertFalse(testMealList.isEmpty()); - - assertEquals("kaya toast", testMealList.get(2).getName()); - assertEquals(3, testMealList.get(2).getServingSize()); - } - - @Test - public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, - UnregisteredDrinkException, NegativeValueException { - String command = "drink d/kopi s/500"; - testUser.handleDrink(command); - - assertEquals("kopi", testDrinkList.get(1).getName()); - assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); - } - - - @Test - public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, - UnregisteredExerciseException, NegativeValueException { - String command = "exercise e/running d/30 i/HIGH"; - testUser.handleExercise(command); - - assertEquals("running", testExerciseList.get(1).getName()); - assertEquals(30, testExerciseList.get(1).getDuration()); - assertEquals(ExerciseIntensity.HIGH, testExerciseList.get(1).getIntensity()); - } - - @Test - public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { - testUser.handleViewCalories(); - String expectedOutput = "Total Calories: 5507"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { - testUser.handleViewCarbohydrates(); - String expectedOutput = "Total Carbohydrates: 912 grams"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewProteins(); - String expectedOutput = "Total Proteins: 215 grams"; - String actualOutput = outputStream.toString().trim(); - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { - testWaterList.add(new Water (500, todayDate)); - - testUser.handleViewWaterIntake(); - String expectedOutput = "Total water intake today: 600 ml"; - String actualOutput = outputStream.toString().trim(); - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewFiber(); - String expectedOutput = "Total Fiber: 80 grams"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewFat_correctFatCalculation_viewFatAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewFat(); - String expectedOutput = "Total Fat: 129 grams"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { - System.setOut(new PrintStream(outputStream)); - - testUser.handleViewSugar(); - String expectedOutput = "Total Sugar: 106 grams"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { - testUser.handleCaloriesBurnt(); - String expectedOutput = "Total calories burnt: 240"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(actualOutput, expectedOutput); - } - - @Test - public void handleListMeals_emptyList_printListAccurate() { - testMealList.clear(); - testUser.handleListMeals(); - - String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListMeals_validList_printListAccurate() { - testUser.handleListMeals(); - - String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + - "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + - "2. laksa (serving size: 10) | date: " + todayDate ; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListDrinks_emptyList_printListAccurate() { - testDrinkList.clear(); - testWaterList.clear(); - testUser.handleListDrinks(); - - String expectedOutput = "here's what you have drank today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - - @Test - public void handleListDrinks_validList_printListAccurate() { - testUser.handleListDrinks(); - - String expectedOutput = "here's what you have drank today" + System.lineSeparator() + - "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake today: 100 ml"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListExercise_emptyList_printListAccurate() { - testExerciseList.clear(); - testUser.handleListExercises(); - - String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - - @Test - public void handleListExercise_validList_printListAccurate() { - testUser.handleListExercises(); - - String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + - "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListEverything_allEmptyLists_printListAccurate() { - testMealList.clear(); - testDrinkList.clear(); - testExerciseList.clear(); - testUser.handleListEverything(); - - String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + - " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + - "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + - "here's the exercises you've done today" + System.lineSeparator() + - " >> nothing so far :o"; - String actualOutput = outputStream.toString().trim(); - - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleListEverything_validList_printListAccurate() { - testUser.handleListEverything(); - - String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + - "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + - "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + - "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + - "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + - "here's the exercises you've done today" + System.lineSeparator() + - "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; - String actualOutput = outputStream.toString().trim(); - assertEquals(expectedOutput, actualOutput); - } - - @Test - public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { - Exception exception = assertThrows(InvalidListIndexException.class, () -> { - String command = "editMeal 5 s/10"; - testUser.handleEditMealServingSize(command); - }); - } - - @Test - public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - String command = "editMeal 2 s/100000000"; - testUser.handleEditMealServingSize(command); - - int mealIndex = 2 - 1; - assertEquals("laksa", testMealList.get(mealIndex).getName()); - assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); - } - - @Test - public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - String command = "editDrink 1 s/100000000"; - testUser.handleEditDrinkServingSize(command); - - int drinkIndex = 0; - assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); - assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); - } - - @Test - public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, - IncompleteDeleteException { - Exception exception = assertThrows(IncompleteDeleteException.class, () -> { - String command = "deleteMeal "; - testUser.handleDeleteMeal(command); - }); - } - - @Test - public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, - IncompleteDeleteException { - Exception exception = assertThrows(NumberFormatException.class, () -> { - String command = "deleteMeal "; - testUser.handleDeleteMeal(command); - }); - } - - @Test - public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, - IncompleteDeleteException { - String command = "deleteMeal 1"; - testUser.handleDeleteMeal(command); - assertEquals(1, testMealList.size()); - assertEquals("laksa", testMealList.get(0).getName()); - } - - @Test - public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { - Exception exception = assertThrows(InvalidListIndexException.class, () -> { - String command = "deleteDrink 5"; - testUser.handleDeleteDrink(command); - }); - } - - @Test - public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, - IncompleteDeleteException { - String command = "deleteDrink 1"; - testUser.handleDeleteDrink(command); - assertEquals(0, testDrinkList.size()); - } - - @Test - public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, - IncompleteDeleteException { - String command = "deleteExercise 1"; - testUser.handleDeleteExercise(command); - assertEquals(0, testExerciseList.size()); - } - - @Test - public void handleClear_validCommand_clearListsSuccessful() { - testUser.handleClear(); - assertEquals(0, testMealList.size()); - assertEquals(0, testDrinkList.size()); - } -} +//package seedu.fitnus.user; +// +//import seedu.fitnus.Date; +//import seedu.fitnus.Drink; +//import seedu.fitnus.Exercise; +//import seedu.fitnus.ExerciseIntensity; +//import seedu.fitnus.meal.Meal; +// +//import seedu.fitnus.Water; +// +//import seedu.fitnus.exception.IncompleteDeleteException; +//import seedu.fitnus.exception.IncompleteDrinkException; +//import seedu.fitnus.exception.IncompleteEditException; +//import seedu.fitnus.exception.IncompleteExerciseException; +//import seedu.fitnus.exception.IncompleteMealException; +//import seedu.fitnus.exception.InvalidListIndexException; +//import seedu.fitnus.exception.NegativeValueException; +//import seedu.fitnus.exception.UnregisteredDrinkException; +//import seedu.fitnus.exception.UnregisteredExerciseException; +//import seedu.fitnus.exception.UnregisteredMealException; +//import seedu.fitnus.storage.Storage; +// +//import java.io.ByteArrayOutputStream; +//import java.io.PrintStream; +//import java.util.ArrayList; +// +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +//import seedu.fitnus.storage.StorageManager; +////import static org.junit.jupiter.api.Assertions.fail; +//import static org.junit.jupiter.api.Assertions.assertEquals; +//import static org.junit.jupiter.api.Assertions.assertFalse; +//import static org.junit.jupiter.api.Assertions.assertThrows; +// +//public class UserTest { +// User testUser; +// String todayDate; +// StorageManager testStorageManager; +// ArrayList testMealList; +// ArrayList testDrinkList; +// ArrayList testWaterList; +// ArrayList testExerciseList; +// private Storage testMealStorage; +// private Storage testDrinkStorage; +// private Storage testExerciseStorage; +// private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); +// private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); +// private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); +// +// private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); +// +// @BeforeEach +// public void setUp() throws UnregisteredExerciseException { +// testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); +// testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); +// testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); +// +// testUser = new User(); +// testStorageManager = new StorageManager(testMealStorage, testDrinkStorage, testExerciseStorage, +// mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); +// +// testMealList = testUser.mealList; +// testDrinkList = testUser.drinkList; +// testExerciseList = testUser.exerciseList; +// testWaterList = testUser.waterList; +// +// Date currentDate = new Date(); +// todayDate = currentDate.getDate(); +// +// testMealList.add(new Meal("kaya toast", 4, todayDate)); +// testMealList.add(new Meal("laksa", 10, todayDate)); +// testDrinkList.add(new Drink("kopi", 100, todayDate)); +// testWaterList.add(new Water( 100, todayDate)); +// testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH, "30-01-2024")); +// +// System.setOut(new PrintStream(outputStream)); +// } +// +// @Test +// public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, +// NegativeValueException { +// String command = "eat m/kaya toast s/3"; +// testUser.handleMeal(command); +// +// assertFalse(testMealList.isEmpty()); +// +// assertEquals("kaya toast", testMealList.get(2).getName()); +// assertEquals(3, testMealList.get(2).getServingSize()); +// } +// +// @Test +// public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, +// UnregisteredDrinkException, NegativeValueException { +// String command = "drink d/kopi s/500"; +// testUser.handleDrink(command); +// +// assertEquals("kopi", testDrinkList.get(1).getName()); +// assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); +// } +// +// +// @Test +// public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, +// UnregisteredExerciseException, NegativeValueException { +// String command = "exercise e/running d/30 i/HIGH"; +// testUser.handleExercise(command); +// +// assertEquals("running", testExerciseList.get(1).getName()); +// assertEquals(30, testExerciseList.get(1).getDuration()); +// assertEquals(ExerciseIntensity.HIGH, testExerciseList.get(1).getIntensity()); +// } +// +// @Test +// public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { +// testUser.handleViewCalories(); +// String expectedOutput = "Total Calories: 5507"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { +// testUser.handleViewCarbohydrates(); +// String expectedOutput = "Total Carbohydrates: 912 grams"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewProteins(); +// String expectedOutput = "Total Proteins: 215 grams"; +// String actualOutput = outputStream.toString().trim(); +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { +// testWaterList.add(new Water (500, todayDate)); +// +// testUser.handleViewWaterIntake(); +// String expectedOutput = "Total water intake today: 600 ml"; +// String actualOutput = outputStream.toString().trim(); +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewFiber(); +// String expectedOutput = "Total Fiber: 80 grams"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleViewFat_correctFatCalculation_viewFatAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewFat(); +// String expectedOutput = "Total Fat: 129 grams"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { +// System.setOut(new PrintStream(outputStream)); +// +// testUser.handleViewSugar(); +// String expectedOutput = "Total Sugar: 106 grams"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { +// testUser.handleCaloriesBurnt(); +// String expectedOutput = "Total calories burnt: 240"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(actualOutput, expectedOutput); +// } +// +// @Test +// public void handleListMeals_emptyList_printListAccurate() { +// testMealList.clear(); +// testUser.handleListMeals(); +// +// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + +// " >> nothing so far :o"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListMeals_validList_printListAccurate() { +// testUser.handleListMeals(); +// +// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + +// "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + +// "2. laksa (serving size: 10) | date: " + todayDate ; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListDrinks_emptyList_printListAccurate() { +// testDrinkList.clear(); +// testWaterList.clear(); +// testUser.handleListDrinks(); +// +// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + +// " >> nothing so far :o"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// +// @Test +// public void handleListDrinks_validList_printListAccurate() { +// testUser.handleListDrinks(); +// +// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + +// "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + +// "Total water intake today: 100 ml"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListExercise_emptyList_printListAccurate() { +// testExerciseList.clear(); +// testUser.handleListExercises(); +// +// String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + +// " >> nothing so far :o"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// +// @Test +// public void handleListExercise_validList_printListAccurate() { +// testUser.handleListExercises(); +// +// String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + +// "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListEverything_allEmptyLists_printListAccurate() { +// testMealList.clear(); +// testDrinkList.clear(); +// testExerciseList.clear(); +// testUser.handleListEverything(); +// +// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + +// " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + +// "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + +// "here's the exercises you've done today" + System.lineSeparator() + +// " >> nothing so far :o"; +// String actualOutput = outputStream.toString().trim(); +// +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleListEverything_validList_printListAccurate() { +// testUser.handleListEverything(); +// +// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + +// "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + +// "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + +// "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + +// "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + +// "here's the exercises you've done today" + System.lineSeparator() + +// "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; +// String actualOutput = outputStream.toString().trim(); +// assertEquals(expectedOutput, actualOutput); +// } +// +// @Test +// public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { +// Exception exception = assertThrows(InvalidListIndexException.class, () -> { +// String command = "editMeal 5 s/10"; +// testUser.handleEditMealServingSize(command); +// }); +// } +// +// @Test +// public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, +// NegativeValueException, IncompleteEditException { +// String command = "editMeal 2 s/100000000"; +// testUser.handleEditMealServingSize(command); +// +// int mealIndex = 2 - 1; +// assertEquals("laksa", testMealList.get(mealIndex).getName()); +// assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); +// } +// +// @Test +// public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, +// NegativeValueException, IncompleteEditException { +// String command = "editDrink 1 s/100000000"; +// testUser.handleEditDrinkServingSize(command); +// +// int drinkIndex = 0; +// assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); +// assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); +// } +// +// @Test +// public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, +// IncompleteDeleteException { +// Exception exception = assertThrows(IncompleteDeleteException.class, () -> { +// String command = "deleteMeal "; +// testUser.handleDeleteMeal(command); +// }); +// } +// +// @Test +// public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, +// IncompleteDeleteException { +// Exception exception = assertThrows(NumberFormatException.class, () -> { +// String command = "deleteMeal "; +// testUser.handleDeleteMeal(command); +// }); +// } +// +// @Test +// public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, +// IncompleteDeleteException { +// String command = "deleteMeal 1"; +// testUser.handleDeleteMeal(command); +// assertEquals(1, testMealList.size()); +// assertEquals("laksa", testMealList.get(0).getName()); +// } +// +// @Test +// public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { +// Exception exception = assertThrows(InvalidListIndexException.class, () -> { +// String command = "deleteDrink 5"; +// testUser.handleDeleteDrink(command); +// }); +// } +// +// @Test +// public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, +// IncompleteDeleteException { +// String command = "deleteDrink 1"; +// testUser.handleDeleteDrink(command); +// assertEquals(0, testDrinkList.size()); +// } +// +// @Test +// public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, +// IncompleteDeleteException { +// String command = "deleteExercise 1"; +// testUser.handleDeleteExercise(command); +// assertEquals(0, testExerciseList.size()); +// } +// +// @Test +// public void handleClear_validCommand_clearListsSuccessful() { +// testUser.handleClear(); +// assertEquals(0, testMealList.size()); +// assertEquals(0, testDrinkList.size()); +// } +//} From 29eb73f9af0059c4e29eb1206388df2d17eb13c9 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 16:50:48 +0800 Subject: [PATCH 186/274] Follow Reposense unused folder --- src/main/java/seedu/fitnus/{ => unused}/CSVReader.java | 3 ++- src/main/java/seedu/fitnus/{ => unused}/CSVWriter.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) rename src/main/java/seedu/fitnus/{ => unused}/CSVReader.java (97%) rename src/main/java/seedu/fitnus/{ => unused}/CSVWriter.java (95%) diff --git a/src/main/java/seedu/fitnus/CSVReader.java b/src/main/java/seedu/fitnus/unused/CSVReader.java similarity index 97% rename from src/main/java/seedu/fitnus/CSVReader.java rename to src/main/java/seedu/fitnus/unused/CSVReader.java index 30f424f6b7..dade70a4e4 100644 --- a/src/main/java/seedu/fitnus/CSVReader.java +++ b/src/main/java/seedu/fitnus/unused/CSVReader.java @@ -1,10 +1,11 @@ -package seedu.fitnus; +package seedu.fitnus.unused; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; +//@@author tinaliu27-unused public class CSVReader { public static final String DELIMITER = ","; private static HashMap foodItems = new HashMap<>(); diff --git a/src/main/java/seedu/fitnus/CSVWriter.java b/src/main/java/seedu/fitnus/unused/CSVWriter.java similarity index 95% rename from src/main/java/seedu/fitnus/CSVWriter.java rename to src/main/java/seedu/fitnus/unused/CSVWriter.java index 3cfbd260ab..bb606effb6 100644 --- a/src/main/java/seedu/fitnus/CSVWriter.java +++ b/src/main/java/seedu/fitnus/unused/CSVWriter.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.unused; import java.io.BufferedWriter; import java.io.File; @@ -8,6 +8,7 @@ import java.text.SimpleDateFormat; import java.util.Date; +//@@author tinaliu27-unused public class CSVWriter { public static void main(String[] args) { writeIntoFile("hi", "FOOD"); From 6a34012c6f216b2e67546ab9ddf8c17546b84050 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 17:00:09 +0800 Subject: [PATCH 187/274] Fix checkstyle error --- src/main/java/seedu/fitnus/storage/Storage.java | 2 -- src/main/java/seedu/fitnus/user/User.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/fitnus/storage/Storage.java b/src/main/java/seedu/fitnus/storage/Storage.java index 21a8ddaaf5..63e7af637b 100644 --- a/src/main/java/seedu/fitnus/storage/Storage.java +++ b/src/main/java/seedu/fitnus/storage/Storage.java @@ -1,7 +1,5 @@ package seedu.fitnus.storage; -import seedu.fitnus.user.User; - import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 8d250a1a8c..fc4623a8b5 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -331,7 +331,8 @@ public void handleListEverythingAll() { MealList.printMealList(1, myMealList.mealListAll); MealList.printMealList(myMealList.mealListAll.size() + 1, myMealList.mealList); printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() + 1, drinkListAll); - printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() + drinkListAll.size() + 1, drinkList); + printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() + + drinkListAll.size() + 1, drinkList); System.out.println(); handleViewWaterIntake(); } From c6b11d2a5c69f9b775641c9031fc42cfa3be56d5 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 17:06:03 +0800 Subject: [PATCH 188/274] Fix CheckStyleTest error --- src/test/java/seedu/fitnus/user/UserTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index e6fd5b03c1..8afde5eb32 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -383,4 +383,4 @@ // assertEquals(0, testMealList.size()); // assertEquals(0, testDrinkList.size()); // } -//} \ No newline at end of file +//} From 8289e4a65172dbb95b1548d8f3e4c3bdd3a285dd Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 17:21:30 +0800 Subject: [PATCH 189/274] Add pre-defined meal and drinks --- db/Drink_db.csv | 17 +++++++++++++++-- db/Meal_db.csv | 18 ++++++++++++++++++ src/main/java/seedu/fitnus/Drink.java | 13 +++++++++++++ src/main/java/seedu/fitnus/meal/Meal.java | 18 ++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/db/Drink_db.csv b/db/Drink_db.csv index 2dff4e01fa..9e4aff223f 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -1,5 +1,18 @@ -sprite,270,42,7,8,2 +soursop juice,117,25,3,1,1 +kopi c,117,20,1,4,0 +kalamansi juice,168,42,0,0,1 +coke,153,32,1,2,1 +kopi o,67,15,1,0,0 milo,124,20,3,3,1 -iced lemon tea,95,21,1,1,1 +plum juice,57,13,1,0,1 kopi,141,26,2,3,1 +teh c bing,231,24,15,1,1 +guava juice,143,38,0,0,1 +tiger beer,42,3,1,0,0 +teh tarik,124,21,3,3,0 +sugarcane juice,192,52,0,0,1 +teh,151,29,4,1,1 +sprite,270,42,7,8,2 +iced lemon tea,95,21,1,1,1 +bandung,153,32,1,2,1 diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 85a5213ee8..11617cca47 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,6 +1,24 @@ +ban mian,475,48,22,22,3,10 +tau huay,153,32,14,1,5,1 +nasi goreng,346,45,13,12,10,2 +babi kecap,607,75,25,23,2,10 +soup kambeng,203,6,28,7,2,5 +nasi lemak,494,80,13,14,6,5 +pepper lunch,500,50,40,11,4,5 +char siew rice,605,91,24,16,6,10 +pork satay with satay sauce,36,1,5,2,10,0 +roti prata,209,32,5,7,2,10 +mee goreng,500,61,18,20,4,5 +chendol,386,59,6,15,7,2 +wanton mee,555,97,15,14,13,10 +oyster omlette,467,40,19,24,10,1 pizza,600,80,50,40,30,20 +ice kachang,257,58,6,1,10,2 chicken rice,400,50,30,20,10,5 fried rice,500,60,25,15,15,5 kaya toast,459,44,8,27,10,1 +mala,583,72,12,30,10,7 laksa,377,71,18,2,4,10 +hokkien prawn mee,522,69,18,19,4,10 +durian,147,27,2,5,3,5 diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/Drink.java index 0644fec117..bc2eac6ad4 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/Drink.java @@ -39,6 +39,19 @@ public Drink(String name, int volume, String currentDate) { nutrientDetails.put("iced lemon tea", new int[]{95, 21, 1, 1, 1}); nutrientDetails.put("milo", new int[]{124, 20, 3, 3, 1}); nutrientDetails.put("kopi", new int[]{141, 26, 2, 3, 1}); + nutrientDetails.put("soursop juice", new int[]{117, 25, 3, 1, 1}); + nutrientDetails.put("kopi c", new int[]{117, 20, 1, 4, 0}); + nutrientDetails.put("kalamansi juice", new int[]{168, 42, 0, 0, 1}); + nutrientDetails.put("coke", new int[]{153, 32, 1, 2, 1}); + nutrientDetails.put("kopi o", new int[]{67, 15, 1, 0, 0}); + nutrientDetails.put("plum juice", new int[]{57, 13, 1, 0, 1}); + nutrientDetails.put("teh c bing", new int[]{231, 24, 15, 1, 1}); + nutrientDetails.put("guava juice", new int[]{143, 38, 0, 0, 1}); + nutrientDetails.put("tiger beer", new int[]{42, 3, 1, 0, 0}); + nutrientDetails.put("teh tarik", new int[]{124, 21, 3, 3, 0}); + nutrientDetails.put("sugarcane juice", new int[]{192, 52, 0, 0, 1}); + nutrientDetails.put("teh", new int[]{151, 29, 4, 1, 1}); + nutrientDetails.put("bandung", new int[]{153, 32, 1, 2, 1}); } private void setNutrientValues(String name) { diff --git a/src/main/java/seedu/fitnus/meal/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java index 8ba7f0eeba..b498a7f24a 100644 --- a/src/main/java/seedu/fitnus/meal/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -41,6 +41,24 @@ public Meal(String name, int servingSize, String currentDate) { nutrientDetails.put("pizza", new int[]{600, 80, 50, 40, 30, 20}); nutrientDetails.put("kaya toast", new int[]{459, 44, 8, 27, 10, 1}); nutrientDetails.put("laksa", new int[]{377, 71, 18, 2, 4, 10}); + nutrientDetails.put("ban mian", new int[]{475, 48, 22, 22, 3, 10}); + nutrientDetails.put("tau huay", new int[]{153, 32, 14, 1, 5, 1}); + nutrientDetails.put("nasi goreng", new int[]{346, 45, 13, 12, 10, 2}); + nutrientDetails.put("babi kecap", new int[]{607, 75, 25, 23, 2, 10}); + nutrientDetails.put("soup kambeng", new int[]{203, 6, 28, 7, 2, 5}); + nutrientDetails.put("nasi lemak", new int[]{494, 80, 13, 14, 6, 5}); + nutrientDetails.put("pepper lunch", new int[]{500, 50, 40, 11, 4, 5}); + nutrientDetails.put("char siew rice", new int[]{605, 91, 24, 16, 6, 10}); + nutrientDetails.put("pork satay with satay sauce", new int[]{36, 1, 5, 2, 10, 0}); + nutrientDetails.put("roti prata", new int[]{209, 32, 5, 7, 2, 10}); + nutrientDetails.put("mee goreng", new int[]{500, 61, 18, 20, 4, 5}); + nutrientDetails.put("chendol", new int[]{386, 59, 6, 15, 7, 2}); + nutrientDetails.put("wanton mee", new int[]{555, 97, 15, 14, 13, 10}); + nutrientDetails.put("oyster omlette", new int[]{467, 40, 19, 24, 10, 1}); + nutrientDetails.put("ice kachang", new int[]{257, 58, 6, 1, 10, 2}); + nutrientDetails.put("mala", new int[]{583, 72, 12, 30, 10, 7}); + nutrientDetails.put("hokkien prawn mee", new int[]{522, 69, 18, 19, 4, 10}); + nutrientDetails.put("durian", new int[]{147, 27, 2, 5, 3, 5}); } private void setNutrientValues(String name) { From d646442a8da6a5d2804c0a0b38791bc4900648b2 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 10 Apr 2024 17:43:46 +0800 Subject: [PATCH 190/274] Refactor Drink and Water list classes --- data/ExerciseList.txt | 4 +- db/Exercise_db.csv | 1 - src/main/java/seedu/fitnus/Ui.java | 1 + .../java/seedu/fitnus/{ => drink}/Drink.java | 2 +- .../java/seedu/fitnus/drink/DrinkList.java | 244 +++++++++++++++ .../java/seedu/fitnus/{ => drink}/Water.java | 2 +- src/main/java/seedu/fitnus/parser/Parser.java | 20 +- .../seedu/fitnus/storage/StorageManager.java | 28 +- src/main/java/seedu/fitnus/user/User.java | 284 ++---------------- 9 files changed, 302 insertions(+), 284 deletions(-) rename src/main/java/seedu/fitnus/{ => drink}/Drink.java (99%) create mode 100644 src/main/java/seedu/fitnus/drink/DrinkList.java rename src/main/java/seedu/fitnus/{ => drink}/Water.java (98%) diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt index f7416e52ee..561e56aeb9 100644 --- a/data/ExerciseList.txt +++ b/data/ExerciseList.txt @@ -1,2 +1,2 @@ -badminton,20,HIGH,02-04-2024 -running,10,HIGH,10-04-2024 +running,100,LOW,10-04-2024 +running,50,LOW,10-04-2024 diff --git a/db/Exercise_db.csv b/db/Exercise_db.csv index d37c5c8a88..b6712304ae 100644 --- a/db/Exercise_db.csv +++ b/db/Exercise_db.csv @@ -1,5 +1,4 @@ running,14,10,7 swimming,12,8,5 -badminton,100,50,5 cycling,10,7,4 diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/Ui.java index 3ab60f8778..c29cddd831 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/Ui.java @@ -1,5 +1,6 @@ package seedu.fitnus; +import seedu.fitnus.drink.Drink; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.parser.Parser; diff --git a/src/main/java/seedu/fitnus/Drink.java b/src/main/java/seedu/fitnus/drink/Drink.java similarity index 99% rename from src/main/java/seedu/fitnus/Drink.java rename to src/main/java/seedu/fitnus/drink/Drink.java index 0644fec117..8a6965770c 100644 --- a/src/main/java/seedu/fitnus/Drink.java +++ b/src/main/java/seedu/fitnus/drink/Drink.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.drink; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredDrinkException; diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java new file mode 100644 index 0000000000..d3e1179557 --- /dev/null +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -0,0 +1,244 @@ +package seedu.fitnus.drink; + +import seedu.fitnus.Date; +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.parser.Parser; + +import java.util.ArrayList; + +public class DrinkList { + public static ArrayList drinkListAll; + public static ArrayList waterListAll; + public static ArrayList drinkList; + public static ArrayList waterList; + + public DrinkList() { + drinkList = new ArrayList<>(); + waterList = new ArrayList<>(); + drinkListAll = new ArrayList<>(); + waterListAll = new ArrayList<>(); + } + + public void handleAddNewDrinkNutrient(String command) throws NegativeValueException { + Parser.parseNewDrink(command); + String description = Parser.drinkNutrientDescription; + int calories = Parser.drinkNutrientCalories; + int carbs = Parser.drinkNutrientCarbs; + int sugar = Parser.drinkNutrientSugar; + int protein = Parser.drinkNutrientProtein; + int fat = Parser.drinkNutrientFat; + Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); + + System.out.println("Added " + description + " to available drinks"); + } + + /** + * Adds a drink to the user's current drinkList, based on what the user has drank and the serving size consumed. + * + * @param command string inputted by the user, containing the drink they consumed and its serving size + * @throws IncompleteDrinkException if the user did not comply with the required format + * @throws UnregisteredDrinkException if the user has inputted a drink that was not pre-defined + * @throws NegativeValueException if the provided serving size is a negative value + */ + public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, + NegativeValueException { + Parser.parseDrink(command); + String drinkName = Parser.drinkDescription; + int servingSize = Parser.drinkSize; + + Date currentDate = new Date(); + + boolean waterExist = false; //Water intake for today does not exist flag + if (drinkName.equals("water")) { + for (Water water: waterList) { + if (currentDate.getDate().equals(water.getDate())) { + water.addWaterIntake(servingSize); + waterExist = true; + } + } + if (!waterExist) { + waterList.add(new Water(servingSize, currentDate.getDate())); + } + } else { + drinkList.add(new Drink(drinkName, servingSize, currentDate.getDate())); + } + System.out.println("Added " + servingSize + " ml of " + drinkName); + } + + /** + * Prints the user's total water intake of the day. + */ + public void handleViewWaterIntake() { + int waterIntake = 0; + for (Water water: waterList) { + waterIntake += water.getWater(); + } + System.out.println("Total water intake today: " + waterIntake + " ml"); + } + + /** + * Prints all the drinks in the drinkListToPrint, + * inclusive of the volume consumed and date. + * + * @param startIndex starting integer value when printing the list, where startIndex >= 1 + * @param drinkListToPrint arraylist containing the drinks that should be printed + */ + //@@author edwardhumi + public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { + for (int i = 0; i < drinkListToPrint.size(); i++) { + Drink currentDrink = drinkListToPrint.get(i); + System.out.println((startIndex+i) + ". " + currentDrink.getName() + " (volume: " + + currentDrink.getDrinkVolumeSize() + "ml)" + " | date: " + currentDrink.getDate()); + } + } + + /** + * Handles when the user is listing the drinks they have consumed today. + * Method first checks if the list is empty. + */ + public void handleListDrinks() { + System.out.println("here's what you have drank today"); + int totalWater = 0; + for (Water water : waterList) { + totalWater += water.getWater(); + } + if (drinkList.isEmpty() && totalWater == 0) { + System.out.println(" >> nothing so far :o"); + } else if (drinkList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + handleViewWaterIntake(); + } else { + printDrinkList(1, drinkList); + System.out.println(); + handleViewWaterIntake(); + } + } + + /** + * Handles when the user is listing all drinks they have consumed, inclusive of previously saved drinks. + * Method first checks if the list is empty. + */ + //@@author edwardhumi + public void handleListDrinksAll() { + System.out.println("here's what you have drank so far"); + int totalWater = 0; + for (Water water : waterList) { + totalWater += water.getWater(); + } + if (drinkListAll.isEmpty() && drinkList.isEmpty() && totalWater == 0) { + System.out.println(" >> nothing so far :o"); + } else if (drinkListAll.isEmpty() && drinkList.isEmpty()) { + System.out.println(" >> nothing so far :o"); + handleViewWaterIntake(); + } else { + printDrinkList(1, drinkListAll); + printDrinkList(1 + drinkListAll.size(), drinkList); + System.out.println(); + handleViewWaterIntake(); + } + } + + /** + * Handles when the user is listing the drinks they have consumed on a certain date. + * Method will first extract all drinks that have this corresponding date, + * before printing. + * + * @param command string inputted by the user, containing the date of which they would like to list drinks of + * @throws InvalidDateException if the date inputted by user is invalid + */ + //@@author edwardhumi + public void handleListDrinksDate(String command) throws InvalidDateException { + String date = Parser.parseListDate(command); + ArrayList drinkListDate = new ArrayList<>(); + for (Drink d : drinkListAll) { + if (d.getDate().equals(date)) { + drinkListDate.add(d); + } + } + for (Drink d : drinkList) { + if (d.getDate().equals(date)) { + drinkListDate.add(d); + } + } + System.out.println("here's what you have drank on " + date); + if (drinkListDate.isEmpty()) { + System.out.println(" >> nothing so far :o"); + } else { + printDrinkList(1, drinkListDate); + } + } + + /** + * Handles when the user would like to edit the serving size of a previously inputted drink. + * + * @param command string inputted by the user, containing the index of the drink to edit and the new serving size + * @throws InvalidListIndexException if the provided index is not a valid index in drinkList + * @throws NegativeValueException if the provided serving size is a negative value + * @throws IncompleteEditException if the user did not comply with the required command format + */ + //@@author claribelho + public void handleEditDrinkServingSize(String command) throws InvalidListIndexException, + NegativeValueException, IncompleteEditException { + Parser.parseEditDrink(command); + + if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { + throw new InvalidListIndexException(); + } + String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); + String drinkDate = drinkList.get(Parser.editDrinkIndex).getDate(); + + Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize, drinkDate); + drinkList.set(Parser.editDrinkIndex, updatedDrink); + System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); + } + + + /** + * Handles when the user would like to edit the total volume of the water they consumed today. + * + * @param command string inputted by the user, containing the new total volume of water + * @throws NegativeValueException if the provided serving size is a negative value + * @throws IncompleteEditException if the user did not comply with the required command format + */ + public void handleEditWaterIntake(String command) throws NegativeValueException, IncompleteEditException { + Parser.parseEditWater(command); + Date currentDate = new Date(); + for (Water water: waterList) { + if (water.getDate().equals(currentDate.getDate())) { + water.editWaterIntake(Parser.editWaterSize); + } + } + System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); + } + + /** + * Handles when the user would like to delete a previously inputted drink. + * + * @param command string inputted by the user, containing the index of the drink to delete + * @throws InvalidListIndexException if the provided index is not a valid index in drinkList + * @throws IncompleteDeleteException if the user did not comply with the required command format + */ + //@@author claribelho + public void handleDeleteDrink(String command) throws InvalidListIndexException, IncompleteDeleteException { + if (command.length() < 13) { + throw new IncompleteDeleteException(); + } + + int drinkIndex = Integer.parseInt(command.substring(12).trim()) - 1; + if (drinkIndex >= drinkList.size() || drinkIndex < 0) { + throw new InvalidListIndexException(); + } + + String drinkName = drinkList.get(drinkIndex).getName(); + drinkList.remove(drinkIndex); + System.out.println("Removed " + drinkName + " from drinks"); + } + + +} diff --git a/src/main/java/seedu/fitnus/Water.java b/src/main/java/seedu/fitnus/drink/Water.java similarity index 98% rename from src/main/java/seedu/fitnus/Water.java rename to src/main/java/seedu/fitnus/drink/Water.java index 7eccdeb358..48ca484b92 100644 --- a/src/main/java/seedu/fitnus/Water.java +++ b/src/main/java/seedu/fitnus/drink/Water.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.drink; public class Water { private int waterIntake; diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 6ff21847d9..982dd05b6e 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,6 +1,6 @@ package seedu.fitnus.parser; -import seedu.fitnus.Drink; +import seedu.fitnus.drink.Drink; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; @@ -102,13 +102,13 @@ public void handleCommand(String command) { } else if (command.startsWith("eat")) { user.myMealList.handleMeal(command); } else if (command.startsWith("drink")) { - user.handleDrink(command); + user.myDrinkList.handleDrink(command); } else if (command.startsWith("exercise")) { user.myExerciseList.handleExercise(command); } else if (command.startsWith("newMeal")) { user.handleAddNewMealNutrient(command); } else if (command.startsWith("newDrink")) { - user.handleAddNewDrinkNutrient(command); + user.myDrinkList.handleAddNewDrinkNutrient(command); } else if (command.startsWith("newExercise")) { user.myExerciseList.handleAddNewExerciseCalories(command); }else if (command.equals("allMeals")) { @@ -136,7 +136,7 @@ public void handleCommand(String command) { } else if (command.equals("fat")) { user.handleViewFat(); } else if (command.equals("viewWater")) { - user.handleViewWaterIntake(); + user.myDrinkList.handleViewWaterIntake(); } else if (command.equals("fiber")) { user.handleViewFiber(); } else if (command.equals("listMeals")) { @@ -146,11 +146,11 @@ public void handleCommand(String command) { } else if (command.startsWith("listMeals") && command.contains("d/")) { user.myMealList.handleListMealsDate(command); } else if (command.equals("listDrinks")) { - user.handleListDrinks(); + user.myDrinkList.handleListDrinks(); } else if (command.equals("listDrinksAll")) { - user.handleListDrinksAll(); + user.myDrinkList.handleListDrinksAll(); } else if (command.startsWith("listDrinks") && command.contains("d/")) { - user.handleListDrinksDate(command); + user.myDrinkList.handleListDrinksDate(command); } else if (command.equals("listExercises")) { user.myExerciseList.handleListExercises(); } else if (command.equals("listExercisesAll")) { @@ -166,13 +166,13 @@ public void handleCommand(String command) { } else if (command.startsWith("editMeal")) { user.myMealList.handleEditMealServingSize(command); } else if (command.startsWith("editDrink")) { - user.handleEditDrinkServingSize(command); + user.myDrinkList.handleEditDrinkServingSize(command); } else if (command.startsWith("editWater")) { - user.handleEditWaterIntake(command); + user.myDrinkList.handleEditWaterIntake(command); } else if (command.startsWith("deleteMeal")) { user.myMealList.handleDeleteMeal(command); } else if (command.startsWith("deleteDrink")) { - user.handleDeleteDrink(command); + user.myDrinkList.handleDeleteDrink(command); } else if (command.startsWith("deleteExercise")) { user.myExerciseList.handleDeleteExercise(command); } else if (command.equals("clear")) { diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index 5a2bdd1405..d564f8bde8 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -2,10 +2,10 @@ import seedu.fitnus.Date; import seedu.fitnus.meal.Meal; -import seedu.fitnus.Drink; +import seedu.fitnus.drink.Drink; import seedu.fitnus.exercise.ExerciseIntensity; import seedu.fitnus.exercise.Exercise; -import seedu.fitnus.Water; +import seedu.fitnus.drink.Water; import seedu.fitnus.user.User; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.UnregisteredExerciseException; @@ -78,26 +78,26 @@ public void loadDrink(Storage drinkStorage) { String drinkDate = Parser.drinkStorageDate; int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { - User.waterListAll.add(new Water(drinkSize, drinkDate)); + User.myDrinkList.waterListAll.add(new Water(drinkSize, drinkDate)); } else { - User.drinkListAll.add(new Drink(drinkDescription, drinkSize, drinkDate)); + User.myDrinkList.drinkListAll.add(new Drink(drinkDescription, drinkSize, drinkDate)); } } } Date currentDate = new Date(); String todayDate = currentDate.getDate(); - for (Drink d : User.drinkListAll) { + for (Drink d : User.myDrinkList.drinkListAll) { if (d.getDate().equals(todayDate)) { - User.drinkList.add(d); + User.myDrinkList.drinkList.add(d); } } - User.drinkListAll.removeAll(User.drinkList); - for (Water w : User.waterListAll) { + User.myDrinkList.drinkListAll.removeAll(User.myDrinkList.drinkList); + for (Water w : User.myDrinkList.waterListAll) { if (w.getDate().equals(todayDate)) { - User.waterList.add(w); + User.myDrinkList.waterList.add(w); } } - User.waterListAll.removeAll(User.waterList); + User.myDrinkList.waterListAll.removeAll(User.myDrinkList.waterList); } catch (FileNotFoundException e) { drinkStorage.createFile(); } @@ -244,19 +244,19 @@ public void saveMeal(Storage mealStorage) { * @param drinkStorage contains filePath and folderPath of where the saved drinksList are stored. */ public void saveDrink(Storage drinkStorage) { - for (Water water : User.waterListAll) { + for (Water water : User.myDrinkList.waterListAll) { String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); drinkStorage.appendTextContent(waterSavedData); } - for (Water water : User.waterList) { + for (Water water : User.myDrinkList.waterList) { String waterSavedData = "water" + "," + water.getWater() + "," + water.getDate(); drinkStorage.appendTextContent(waterSavedData); } - for (Drink drink : User.drinkListAll) { + for (Drink drink : User.myDrinkList.drinkListAll) { String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); drinkStorage.appendTextContent(drinkSavedData); } - for (Drink drink : User.drinkList) { + for (Drink drink : User.myDrinkList.drinkList) { String drinkSavedData = drink.getName() + "," + drink.getDrinkVolumeSize() + "," + drink.getDate(); drinkStorage.appendTextContent(drinkSavedData); } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index fc4623a8b5..ddb2df9d99 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -1,20 +1,14 @@ package seedu.fitnus.user; -import seedu.fitnus.Date; -import seedu.fitnus.Drink; +import seedu.fitnus.drink.Drink; +import seedu.fitnus.drink.DrinkList; import seedu.fitnus.meal.Meal; import seedu.fitnus.meal.MealList; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseList; import seedu.fitnus.parser.Parser; -import seedu.fitnus.Water; - -import seedu.fitnus.exception.IncompleteDeleteException; -import seedu.fitnus.exception.IncompleteDrinkException; -import seedu.fitnus.exception.IncompleteEditException; -import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.drink.Water; import seedu.fitnus.exception.NegativeValueException; -import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.InvalidDateException; import java.util.ArrayList; @@ -25,22 +19,13 @@ public class User { public static final int RECOMMEND_WATER_INTAKE = 2600; public static final int RECOMMEND_CALORIE_INTAKE = 2200; - public static ArrayList drinkList; - public static ArrayList waterList; public static MealList myMealList; - public static ArrayList drinkListAll; - public static ArrayList waterListAll; public static ExerciseList myExerciseList; + public static DrinkList myDrinkList; public User() { myMealList = new MealList(); - - drinkList = new ArrayList<>(); - waterList = new ArrayList<>(); - - drinkListAll = new ArrayList<>(); - waterListAll = new ArrayList<>(); - + myDrinkList = new DrinkList(); myExerciseList = new ExerciseList(); } @@ -58,52 +43,6 @@ public void handleAddNewMealNutrient(String command) throws NegativeValueExcepti System.out.println("Added " + description + " to available meals"); } - public void handleAddNewDrinkNutrient(String command) throws NegativeValueException{ - Parser.parseNewDrink(command); - String description = Parser.drinkNutrientDescription; - int calories = Parser.drinkNutrientCalories; - int carbs = Parser.drinkNutrientCarbs; - int sugar = Parser.drinkNutrientSugar; - int protein = Parser.drinkNutrientProtein; - int fat = Parser.drinkNutrientFat; - Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); - - System.out.println("Added " + description + " to available drinks"); - } - - /** - * Adds a drink to the user's current drinkList, based on what the user has drank and the serving size consumed. - * - * @param command string inputted by the user, containing the drink they consumed and its serving size - * @throws IncompleteDrinkException if the user did not comply with the required format - * @throws UnregisteredDrinkException if the user has inputted a drink that was not pre-defined - * @throws NegativeValueException if the provided serving size is a negative value - */ - public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, - NegativeValueException { - Parser.parseDrink(command); - String drinkName = Parser.drinkDescription; - int servingSize = Parser.drinkSize; - - Date currentDate = new Date(); - - boolean waterExist = false; //Water intake for today does not exist flag - if (drinkName.equals("water")) { - for (Water water: waterList) { - if (currentDate.getDate().equals(water.getDate())) { - water.addWaterIntake(servingSize); - waterExist = true; - } - } - if (!waterExist) { - waterList.add(new Water(servingSize, currentDate.getDate())); - } - } else { - drinkList.add(new Drink(drinkName, servingSize, currentDate.getDate())); - } - System.out.println("Added " + servingSize + " ml of " + drinkName); - } - /** * Prints the user's total calorie intake of the day. * The method sums up the calories from meals and drinks, and subtracts calories burnt from exercise. @@ -113,7 +52,7 @@ public void handleViewCalories() { for (Meal meal: myMealList.mealList) { caloriesCount += meal.getCalories(); } - for (Drink drink: drinkList) { + for (Drink drink: myDrinkList.drinkList) { caloriesCount += drink.getCalories(); } for (Exercise exercise: myExerciseList.exerciseList) { @@ -131,7 +70,7 @@ public void handleViewCarbohydrates() { for (Meal meal: myMealList.mealList) { carbohydratesCount += meal.getCarbs(); } - for (Drink drink: drinkList) { + for (Drink drink: myDrinkList.drinkList) { carbohydratesCount += drink.getCarbs(); } System.out.println("Total Carbohydrates: " + carbohydratesCount + " grams"); @@ -146,23 +85,12 @@ public void handleViewProteins() { for (Meal meal: myMealList.mealList) { proteinCount += meal.getProtein(); } - for (Drink drink: drinkList) { + for (Drink drink: myDrinkList.drinkList) { proteinCount += drink.getProtein(); } System.out.println("Total Proteins: " + proteinCount + " grams"); } - /** - * Prints the user's total water intake of the day. - */ - public void handleViewWaterIntake() { - int waterIntake = 0; - for (Water water: waterList) { - waterIntake += water.getWater(); - } - System.out.println("Total water intake today: " + waterIntake + " ml"); - } - /** * Prints the user's total fiber intake of the day. * The method sums up the fiber from meals. @@ -184,7 +112,7 @@ public void handleViewFat() { for (Meal meal: myMealList.mealList) { fatCount += meal.getFat(); } - for (Drink drink: drinkList) { + for (Drink drink: myDrinkList.drinkList) { fatCount += drink.getFat(); } System.out.println("Total Fat: " + fatCount + " grams"); @@ -199,116 +127,27 @@ public void handleViewSugar() { for (Meal meal: myMealList.mealList) { sugarCount += meal.getSugar(); } - for (Drink drink: drinkList) { + for (Drink drink: myDrinkList.drinkList) { sugarCount += drink.getSugar(); } System.out.println("Total Sugar: " + sugarCount + " grams"); } - /** - * Prints all the drinks in the drinkListToPrint, - * inclusive of the volume consumed and date. - * - * @param startIndex starting integer value when printing the list, where startIndex >= 1 - * @param drinkListToPrint arraylist containing the drinks that should be printed - */ - public void printDrinkList(int startIndex, ArrayList drinkListToPrint) { - for (int i = 0; i < drinkListToPrint.size(); i++) { - Drink currentDrink = drinkListToPrint.get(i); - System.out.println((startIndex+i) + ". " + currentDrink.getName() + " (volume: " - + currentDrink.getDrinkVolumeSize() + "ml)" + " | date: " + currentDrink.getDate()); - } - } - - /** - * Handles when the user is listing the drinks they have consumed today. - * Method first checks if the list is empty. - */ - public void handleListDrinks() { - System.out.println("here's what you have drank today"); - int totalWater = 0; - for (Water water : waterList) { - totalWater += water.getWater(); - } - if (drinkList.isEmpty() && totalWater == 0) { - System.out.println(" >> nothing so far :o"); - } else if (drinkList.isEmpty()) { - System.out.println(" >> nothing so far :o"); - handleViewWaterIntake(); - } else { - printDrinkList(1, drinkList); - System.out.println(); - handleViewWaterIntake(); - } - } - - /** - * Handles when the user is listing all drinks they have consumed, inclusive of previously saved drinks. - * Method first checks if the list is empty. - */ - public void handleListDrinksAll() { - System.out.println("here's what you have drank so far"); - int totalWater = 0; - for (Water water : waterList) { - totalWater += water.getWater(); - } - if (drinkListAll.isEmpty() && drinkList.isEmpty() && totalWater == 0) { - System.out.println(" >> nothing so far :o"); - } else if (drinkListAll.isEmpty() && drinkList.isEmpty()) { - System.out.println(" >> nothing so far :o"); - handleViewWaterIntake(); - } else { - printDrinkList(1, drinkListAll); - printDrinkList(1 + drinkListAll.size(), drinkList); - System.out.println(); - handleViewWaterIntake(); - } - } - - /** - * Handles when the user is listing the drinks they have consumed on a certain date. - * Method will first extract all drinks that have this corresponding date, - * before printing. - * - * @param command string inputted by the user, containing the date of which they would like to list drinks of - * @throws InvalidDateException if the date inputted by user is invalid - */ - public void handleListDrinksDate(String command) throws InvalidDateException { - String date = Parser.parseListDate(command); - ArrayList drinkListDate = new ArrayList<>(); - for (Drink d : drinkListAll) { - if (d.getDate().equals(date)) { - drinkListDate.add(d); - } - } - for (Drink d : drinkList) { - if (d.getDate().equals(date)) { - drinkListDate.add(d); - } - } - System.out.println("here's what you have drank on " + date); - if (drinkListDate.isEmpty()) { - System.out.println(" >> nothing so far :o"); - } else { - printDrinkList(1, drinkListDate); - } - } - /** * Handles when the user is listing all meals and drinks they have inputted today. * Method first checks if the lists is empty. */ public void handleListEverything() { System.out.println("here's what you have consumed today"); - if (drinkList.isEmpty() && myMealList.mealList.isEmpty()) { + if (myDrinkList.drinkList.isEmpty() && myMealList.mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); System.out.println(); - handleViewWaterIntake(); + myDrinkList.handleViewWaterIntake(); } else { MealList.printMealList(1, myMealList.mealList); - printDrinkList(myMealList.mealList.size()+1, drinkList); + myDrinkList.printDrinkList(myMealList.mealList.size()+1, myDrinkList.drinkList); System.out.println(); - handleViewWaterIntake(); + myDrinkList.handleViewWaterIntake(); } System.out.println(" ~~~"); @@ -322,19 +161,20 @@ public void handleListEverything() { */ public void handleListEverythingAll() { System.out.println("here's what you have consumed so far"); - if (drinkListAll.isEmpty() && myMealList.mealListAll.isEmpty() && drinkList.isEmpty() + if (myDrinkList.drinkListAll.isEmpty() && myMealList.mealListAll.isEmpty() && myDrinkList.drinkList.isEmpty() && myMealList.mealList.isEmpty()) { System.out.println(" >> nothing so far :o"); System.out.println(); - handleViewWaterIntake(); + myDrinkList.handleViewWaterIntake(); } else { MealList.printMealList(1, myMealList.mealListAll); MealList.printMealList(myMealList.mealListAll.size() + 1, myMealList.mealList); - printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() + 1, drinkListAll); - printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() - + drinkListAll.size() + 1, drinkList); + myDrinkList.printDrinkList(myMealList.mealListAll.size() + + myMealList.mealList.size() + 1, myDrinkList.drinkListAll); + myDrinkList.printDrinkList(myMealList.mealListAll.size() + myMealList.mealList.size() + + myDrinkList.drinkListAll.size() + 1, myDrinkList.drinkList); System.out.println(); - handleViewWaterIntake(); + myDrinkList.handleViewWaterIntake(); } System.out.println(" ~~~"); @@ -364,12 +204,12 @@ public void handleListEverythingDate(String command) throws InvalidDateException } ArrayList drinkListDate = new ArrayList<>(); - for (Drink d : drinkListAll) { + for (Drink d : myDrinkList.drinkListAll) { if (d.getDate().equals(date)) { drinkListDate.add(d); } } - for (Drink d : drinkList) { + for (Drink d : myDrinkList.drinkList) { if (d.getDate().equals(date)) { drinkListDate.add(d); } @@ -381,7 +221,7 @@ public void handleListEverythingDate(String command) throws InvalidDateException System.out.println(); } else { MealList.printMealList(1, mealListDate); - printDrinkList(1 + mealListDate.size(), drinkListDate); + myDrinkList.printDrinkList(1 + mealListDate.size(), drinkListDate); System.out.println(); } @@ -389,84 +229,18 @@ public void handleListEverythingDate(String command) throws InvalidDateException myExerciseList.handleListExercisesDate(command); } - - /** - * Handles when the user would like to edit the serving size of a previously inputted drink. - * - * @param command string inputted by the user, containing the index of the drink to edit and the new serving size - * @throws InvalidListIndexException if the provided index is not a valid index in drinkList - * @throws NegativeValueException if the provided serving size is a negative value - * @throws IncompleteEditException if the user did not comply with the required command format - */ - public void handleEditDrinkServingSize(String command) throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { - Parser.parseEditDrink(command); - - if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { - throw new InvalidListIndexException(); - } - String drinkName = drinkList.get(Parser.editDrinkIndex).getName(); - String drinkDate = drinkList.get(Parser.editDrinkIndex).getDate(); - - Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize, drinkDate); - drinkList.set(Parser.editDrinkIndex, updatedDrink); - System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); - } - - /** - * Handles when the user would like to edit the total volume of the water they consumed today. - * - * @param command string inputted by the user, containing the new total volume of water - * @throws NegativeValueException if the provided serving size is a negative value - * @throws IncompleteEditException if the user did not comply with the required command format - */ - public void handleEditWaterIntake(String command) throws NegativeValueException, IncompleteEditException { - Parser.parseEditWater(command); - Date currentDate = new Date(); - for (Water water: waterList) { - if (water.getDate().equals(currentDate.getDate())) { - water.editWaterIntake(Parser.editWaterSize); - } - } - System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); - } - - - /** - * Handles when the user would like to delete a previously inputted drink. - * - * @param command string inputted by the user, containing the index of the drink to delete - * @throws InvalidListIndexException if the provided index is not a valid index in drinkList - * @throws IncompleteDeleteException if the user did not comply with the required command format - */ - public void handleDeleteDrink(String command) throws InvalidListIndexException, IncompleteDeleteException { - if (command.length() < 13) { - throw new IncompleteDeleteException(); - } - - int drinkIndex = Integer.parseInt(command.substring(12).trim()) - 1; - if (drinkIndex >= drinkList.size() || drinkIndex < 0) { - throw new InvalidListIndexException(); - } - - String drinkName = drinkList.get(drinkIndex).getName(); - drinkList.remove(drinkIndex); - System.out.println("Removed " + drinkName + " from drinks"); - } - - /** * Handle when user would like to clear all entries from today. * This includes all meals, drinks and exercise. */ public void handleClear() { myMealList.mealList.clear(); - drinkList.clear(); - waterList.clear(); + myDrinkList.drinkList.clear(); + myDrinkList.waterList.clear(); myExerciseList.exerciseList.clear(); assert myMealList.mealList.isEmpty(): "clearing of meal list failed"; - assert drinkList.isEmpty(): "clearing of drink list failed"; + assert myDrinkList.drinkList.isEmpty(): "clearing of drink list failed"; assert myExerciseList.exerciseList.isEmpty(): "clearing of exercise list failed"; System.out.println("All entries have been deleted"); @@ -478,7 +252,7 @@ public void handleClear() { */ public void handleRecommendations() { int waterIntake = 0; - for (Water water: waterList) { + for (Water water: myDrinkList.waterList) { waterIntake += water.getWater(); } int waterDifference = RECOMMEND_WATER_INTAKE -waterIntake; @@ -493,7 +267,7 @@ public void handleRecommendations() { for (Meal meal: myMealList.mealList) { caloriesCount += meal.getCalories(); } - for (Drink drink: drinkList) { + for (Drink drink: myDrinkList.drinkList) { caloriesCount += drink.getCalories(); } for (Exercise exercise: myExerciseList.exerciseList) { From 87b89b7818c2eefb6d36ae1e4b96a7372837e60e Mon Sep 17 00:00:00 2001 From: Bryvo Date: Wed, 10 Apr 2024 17:51:12 +0800 Subject: [PATCH 191/274] Create ui and date packages --- src/main/java/seedu/fitnus/FitNus.java | 2 ++ src/main/java/seedu/fitnus/{ => date}/Date.java | 2 +- src/main/java/seedu/fitnus/drink/DrinkList.java | 2 +- src/main/java/seedu/fitnus/exercise/ExerciseList.java | 2 +- src/main/java/seedu/fitnus/meal/MealList.java | 2 +- src/main/java/seedu/fitnus/parser/Parser.java | 2 +- src/main/java/seedu/fitnus/storage/StorageManager.java | 2 +- src/main/java/seedu/fitnus/{ => ui}/Ui.java | 2 +- 8 files changed, 9 insertions(+), 7 deletions(-) rename src/main/java/seedu/fitnus/{ => date}/Date.java (98%) rename src/main/java/seedu/fitnus/{ => ui}/Ui.java (99%) diff --git a/src/main/java/seedu/fitnus/FitNus.java b/src/main/java/seedu/fitnus/FitNus.java index c2a91af478..11af2cee8e 100644 --- a/src/main/java/seedu/fitnus/FitNus.java +++ b/src/main/java/seedu/fitnus/FitNus.java @@ -1,5 +1,7 @@ package seedu.fitnus; +import seedu.fitnus.ui.Ui; + public class FitNus { private static Ui ui; diff --git a/src/main/java/seedu/fitnus/Date.java b/src/main/java/seedu/fitnus/date/Date.java similarity index 98% rename from src/main/java/seedu/fitnus/Date.java rename to src/main/java/seedu/fitnus/date/Date.java index 128b7727d8..a403070b1b 100644 --- a/src/main/java/seedu/fitnus/Date.java +++ b/src/main/java/seedu/fitnus/date/Date.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.date; import java.text.ParseException; import java.text.SimpleDateFormat; diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index d3e1179557..1d97931e0d 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -1,6 +1,6 @@ package seedu.fitnus.drink; -import seedu.fitnus.Date; +import seedu.fitnus.date.Date; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java index cdf332b13d..0bec33ca23 100644 --- a/src/main/java/seedu/fitnus/exercise/ExerciseList.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -1,6 +1,6 @@ package seedu.fitnus.exercise; -import seedu.fitnus.Date; +import seedu.fitnus.date.Date; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.InvalidDateException; diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index aeb666b553..913bfc1f4b 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -1,6 +1,6 @@ package seedu.fitnus.meal; -import seedu.fitnus.Date; +import seedu.fitnus.date.Date; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.IncompleteMealException; diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 982dd05b6e..d4cf02f3e0 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -4,7 +4,7 @@ import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; -import seedu.fitnus.Date; +import seedu.fitnus.date.Date; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index d564f8bde8..95e67a3755 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -1,6 +1,6 @@ package seedu.fitnus.storage; -import seedu.fitnus.Date; +import seedu.fitnus.date.Date; import seedu.fitnus.meal.Meal; import seedu.fitnus.drink.Drink; import seedu.fitnus.exercise.ExerciseIntensity; diff --git a/src/main/java/seedu/fitnus/Ui.java b/src/main/java/seedu/fitnus/ui/Ui.java similarity index 99% rename from src/main/java/seedu/fitnus/Ui.java rename to src/main/java/seedu/fitnus/ui/Ui.java index c29cddd831..5cf9c2f48f 100644 --- a/src/main/java/seedu/fitnus/Ui.java +++ b/src/main/java/seedu/fitnus/ui/Ui.java @@ -1,4 +1,4 @@ -package seedu.fitnus; +package seedu.fitnus.ui; import seedu.fitnus.drink.Drink; import seedu.fitnus.meal.Meal; From bfdf3db527599dfe619f6729337ddbd37ac8704e Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 18:50:05 +0800 Subject: [PATCH 192/274] Add check if input date has passed --- src/main/java/seedu/fitnus/date/Date.java | 31 +---------- .../seedu/fitnus/date/DateValidation.java | 52 +++++++++++++++++++ .../java/seedu/fitnus/drink/DrinkList.java | 3 +- .../fitnus/exception/FutureDateException.java | 5 ++ .../seedu/fitnus/exercise/ExerciseList.java | 3 +- src/main/java/seedu/fitnus/meal/MealList.java | 3 +- src/main/java/seedu/fitnus/parser/Parser.java | 8 ++- src/main/java/seedu/fitnus/user/User.java | 3 +- .../java/seedu/fitnus/parser/ParserTest.java | 3 +- 9 files changed, 74 insertions(+), 37 deletions(-) create mode 100644 src/main/java/seedu/fitnus/date/DateValidation.java create mode 100644 src/main/java/seedu/fitnus/exception/FutureDateException.java diff --git a/src/main/java/seedu/fitnus/date/Date.java b/src/main/java/seedu/fitnus/date/Date.java index a403070b1b..fc7fc32d8c 100644 --- a/src/main/java/seedu/fitnus/date/Date.java +++ b/src/main/java/seedu/fitnus/date/Date.java @@ -7,7 +7,7 @@ * Class that handles any references to the current date and time. */ public class Date { - private String currentDate; + protected static String currentDate; /** * Constructor that gets the current system date and formats it in the stated format. @@ -31,33 +31,4 @@ public Date() { public String getDate() { return currentDate; } - - /** - * Returns true if the date inputted by the user is a valid date. - * The method verifies the day, month and year are in the correct range. - * - * @param date string containing the date to check if valid - * @return true if the date inputted by the user is a valid date. - */ - public static boolean isValidDate(String date) { - SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); - dateFormat.setLenient(false); - try { - java.util.Date javaDate = dateFormat.parse(date); - } catch (ParseException e) { - return false; - } - String[] arrayOfDates = date.split("-"); - int day = Integer.parseInt(arrayOfDates[0]); - int month = Integer.parseInt(arrayOfDates[1]); - int year = Integer.parseInt(arrayOfDates[2]); - if (day < 1 || month < 1 || month > 12 || year < 0) { - return false; - } - int[] dayInMonth = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - if (day > dayInMonth[month - 1]) { - return false; - } - return true; - } } diff --git a/src/main/java/seedu/fitnus/date/DateValidation.java b/src/main/java/seedu/fitnus/date/DateValidation.java new file mode 100644 index 0000000000..df2b76bb99 --- /dev/null +++ b/src/main/java/seedu/fitnus/date/DateValidation.java @@ -0,0 +1,52 @@ +package seedu.fitnus.date; + +import seedu.fitnus.exception.FutureDateException; +import seedu.fitnus.exception.InvalidDateException; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +public class DateValidation extends Date { + /** + * Returns true if the date inputted by the user is a valid date. + * The method verifies the day, month and year are in the correct range. + * + * @param date string containing the date to check if valid + * @return true if the date inputted by the user is a valid date. + */ + //@@author edwardhumi + public static boolean isValidDate(String date) throws FutureDateException { + SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); + dateFormat.setLenient(false); + try { + java.util.Date javaDate = dateFormat.parse(date); + checkDateHasPassed(javaDate); + } catch (ParseException e) { + return false; + } + + + String[] arrayOfDates = date.split("-"); + int day = Integer.parseInt(arrayOfDates[0]); + int month = Integer.parseInt(arrayOfDates[1]); + int year = Integer.parseInt(arrayOfDates[2]); + if (day < 1 || month < 1 || month > 12 || year < 0) { + return false; + } + int[] dayInMonth = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if (day > dayInMonth[month - 1]) { + return false; + } + return true; + } + + public static boolean checkDateHasPassed(java.util.Date inputDate) throws FutureDateException { + long millis = System.currentTimeMillis(); + java.sql.Date currentDate = new java.sql.Date(millis); + + if (inputDate.after(currentDate)) { + throw new FutureDateException(); + } + return true; + } +} diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index 1d97931e0d..3da67bc184 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -1,6 +1,7 @@ package seedu.fitnus.drink; import seedu.fitnus.date.Date; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; @@ -153,7 +154,7 @@ public void handleListDrinksAll() { * @throws InvalidDateException if the date inputted by user is invalid */ //@@author edwardhumi - public void handleListDrinksDate(String command) throws InvalidDateException { + public void handleListDrinksDate(String command) throws InvalidDateException, FutureDateException { String date = Parser.parseListDate(command); ArrayList drinkListDate = new ArrayList<>(); for (Drink d : drinkListAll) { diff --git a/src/main/java/seedu/fitnus/exception/FutureDateException.java b/src/main/java/seedu/fitnus/exception/FutureDateException.java new file mode 100644 index 0000000000..ba40f06cd9 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/FutureDateException.java @@ -0,0 +1,5 @@ +package seedu.fitnus.exception; + +public class FutureDateException extends Exception { + +} diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java index 0bec33ca23..b10d88665e 100644 --- a/src/main/java/seedu/fitnus/exercise/ExerciseList.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -1,6 +1,7 @@ package seedu.fitnus.exercise; import seedu.fitnus.date.Date; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.InvalidDateException; @@ -84,7 +85,7 @@ public void handleListExercisesAll() { * @param command string inputted by the user, containing the date of which they would like to list exercises of * @throws InvalidDateException if the date inputted by user is invalid */ - public void handleListExercisesDate(String command) throws InvalidDateException { + public void handleListExercisesDate(String command) throws InvalidDateException, FutureDateException { String date = Parser.parseListDate(command); ArrayList exercisesListDate = new ArrayList<>(); for (Exercise e : exerciseListAll) { diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index 913bfc1f4b..640e52a099 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -1,6 +1,7 @@ package seedu.fitnus.meal; import seedu.fitnus.date.Date; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.IncompleteMealException; @@ -97,7 +98,7 @@ public static void handleListMealsAll() { * @throws InvalidDateException if the date inputted by user is invalid */ //@@author edwardhumi - public static void handleListMealsDate(String command) throws InvalidDateException { + public static void handleListMealsDate(String command) throws InvalidDateException, FutureDateException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); for (Meal m : mealListAll) { diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index d4cf02f3e0..39b0b15688 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,6 +1,8 @@ package seedu.fitnus.parser; +import seedu.fitnus.date.DateValidation; import seedu.fitnus.drink.Drink; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; @@ -221,6 +223,8 @@ public void handleCommand(String command) { System.out.println("Your serving size/exercise duration must be at least 0!"); } catch (InvalidDateException e) { System.out.println("Invalid date provided. Your date must be in the format of dd-MM-yyyy."); + } catch (FutureDateException e) { + System.out.println("Specified date has not passed. Please try another date."); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); } @@ -634,10 +638,10 @@ public static void parseExerciseCalories(String data) throws IllegalArgumentExce * @return The parsed date string. * @throws InvalidDateException If the date format is invalid. */ - public static String parseListDate(String command) throws InvalidDateException { + public static String parseListDate(String command) throws InvalidDateException, FutureDateException { int indexOfDate = command.indexOf("d/") + 2; String date = command.substring(indexOfDate); - if (Date.isValidDate(date)) { + if (DateValidation.isValidDate(date) ) { return date; } throw new InvalidDateException(); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index ddb2df9d99..1a84d126d7 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -2,6 +2,7 @@ import seedu.fitnus.drink.Drink; import seedu.fitnus.drink.DrinkList; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.meal.Meal; import seedu.fitnus.meal.MealList; import seedu.fitnus.exercise.Exercise; @@ -189,7 +190,7 @@ public void handleListEverythingAll() { * @param command string inputted by the user, containing the date of which they would like to list * @throws InvalidDateException if the date inputted by user is invalid */ - public void handleListEverythingDate(String command) throws InvalidDateException { + public void handleListEverythingDate(String command) throws InvalidDateException, FutureDateException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); for (Meal m : myMealList.mealListAll) { diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 55c7c96762..317a615f96 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -1,6 +1,7 @@ package seedu.fitnus.parser; import org.junit.jupiter.api.Test; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteEditException; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.UnregisteredDrinkException; @@ -156,7 +157,7 @@ public void parseExerciseCalories_validInputs_success() throws NegativeValueExce } @Test - public void parseListDate_validInputs_success() throws InvalidDateException { + public void parseListDate_validInputs_success() throws InvalidDateException, FutureDateException { String command = "listMeals d/12-02-2024"; String date = Parser.parseListDate(command); assertEquals("12-02-2024", date); From 1c0ef11d5b402aedc49e5934aee6cdecafa61c98 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 19:06:17 +0800 Subject: [PATCH 193/274] Fix date validation for user input dates --- .../seedu/fitnus/date/DateValidation.java | 42 +++++++++---------- .../java/seedu/fitnus/drink/DrinkList.java | 3 +- .../seedu/fitnus/exercise/ExerciseList.java | 3 +- src/main/java/seedu/fitnus/meal/MealList.java | 3 +- src/main/java/seedu/fitnus/parser/Parser.java | 12 +++--- src/main/java/seedu/fitnus/user/User.java | 3 +- .../java/seedu/fitnus/parser/ParserTest.java | 4 +- 7 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/main/java/seedu/fitnus/date/DateValidation.java b/src/main/java/seedu/fitnus/date/DateValidation.java index df2b76bb99..f5aec6d64c 100644 --- a/src/main/java/seedu/fitnus/date/DateValidation.java +++ b/src/main/java/seedu/fitnus/date/DateValidation.java @@ -1,7 +1,6 @@ package seedu.fitnus.date; import seedu.fitnus.exception.FutureDateException; -import seedu.fitnus.exception.InvalidDateException; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -14,30 +13,31 @@ public class DateValidation extends Date { * @param date string containing the date to check if valid * @return true if the date inputted by the user is a valid date. */ - //@@author edwardhumi - public static boolean isValidDate(String date) throws FutureDateException { + public static String formatDateIfValid(String date) throws FutureDateException, ParseException { SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); dateFormat.setLenient(false); - try { - java.util.Date javaDate = dateFormat.parse(date); - checkDateHasPassed(javaDate); - } catch (ParseException e) { - return false; - } + String formattedDate = date; - String[] arrayOfDates = date.split("-"); - int day = Integer.parseInt(arrayOfDates[0]); - int month = Integer.parseInt(arrayOfDates[1]); - int year = Integer.parseInt(arrayOfDates[2]); - if (day < 1 || month < 1 || month > 12 || year < 0) { - return false; - } - int[] dayInMonth = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - if (day > dayInMonth[month - 1]) { - return false; - } - return true; + java.util.Date javaDate = dateFormat.parse(date); + checkDateHasPassed(javaDate); + formattedDate = dateFormat.format(javaDate); + + return formattedDate; + +// +// +// String[] arrayOfDates = date.split("-"); +// int day = Integer.parseInt(arrayOfDates[0]); +// int month = Integer.parseInt(arrayOfDates[1]); +// int year = Integer.parseInt(arrayOfDates[2]); +// if (day < 1 || month < 1 || month > 12 || year < 0) { +// return false; +// } +// int[] dayInMonth = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +// if (day > dayInMonth[month - 1]) { +// return false; +// } } public static boolean checkDateHasPassed(java.util.Date inputDate) throws FutureDateException { diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index 3da67bc184..c067c54b2f 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -11,6 +11,7 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.parser.Parser; +import java.text.ParseException; import java.util.ArrayList; public class DrinkList { @@ -154,7 +155,7 @@ public void handleListDrinksAll() { * @throws InvalidDateException if the date inputted by user is invalid */ //@@author edwardhumi - public void handleListDrinksDate(String command) throws InvalidDateException, FutureDateException { + public void handleListDrinksDate(String command) throws InvalidDateException, FutureDateException, ParseException { String date = Parser.parseListDate(command); ArrayList drinkListDate = new ArrayList<>(); for (Drink d : drinkListAll) { diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java index b10d88665e..c0d17f0513 100644 --- a/src/main/java/seedu/fitnus/exercise/ExerciseList.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -10,6 +10,7 @@ import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.parser.Parser; +import java.text.ParseException; import java.util.ArrayList; public class ExerciseList { @@ -85,7 +86,7 @@ public void handleListExercisesAll() { * @param command string inputted by the user, containing the date of which they would like to list exercises of * @throws InvalidDateException if the date inputted by user is invalid */ - public void handleListExercisesDate(String command) throws InvalidDateException, FutureDateException { + public void handleListExercisesDate(String command) throws InvalidDateException, FutureDateException, ParseException { String date = Parser.parseListDate(command); ArrayList exercisesListDate = new ArrayList<>(); for (Exercise e : exerciseListAll) { diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index 640e52a099..0f6efac34f 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -11,6 +11,7 @@ import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.parser.Parser; +import java.text.ParseException; import java.util.ArrayList; public class MealList { @@ -98,7 +99,7 @@ public static void handleListMealsAll() { * @throws InvalidDateException if the date inputted by user is invalid */ //@@author edwardhumi - public static void handleListMealsDate(String command) throws InvalidDateException, FutureDateException { + public static void handleListMealsDate(String command) throws InvalidDateException, FutureDateException, ParseException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); for (Meal m : mealListAll) { diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 39b0b15688..969e8f3a7d 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -6,7 +6,6 @@ import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; -import seedu.fitnus.date.Date; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; @@ -25,6 +24,8 @@ import seedu.fitnus.user.User; import seedu.fitnus.validator.IntegerValidation; +import java.text.ParseException; + /** * The Parser class is responsible for parsing user commands and delegating * them to the appropriate classes for execution. @@ -225,6 +226,8 @@ public void handleCommand(String command) { System.out.println("Invalid date provided. Your date must be in the format of dd-MM-yyyy."); } catch (FutureDateException e) { System.out.println("Specified date has not passed. Please try another date."); + } catch (ParseException e) { + System.out.println("Specified date is invalid. Please try another date."); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); } @@ -638,13 +641,10 @@ public static void parseExerciseCalories(String data) throws IllegalArgumentExce * @return The parsed date string. * @throws InvalidDateException If the date format is invalid. */ - public static String parseListDate(String command) throws InvalidDateException, FutureDateException { + public static String parseListDate(String command) throws InvalidDateException, FutureDateException, ParseException { int indexOfDate = command.indexOf("d/") + 2; String date = command.substring(indexOfDate); - if (DateValidation.isValidDate(date) ) { - return date; - } - throw new InvalidDateException(); + return DateValidation.formatDateIfValid(date); } public static void parseNewMeal(String command) throws NegativeValueException { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 1a84d126d7..b97dd200ca 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -12,6 +12,7 @@ import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.InvalidDateException; +import java.text.ParseException; import java.util.ArrayList; /** @@ -190,7 +191,7 @@ public void handleListEverythingAll() { * @param command string inputted by the user, containing the date of which they would like to list * @throws InvalidDateException if the date inputted by user is invalid */ - public void handleListEverythingDate(String command) throws InvalidDateException, FutureDateException { + public void handleListEverythingDate(String command) throws InvalidDateException, FutureDateException, ParseException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); for (Meal m : myMealList.mealListAll) { diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 317a615f96..89d535831b 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -13,6 +13,8 @@ import seedu.fitnus.exercise.ExerciseIntensity; +import java.text.ParseException; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -157,7 +159,7 @@ public void parseExerciseCalories_validInputs_success() throws NegativeValueExce } @Test - public void parseListDate_validInputs_success() throws InvalidDateException, FutureDateException { + public void parseListDate_validInputs_success() throws InvalidDateException, FutureDateException, ParseException { String command = "listMeals d/12-02-2024"; String date = Parser.parseListDate(command); assertEquals("12-02-2024", date); From 3ede16eb8b9279839b150d32ff8807e1dd8828b6 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 19:11:12 +0800 Subject: [PATCH 194/274] Fix PED issue #103 --- src/main/java/seedu/fitnus/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 969e8f3a7d..4f0cebda97 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -221,7 +221,7 @@ public void handleCommand(String command) { System.out.println("Please specify a meal/drink/exercise that you would like to view the info of. " + "Type [help] to view the commands format."); } catch (NegativeValueException e) { - System.out.println("Your serving size/exercise duration must be at least 0!"); + System.out.println("Your serving size/exercise duration must be more than 0!"); } catch (InvalidDateException e) { System.out.println("Invalid date provided. Your date must be in the format of dd-MM-yyyy."); } catch (FutureDateException e) { From 022a6e5ae759591e69404f627b82e2f1bff36c46 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Wed, 10 Apr 2024 19:14:15 +0800 Subject: [PATCH 195/274] Fix checkstyle errors --- src/main/java/seedu/fitnus/date/Date.java | 1 - .../java/seedu/fitnus/date/DateValidation.java | 14 -------------- .../java/seedu/fitnus/exercise/ExerciseList.java | 3 ++- src/main/java/seedu/fitnus/meal/MealList.java | 3 ++- src/main/java/seedu/fitnus/parser/Parser.java | 2 +- src/main/java/seedu/fitnus/user/User.java | 3 ++- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/main/java/seedu/fitnus/date/Date.java b/src/main/java/seedu/fitnus/date/Date.java index fc7fc32d8c..05cc3c25e0 100644 --- a/src/main/java/seedu/fitnus/date/Date.java +++ b/src/main/java/seedu/fitnus/date/Date.java @@ -1,6 +1,5 @@ package seedu.fitnus.date; -import java.text.ParseException; import java.text.SimpleDateFormat; /** diff --git a/src/main/java/seedu/fitnus/date/DateValidation.java b/src/main/java/seedu/fitnus/date/DateValidation.java index f5aec6d64c..e9862c27d5 100644 --- a/src/main/java/seedu/fitnus/date/DateValidation.java +++ b/src/main/java/seedu/fitnus/date/DateValidation.java @@ -24,20 +24,6 @@ public static String formatDateIfValid(String date) throws FutureDateException, formattedDate = dateFormat.format(javaDate); return formattedDate; - -// -// -// String[] arrayOfDates = date.split("-"); -// int day = Integer.parseInt(arrayOfDates[0]); -// int month = Integer.parseInt(arrayOfDates[1]); -// int year = Integer.parseInt(arrayOfDates[2]); -// if (day < 1 || month < 1 || month > 12 || year < 0) { -// return false; -// } -// int[] dayInMonth = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -// if (day > dayInMonth[month - 1]) { -// return false; -// } } public static boolean checkDateHasPassed(java.util.Date inputDate) throws FutureDateException { diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java index c0d17f0513..dbb586fc14 100644 --- a/src/main/java/seedu/fitnus/exercise/ExerciseList.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -86,7 +86,8 @@ public void handleListExercisesAll() { * @param command string inputted by the user, containing the date of which they would like to list exercises of * @throws InvalidDateException if the date inputted by user is invalid */ - public void handleListExercisesDate(String command) throws InvalidDateException, FutureDateException, ParseException { + public void handleListExercisesDate(String command) throws InvalidDateException, FutureDateException, + ParseException { String date = Parser.parseListDate(command); ArrayList exercisesListDate = new ArrayList<>(); for (Exercise e : exerciseListAll) { diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index 0f6efac34f..e083d55a9c 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -99,7 +99,8 @@ public static void handleListMealsAll() { * @throws InvalidDateException if the date inputted by user is invalid */ //@@author edwardhumi - public static void handleListMealsDate(String command) throws InvalidDateException, FutureDateException, ParseException { + public static void handleListMealsDate(String command) throws InvalidDateException, FutureDateException, + ParseException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); for (Meal m : mealListAll) { diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 4f0cebda97..d0904e6eb9 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -641,7 +641,7 @@ public static void parseExerciseCalories(String data) throws IllegalArgumentExce * @return The parsed date string. * @throws InvalidDateException If the date format is invalid. */ - public static String parseListDate(String command) throws InvalidDateException, FutureDateException, ParseException { + public static String parseListDate(String command) throws FutureDateException, ParseException { int indexOfDate = command.indexOf("d/") + 2; String date = command.substring(indexOfDate); return DateValidation.formatDateIfValid(date); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index b97dd200ca..2d30e66d27 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -191,7 +191,8 @@ public void handleListEverythingAll() { * @param command string inputted by the user, containing the date of which they would like to list * @throws InvalidDateException if the date inputted by user is invalid */ - public void handleListEverythingDate(String command) throws InvalidDateException, FutureDateException, ParseException { + public void handleListEverythingDate(String command) throws InvalidDateException, FutureDateException, + ParseException { String date = Parser.parseListDate(command); ArrayList mealListDate = new ArrayList<>(); for (Meal m : myMealList.mealListAll) { From ec96d82344c34f87b8218e1e9c7a1868764a9cf8 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Fri, 12 Apr 2024 00:09:58 +0800 Subject: [PATCH 196/274] Fix PE-Bugs --- docs/UserGuide.md | 112 ++++++---------- src/main/java/seedu/fitnus/drink/Drink.java | 5 + .../java/seedu/fitnus/drink/DrinkList.java | 20 ++- .../exception/NegativeValueException.java | 2 +- .../exception/NonPositiveValueException.java | 8 ++ .../seedu/fitnus/exercise/ExerciseList.java | 15 ++- src/main/java/seedu/fitnus/meal/Meal.java | 5 + src/main/java/seedu/fitnus/meal/MealList.java | 30 ++++- src/main/java/seedu/fitnus/parser/Parser.java | 121 +++++++++++++----- .../seedu/fitnus/storage/StorageManager.java | 13 +- src/main/java/seedu/fitnus/user/User.java | 15 --- .../fitnus/validator/IntegerValidation.java | 7 +- .../java/seedu/fitnus/parser/ParserTest.java | 21 +-- 13 files changed, 223 insertions(+), 151 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/NonPositiveValueException.java diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 87d3ccd106..9954dd4f33 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -78,20 +78,24 @@ Shows a list of all possible command inputs. **Format**: `help` **Expected Output**: ~~~ -here's all the valid commands i recognise: -- Add a meal eaten: eat m/MEAL s/SERVING_SIZE -- Add a drink: drink d/DRINK s/VOLUME(ML) +Here's all the valid commands I recognise: + +Track a meal/drink/exercise: +- Track a meal eaten: eat m/MEAL s/SERVING_SIZE +- Track a drink: drink d/DRINK s/VOLUME(ML) - Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, LOW) -- Add a new meal to available meals: newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR -- Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT -- Add a new exercise to available exercises: newExercise CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM, -CALORIES_BURNT_LOW" + +View available meals/drinks/exercises: - View all meals that you can input: allMeals - View all drinks that you can input: allDrinks - View all exercises that you can input: allExercises + +Find information about a meal/drink/exercise: - Find the information about a certain meal: infoMeal MEAL - Find the information about a certain drink: infoDrink DRINK - Find the information about a certain exercise: infoExercise EXERCISE + +View nutrients and calories: - View daily calories consumed: calories - View daily carbohydrates consumed: carbs - View daily proteins consumed: protein @@ -100,6 +104,8 @@ CALORIES_BURNT_LOW" - View daily fiber consumed: fiber - View daily water consumption: viewWater - View daily calories burnt: caloriesBurnt + +List Commands: - List today's meal intake: listMeals - List today's drink intake: listDrinks - List today's exercises done: listExercises @@ -112,14 +118,26 @@ CALORIES_BURNT_LOW" - List drink intake for certain date: listDrinks d/dd-MM-yyyy - List exercises done for certain date: listExercises d/dd-MM-yyyy - List entire food intake and exercises for certain date: listEverything d/dd-MM-yyyy + +Edit Commands: - Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE - Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE - Edit total water intake after inserted: editWater s/TOTAL_WATER_INTAKE + +Delete Commands: - Delete certain meal entry: deleteMeal INDEX - Delete certain drink entry: deleteDrink INDEX - Delete certain exercise entry: deleteExercise INDEX + +Adding a meal/drink/exercises to available list: +- Add a new meal to available meals: newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR +- Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT +- Add a new exercise to available exercises: newExercise EXERCISE_NAME,CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW + +Miscellaneous: +- View daily calories and water intake recommendation: recommend - Clear all entries: clear -- Exit the app: exit +- Exit the app: exit ~~~ ### 1.1.2 Viewing all pre-defined meals: `allMeals` Shows a list of all pre-defined meals. These meals will have their nutritional content defined per serving size and can @@ -128,29 +146,11 @@ be inputted immediately. **Expected Output**: ~~~ Available meals: -- char kway teow -- ban mian -- tau huay -- nasi goreng -- soup kambeng -- nasi lemak -- pepper lunch -- char siew rice -- pork satay with satay sauce -- roti prata -- mee goreng -- chendol -- wanton mee -- oyster omlette - pizza -- ice kachang - chicken rice - fried rice - kaya toast -- mala - laksa -- hokkien prawn mee -- durian You may also input a meal that isn't here. ~~~ @@ -162,29 +162,10 @@ and can be inputted immediately. **Expected Output**: ~~~ Available drinks: -- milo dinosaur -- chrysanthemun juice -- honey lemon tea -- soursop juice -- lemon tea -- kopi c -- kalamansi juice -- kopi o -- milo -- plum juice -- water -- 100 plus -- milk coffee -- teh c bing -- kopi -- guava juice -- tiger beer -- teh tarik -- sugarcane juice -- teh - sprite +- milo - iced lemon tea -- bandung +- kopi You may also input a drink that isn't here. ~~~ @@ -196,21 +177,9 @@ high/medium/low intensity workout defined per minute and can be inputted immedia **Expected Output**: ~~~ Available exercises: -- soccer -- rugby -- yoga -- badminton -- hiking -- cycling -- tennis - running -- weightlifting - swimming -- basketball -- rowing -- boxing -- volleyball -- skipping +- cycling You may also input an exercise that isn't here. ~~~ @@ -227,7 +196,7 @@ Added 1 serving of chicken rice ### 1.2.2 Add a drink: `drink` Adds a drink to the list of drinks -**Format**: `drink d/DRINK s/SERVING_SIZE` +**Format**: `drink d/DRINK s/VOLUME(ML)` **Sample Input**: `drink d/Iced Lemon Tea s/200` **Expected Output**: ~~~ @@ -254,7 +223,7 @@ Tracked 30 minutes of swimming ### 1.2.4 Add new meal to available meals: `newMeal` Adds a new meal to available meals -**Format**: `newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR` +**Format**: `newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR` **Sample Input**: `newMeal mie,607,75,25,23,2,10` **Expected Output**: ~~~ @@ -263,8 +232,8 @@ Added mie to available meals ### 1.2.4 Add new meal to available meals: `newDrink` Adds a new drink to available drinks -**Format**: `newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT` -**Sample Input**: `newDrink coke,153,32,1,2,1` +**Format**: `newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT` +**Sample Input**: `newDrink coke,153,32,1,2,1` **Expected Output**: ~~~ Added coke to available drinks @@ -272,7 +241,7 @@ Added coke to available drinks ### 1.2.5 Add new exercise to available exercises: `newExercise` Adds a new exercise to available exercises -**Format**: `newExercise CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW` +**Format**: `newExercise EXERCISE_NAME,CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW` **Sample Input**: `newExercise badminton,20,10,5` **Expected Output**: ~~~ @@ -287,12 +256,13 @@ For the specified meal, display its nutritional content to the user **Expected Output**: ~~~ Meal: chicken rice (per serving)` -Calories: 607 -Carbs: 75 -Protein: 25 -Fat: 23 -Fiber: 2 -Sugar: 10 +Calories: 400 +Carbs: 50 +Protein: 30 +Fat: 20 +Fiber: 10 +Sugar: 5 +Sugar: 5 ~~~ ### 1.3.2 Find the information about a certain drink: `infoDrink` diff --git a/src/main/java/seedu/fitnus/drink/Drink.java b/src/main/java/seedu/fitnus/drink/Drink.java index 8a6965770c..019f25a56c 100644 --- a/src/main/java/seedu/fitnus/drink/Drink.java +++ b/src/main/java/seedu/fitnus/drink/Drink.java @@ -41,6 +41,11 @@ public Drink(String name, int volume, String currentDate) { nutrientDetails.put("kopi", new int[]{141, 26, 2, 3, 1}); } + /** + * Sets nutrients details for a certain drink based on values in hashmap + * + * @param name name of drink to set nutrients + */ private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); calories = nutrients[0] * drinkVolume / 100; diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index 1d97931e0d..3a2c34a02b 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -7,6 +7,7 @@ import seedu.fitnus.exception.InvalidDateException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.NonPositiveValueException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.parser.Parser; @@ -25,6 +26,13 @@ public DrinkList() { waterListAll = new ArrayList<>(); } + /** + * Adds a drink to available drinks + * + * @param command string inputted by the user, containing the drink they want to add to available drinks and + * its nutrient details + * @throws NegativeValueException if the nutrient detail is a negative value + */ public void handleAddNewDrinkNutrient(String command) throws NegativeValueException { Parser.parseNewDrink(command); String description = Parser.drinkNutrientDescription; @@ -44,10 +52,10 @@ public void handleAddNewDrinkNutrient(String command) throws NegativeValueExcept * @param command string inputted by the user, containing the drink they consumed and its serving size * @throws IncompleteDrinkException if the user did not comply with the required format * @throws UnregisteredDrinkException if the user has inputted a drink that was not pre-defined - * @throws NegativeValueException if the provided serving size is a negative value + * @throws NonPositiveValueException if the provided serving size is a negative value */ public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, - NegativeValueException { + NonPositiveValueException { Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; @@ -179,12 +187,12 @@ public void handleListDrinksDate(String command) throws InvalidDateException { * * @param command string inputted by the user, containing the index of the drink to edit and the new serving size * @throws InvalidListIndexException if the provided index is not a valid index in drinkList - * @throws NegativeValueException if the provided serving size is a negative value + * @throws NonPositiveValueException if the provided serving size is a negative value * @throws IncompleteEditException if the user did not comply with the required command format */ //@@author claribelho public void handleEditDrinkServingSize(String command) throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { + NonPositiveValueException, IncompleteEditException { Parser.parseEditDrink(command); if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { @@ -203,10 +211,10 @@ public void handleEditDrinkServingSize(String command) throws InvalidListIndexEx * Handles when the user would like to edit the total volume of the water they consumed today. * * @param command string inputted by the user, containing the new total volume of water - * @throws NegativeValueException if the provided serving size is a negative value + * @throws NonPositiveValueException if the provided serving size is a negative value * @throws IncompleteEditException if the user did not comply with the required command format */ - public void handleEditWaterIntake(String command) throws NegativeValueException, IncompleteEditException { + public void handleEditWaterIntake(String command) throws NonPositiveValueException, IncompleteEditException { Parser.parseEditWater(command); Date currentDate = new Date(); for (Water water: waterList) { diff --git a/src/main/java/seedu/fitnus/exception/NegativeValueException.java b/src/main/java/seedu/fitnus/exception/NegativeValueException.java index 94d3dc65b0..dae224e20d 100644 --- a/src/main/java/seedu/fitnus/exception/NegativeValueException.java +++ b/src/main/java/seedu/fitnus/exception/NegativeValueException.java @@ -1,7 +1,7 @@ package seedu.fitnus.exception; /** - * Exception class thrown when the integer is a non-positive value. + * Exception class thrown when the integer is negative value. * Class is inherited from Exception. */ public class NegativeValueException extends Exception { diff --git a/src/main/java/seedu/fitnus/exception/NonPositiveValueException.java b/src/main/java/seedu/fitnus/exception/NonPositiveValueException.java new file mode 100644 index 0000000000..e1fb79eff2 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/NonPositiveValueException.java @@ -0,0 +1,8 @@ +package seedu.fitnus.exception; + +/** + * Exception class thrown when the integer is a non-positive value. + * Class is inherited from Exception. + */ +public class NonPositiveValueException extends Exception { +} diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java index 0bec33ca23..ed8b428722 100644 --- a/src/main/java/seedu/fitnus/exercise/ExerciseList.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -5,7 +5,7 @@ import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.InvalidDateException; import seedu.fitnus.exception.InvalidListIndexException; -import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.NonPositiveValueException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.parser.Parser; @@ -20,7 +20,14 @@ public ExerciseList() { exerciseListAll = new ArrayList<>(); } - public void handleAddNewExerciseCalories(String command) throws NegativeValueException { + /** + * Adds a exercise to available exercises + * + * @param command string inputted by the user, containing the exercise they want to add to available exercises + * and details regarding the calories burnt + * @throws NonPositiveValueException if the calories burnt is a negative value + */ + public void handleAddNewExerciseCalories(String command) throws NonPositiveValueException { Parser.parseNewExercise(command); String description = Parser.exerciseCaloriesDescription; int high = Parser.exerciseCaloriesHigh; @@ -135,10 +142,10 @@ public void handleDeleteExercise(String command) throws InvalidListIndexExceptio * intensity. * @throws IncompleteExerciseException if the user did not comply with the required format * @throws UnregisteredExerciseException if the user has inputted an exercise that was not pre-defined - * @throws NegativeValueException if the provided exercise duration is a negative value + * @throws NonPositiveValueException if the provided exercise duration is a negative value */ public void handleExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, - NegativeValueException { + NonPositiveValueException { Parser.parseExercise(command); String exerciseType = Parser.exerciseDescription; int duration = Parser.exerciseDuration; diff --git a/src/main/java/seedu/fitnus/meal/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java index 8ba7f0eeba..3ff2c24183 100644 --- a/src/main/java/seedu/fitnus/meal/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -43,6 +43,11 @@ public Meal(String name, int servingSize, String currentDate) { nutrientDetails.put("laksa", new int[]{377, 71, 18, 2, 4, 10}); } + /** + * Sets nutrients details for a certain meal based on values in hashmap + * + * @param name name of meal to set nutrients + */ private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); calories = nutrients[0] * servingSize; diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index 913bfc1f4b..6d2fa83ee5 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -7,6 +7,7 @@ import seedu.fitnus.exception.InvalidDateException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.NonPositiveValueException; import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.parser.Parser; @@ -22,16 +23,37 @@ public MealList() { mealListAll = new ArrayList<>(); } + /** + * Adds a meal to available meals + * + * @param command string inputted by the user, containing the meal they want to add to available meals and + * its nutrient details + * @throws NegativeValueException if the nutrient detail is a negative value + */ + public void handleAddNewMealNutrient(String command) throws NegativeValueException { + Parser.parseNewMeal(command); + String description = Parser.mealNutrientDescription; + int calories = Parser.mealNutrientCalories; + int carbs = Parser.mealNutrientCarbs; + int protein = Parser.mealNutrientProtein; + int fat = Parser.mealNutrientFat; + int fiber = Parser.mealNutrientFiber; + int sugar = Parser.mealNutrientSugar; + Meal.nutrientDetails.put(description, new int[]{calories, carbs, protein, fat, fiber, sugar}); + + System.out.println("Added " + description + " to available meals"); + } + /** * Adds a meal to the user's current mealList, based on what the user has eaten and the serving size consumed. * * @param command string inputted by the user, containing the meal they ate and its serving size * @throws IncompleteMealException if the user did not comply with the required format * @throws UnregisteredMealException if the user has inputted a meal that was not pre-defined - * @throws NegativeValueException if the provided serving size is a negative value + * @throws NonPositiveValueException if the provided serving size is a negative value */ public static void handleMeal(String command) throws IncompleteMealException, UnregisteredMealException, - NegativeValueException { + NonPositiveValueException { Parser.parseMeal(command); String mealName = Parser.mealDescription; int servingSize = Parser.mealSize; @@ -123,11 +145,11 @@ public static void handleListMealsDate(String command) throws InvalidDateExcepti * * @param command string inputted by the user, containing the index of the meal to edit and the new serving size * @throws InvalidListIndexException if the provided index is not a valid index in mealList - * @throws NegativeValueException if the provided serving size is a negative value + * @throws NonPositiveValueException if the provided serving size is a negative value * @throws IncompleteEditException if the user did not comply with the required command format */ public static void handleEditMealServingSize(String command) throws InvalidListIndexException, - NegativeValueException, IncompleteEditException { + NonPositiveValueException, IncompleteEditException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 if (Parser.editMealIndex >= mealList.size() || Parser.editMealIndex < 0) { throw new InvalidListIndexException(); diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index d4cf02f3e0..13aa800e6a 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,11 +1,6 @@ package seedu.fitnus.parser; import seedu.fitnus.drink.Drink; -import seedu.fitnus.meal.Meal; -import seedu.fitnus.exercise.Exercise; -import seedu.fitnus.exercise.ExerciseIntensity; -import seedu.fitnus.date.Date; - import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; @@ -13,12 +8,17 @@ import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidCommandException; +import seedu.fitnus.exception.InvalidDateException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.NonPositiveValueException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.meal.Meal; +import seedu.fitnus.exercise.Exercise; +import seedu.fitnus.exercise.ExerciseIntensity; +import seedu.fitnus.date.Date; import seedu.fitnus.user.User; import seedu.fitnus.validator.IntegerValidation; @@ -106,7 +106,7 @@ public void handleCommand(String command) { } else if (command.startsWith("exercise")) { user.myExerciseList.handleExercise(command); } else if (command.startsWith("newMeal")) { - user.handleAddNewMealNutrient(command); + user.myMealList.handleAddNewMealNutrient(command); } else if (command.startsWith("newDrink")) { user.myDrinkList.handleAddNewDrinkNutrient(command); } else if (command.startsWith("newExercise")) { @@ -185,7 +185,7 @@ public void handleCommand(String command) { } catch (InvalidCommandException e) { System.out.println("Invalid command, type [help] to view all commands."); } catch (IncompleteDrinkException e) { - System.out.println("Incomplete/Incorrect command, the format MUST be [drink d/DRINK s/SERVING_SIZE]."); + System.out.println("Incomplete/Incorrect command, the format MUST be [drink d/DRINK s/VOLUME(ML)]."); } catch (IncompleteMealException e) { System.out.println("Incomplete/Incorrect command, the format MUST be [eat m/MEAL s/SERVING_SIZE]."); } catch (IncompleteExerciseException e) { @@ -217,8 +217,10 @@ public void handleCommand(String command) { } catch (IncompleteInfoException e) { System.out.println("Please specify a meal/drink/exercise that you would like to view the info of. " + "Type [help] to view the commands format."); - } catch (NegativeValueException e) { - System.out.println("Your serving size/exercise duration must be at least 0!"); + } catch (NonPositiveValueException e) { + System.out.println("Your serving size/exercise duration must be greater than 0!"); + } catch (NegativeValueException e) { + System.out.println("Value cannot be negative!"); } catch (InvalidDateException e) { System.out.println("Invalid date provided. Your date must be in the format of dd-MM-yyyy."); } catch (IllegalArgumentException e) { @@ -231,17 +233,25 @@ public void handleCommand(String command) { * Displays a list of valid commands and their formats. */ public static void handleHelp() { - System.out.println("here's all the valid commands i recognise: "); - System.out.println("- Add a meal eaten: eat m/MEAL s/SERVING_SIZE"); - System.out.println("- Add a drink: drink d/DRINK s/VOLUME(ML)"); + System.out.println("Here's all the valid commands I recognise: "); + System.out.println(); + System.out.println("Track a meal/drink/exercise: "); + System.out.println("- Track a meal eaten: eat m/MEAL s/SERVING_SIZE"); + System.out.println("- Track a drink: drink d/DRINK s/VOLUME(ML)"); System.out.println("- Track an exercise: exercise e/EXERCISE d/DURATION(MINUTES) " + "i/INTENSITY(HIGH, MEDIUM, LOW)"); + System.out.println(); + System.out.println("View available meals/drinks/exercises: "); System.out.println("- View all meals that you can input: allMeals"); System.out.println("- View all drinks that you can input: allDrinks"); System.out.println("- View all exercises that you can input: allExercises"); + System.out.println(); + System.out.println("Find information about a meal/drink/exercise: "); System.out.println("- Find the information about a certain meal: infoMeal MEAL"); System.out.println("- Find the information about a certain drink: infoDrink DRINK"); System.out.println("- Find the information about a certain exercise: infoExercise EXERCISE"); + System.out.println(); + System.out.println("View nutrients and calories: "); System.out.println("- View daily calories consumed: calories"); System.out.println("- View daily carbohydrates consumed: carbs"); System.out.println("- View daily proteins consumed: protein"); @@ -250,7 +260,8 @@ public static void handleHelp() { System.out.println("- View daily fiber consumed: fiber"); System.out.println("- View daily water consumption: viewWater"); System.out.println("- View daily calories burnt: caloriesBurnt"); - System.out.println("- View daily calories and water intake recommendation: recommend"); + System.out.println(); + System.out.println("List Commands: "); System.out.println("- List today's meal intake: listMeals"); System.out.println("- List today's drink intake: listDrinks"); System.out.println("- List today's exercises done: listExercises"); @@ -263,18 +274,27 @@ public static void handleHelp() { System.out.println("- List drink intake for certain date: listDrinks d/dd-MM-yyyy"); System.out.println("- List exercises done for certain date: listExercises d/dd-MM-yyyy"); System.out.println("- List entire food intake and exercises for certain date: listEverything d/dd-MM-yyyy"); + System.out.println(); + System.out.println("Edit Commands: "); System.out.println("- Edit an existing meal after inserted: editMeal INDEX s/NEW_SERVING_SIZE"); System.out.println("- Edit an existing drink after inserted: editDrink INDEX s/NEW_SERVING_SIZE"); System.out.println("- Edit total water intake after inserted: editWater s/TOTAL_WATER_INTAKE"); + System.out.println(); + System.out.println("Delete Commands: "); System.out.println("- Delete certain meal entry: deleteMeal INDEX"); System.out.println("- Delete certain drink entry: deleteDrink INDEX"); System.out.println("- Delete certain exercise entry: deleteExercise INDEX"); + System.out.println(); + System.out.println("Adding a meal/drink/exercises to available list: "); System.out.println("- Add a new meal to available meals: newMeal MEAL_NAME,CALORIES," + "CARBS,PROTEIN,FAT,FIBER,SUGAR"); System.out.println("- Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES," + "CARBS,SUGAR,PROTEIN,FAT"); System.out.println("- Add a new exercise to available exercises: newExercise EXERCISE_NAME," + "CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW"); + System.out.println(); + System.out.println("Miscellaneous: "); + System.out.println("- View daily calories and water intake recommendation: recommend"); System.out.println("- Clear all entries: clear"); System.out.println("- Exit the app: exit "); } @@ -285,10 +305,10 @@ public static void handleHelp() { * @param command The command entered by the user. * @throws IncompleteMealException If the meal command is incomplete. * @throws UnregisteredMealException If the meal is not registered in the database. - * @throws NegativeValueException If a negative value is encountered. + * @throws NonPositiveValueException If a negative value is encountered. */ public static void parseMeal(String command) throws IncompleteMealException, UnregisteredMealException, - NegativeValueException { + NonPositiveValueException { if (!command.contains("m/") || !command.contains("s/")) { throw new IncompleteMealException(); } @@ -316,10 +336,10 @@ public static void parseMeal(String command) throws IncompleteMealException, Unr * @param command The command entered by the user. * @throws IncompleteDrinkException If the drink command is incomplete. * @throws UnregisteredDrinkException If the drink is not registered in the database. - * @throws NegativeValueException If a negative value is encountered. + * @throws NonPositiveValueException If a negative value is encountered. */ public static void parseDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, - NegativeValueException { + NonPositiveValueException { if (!command.contains("d/") || !command.contains("s/")) { throw new IncompleteDrinkException(); } @@ -406,10 +426,10 @@ public static String parseInfoDrink(String command) throws UnregisteredDrinkExce * Parses the command for editing a meal. * * @param command The command entered by the user. - * @throws NegativeValueException If a negative value is encountered. + * @throws NonPositiveValueException If a negative value is encountered. * @throws IncompleteEditException If the command is incomplete. */ - public static void parseEditMeal(String command) throws NegativeValueException, IncompleteEditException { + public static void parseEditMeal(String command) throws NonPositiveValueException, IncompleteEditException { int mealSizePosition = command.indexOf("s/"); if (mealSizePosition <= 9) { throw new IncompleteEditException(); @@ -424,10 +444,10 @@ public static void parseEditMeal(String command) throws NegativeValueException, * Parses the command for editing a drink. * * @param command The command entered by the user. - * @throws NegativeValueException If a negative value is encountered. + * @throws NonPositiveValueException If a negative value is encountered. * @throws IncompleteEditException If the command is incomplete. */ - public static void parseEditDrink(String command) throws NegativeValueException, IncompleteEditException { + public static void parseEditDrink(String command) throws NonPositiveValueException, IncompleteEditException { int drinkSizePosition = command.indexOf("s/"); if (drinkSizePosition <= 10) { throw new IncompleteEditException(); @@ -442,10 +462,10 @@ public static void parseEditDrink(String command) throws NegativeValueException, * Parses the command for editing water intake. * * @param command The command entered by the user. - * @throws NegativeValueException If a negative value is encountered. + * @throws NonPositiveValueException If a negative value is encountered. * @throws IncompleteEditException If the command is incomplete. */ - public static void parseEditWater(String command) throws NegativeValueException, IncompleteEditException { + public static void parseEditWater(String command) throws NonPositiveValueException, IncompleteEditException { int waterSizePosition = command.indexOf("s/") + 2; if (waterSizePosition <= 1) { //-1 + 2 throw new IncompleteEditException(); @@ -500,10 +520,10 @@ public static void parseExerciseStorage(String data) { * @param command The command entered by the user. * @throws IncompleteExerciseException If the exercise command is incomplete. * @throws UnregisteredExerciseException If the exercise is not registered in the database. - * @throws NegativeValueException If a negative value is encountered. + * @throws NonPositiveValueException If a negative value is encountered. */ public static void parseExercise(String command) throws IncompleteExerciseException, UnregisteredExerciseException, - NegativeValueException { + NonPositiveValueException { if (!command.contains("e/") || !command.contains("d/") || !command.contains("i/")) { throw new IncompleteExerciseException(); } @@ -538,10 +558,14 @@ public static void parseExercise(String command) throws IncompleteExerciseExcept * * @param data The nutrient data string to be parsed. */ - public static void parseMealNutrient(String data) throws IllegalArgumentException, NegativeValueException{ + public static void parseMealNutrient(String data) throws IllegalArgumentException, NegativeValueException { String delimiter = ","; String[] arrayOfMealNutrient = data.split(delimiter); + for (int i = 0; i < arrayOfMealNutrient.length; i++) { + arrayOfMealNutrient[i] = arrayOfMealNutrient[i].trim(); + } + if (arrayOfMealNutrient.length != 7) { throw new IllegalArgumentException("Invalid number of arguments provided. Expected 7, got " + arrayOfMealNutrient.length); @@ -576,6 +600,10 @@ public static void parseDrinkNutrient(String data) throws IllegalArgumentExcept String delimiter = ","; String[] arrayOfDrinkNutrient = data.split(delimiter); + for (int i = 0; i < arrayOfDrinkNutrient.length; i++) { + arrayOfDrinkNutrient[i] = arrayOfDrinkNutrient[i].trim(); + } + if (arrayOfDrinkNutrient.length != 6) { throw new IllegalArgumentException("Invalid number of arguments provided. Expected 6, got " + arrayOfDrinkNutrient.length); @@ -604,10 +632,14 @@ public static void parseDrinkNutrient(String data) throws IllegalArgumentExcept * * @param data The calorie data string to be parsed. */ - public static void parseExerciseCalories(String data) throws IllegalArgumentException, NegativeValueException { + public static void parseExerciseCalories(String data) throws IllegalArgumentException, NonPositiveValueException { String delimiter = ","; String[] arrayOfExerciseCalories = data.split(delimiter); + for (int i = 0; i < arrayOfExerciseCalories.length; i++) { + arrayOfExerciseCalories[i] = arrayOfExerciseCalories[i].trim(); + } + if (arrayOfExerciseCalories.length != 4) { throw new IllegalArgumentException("Invalid number of arguments provided. Expected 4, got " + arrayOfExerciseCalories.length); @@ -619,9 +651,14 @@ public static void parseExerciseCalories(String data) throws IllegalArgumentExce exerciseCaloriesMedium = Integer.parseInt(arrayOfExerciseCalories[2]); exerciseCaloriesLow = Integer.parseInt(arrayOfExerciseCalories[3]); - IntegerValidation.checkIntegerGreaterOrEqualThanZero(exerciseCaloriesHigh); - IntegerValidation.checkIntegerGreaterOrEqualThanZero(exerciseCaloriesMedium); - IntegerValidation.checkIntegerGreaterOrEqualThanZero(exerciseCaloriesLow); + if (exerciseCaloriesHigh <= exerciseCaloriesMedium || exerciseCaloriesMedium <= exerciseCaloriesLow) { + throw new IllegalArgumentException("HIGH intensity must be greater than MEDIUM intensity and MEDIUM " + + "intensity must be larger than LOW intensity."); + } + + IntegerValidation.checkIntegerGreaterThanZero(exerciseCaloriesHigh); + IntegerValidation.checkIntegerGreaterThanZero(exerciseCaloriesMedium); + IntegerValidation.checkIntegerGreaterThanZero(exerciseCaloriesLow); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid numeric format, please input an integer"); } @@ -643,17 +680,37 @@ public static String parseListDate(String command) throws InvalidDateException { throw new InvalidDateException(); } + /** + * Parses the newMeal command from a command string. + * + * @param command The command entered by the user containing the new meal they want to add and its nutrient details + * @throws NegativeValueException If a negative value is encountered. + */ public static void parseNewMeal(String command) throws NegativeValueException { String mealNutrients = command.substring(8).trim(); parseMealNutrient(mealNutrients); } + + /** + * Parses the newDrink command from a command string. + * + * @param command The command entered by the user containing the new drink they want to add and its nutrient details + * @throws NegativeValueException If a negative value is encountered. + */ public static void parseNewDrink(String command) throws NegativeValueException { String drinkNutrients = command.substring(9).trim(); parseDrinkNutrient(drinkNutrients); } - public static void parseNewExercise(String command) throws NegativeValueException{ + /** + * Parses the newMeal command from a command string. + * + * @param command The command entered by the user containing the new exercise they want to add and its calories + * burnt details + * @throws NonPositiveValueException If a negative value is encountered. + */ + public static void parseNewExercise(String command) throws NonPositiveValueException { String exerciseDetails = command.substring(12).trim(); parseExerciseCalories(exerciseDetails); } diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index 95e67a3755..6deff2c1a0 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -1,13 +1,14 @@ package seedu.fitnus.storage; import seedu.fitnus.date.Date; +import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.meal.Meal; import seedu.fitnus.drink.Drink; import seedu.fitnus.exercise.ExerciseIntensity; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.drink.Water; import seedu.fitnus.user.User; -import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.NonPositiveValueException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.parser.Parser; @@ -26,8 +27,10 @@ public StorageManager(Storage mealStorage, Storage drinkStorage, Storage exercis loadMeal(mealStorage); loadDrink(drinkStorage); loadExercise(exerciseStorage); + } catch (NonPositiveValueException e) { + System.out.println("Calories burnt must be greater than 0"); } catch (NegativeValueException e) { - System.out.println("Nutrient details must be greater than 0"); + System.out.println("Nutrient details cannot be negative"); } } @@ -145,7 +148,7 @@ public void loadExercise(Storage exerciseStorage) { * * @param mealNutrientStorage contains filePath and folderPath of where the pre-defined meals are stored. */ - public void loadMealNutrient(Storage mealNutrientStorage) throws NegativeValueException{ + public void loadMealNutrient(Storage mealNutrientStorage) throws NegativeValueException { try { ArrayList mealNutrientList = mealNutrientStorage.readFile(); if (!mealNutrientList.isEmpty()) { @@ -171,7 +174,7 @@ public void loadMealNutrient(Storage mealNutrientStorage) throws NegativeValueEx * * @param drinkNutrientStorage contains filePath and folderPath of where the pre-defined drinks are stored. */ - public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValueException{ + public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValueException { try { ArrayList drinkNutrientList = drinkNutrientStorage.readFile(); if (!drinkNutrientList.isEmpty()) { @@ -197,7 +200,7 @@ public void loadDrinkNutrient(Storage drinkNutrientStorage) throws NegativeValue * * @param exerciseCaloriesStorage contains filePath and folderPath of where the pre-defined exercises are stored. */ - public void loadExerciseCalories(Storage exerciseCaloriesStorage) throws NegativeValueException { + public void loadExerciseCalories(Storage exerciseCaloriesStorage) throws NonPositiveValueException { try { ArrayList exerciseCaloriesList = exerciseCaloriesStorage.readFile(); if (!exerciseCaloriesList.isEmpty()) { diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index ddb2df9d99..96e0787d36 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -8,7 +8,6 @@ import seedu.fitnus.exercise.ExerciseList; import seedu.fitnus.parser.Parser; import seedu.fitnus.drink.Water; -import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.InvalidDateException; import java.util.ArrayList; @@ -29,20 +28,6 @@ public User() { myExerciseList = new ExerciseList(); } - public void handleAddNewMealNutrient(String command) throws NegativeValueException{ - Parser.parseNewMeal(command); - String description = Parser.mealNutrientDescription; - int calories = Parser.mealNutrientCalories; - int carbs = Parser.mealNutrientCarbs; - int protein = Parser.mealNutrientProtein; - int fat = Parser.mealNutrientFat; - int fiber = Parser.mealNutrientFiber; - int sugar = Parser.mealNutrientSugar; - Meal.nutrientDetails.put(description, new int[]{calories, carbs, protein, fat, fiber, sugar}); - - System.out.println("Added " + description + " to available meals"); - } - /** * Prints the user's total calorie intake of the day. * The method sums up the calories from meals and drinks, and subtracts calories burnt from exercise. diff --git a/src/main/java/seedu/fitnus/validator/IntegerValidation.java b/src/main/java/seedu/fitnus/validator/IntegerValidation.java index e20eaacd9c..e7eee85619 100644 --- a/src/main/java/seedu/fitnus/validator/IntegerValidation.java +++ b/src/main/java/seedu/fitnus/validator/IntegerValidation.java @@ -1,6 +1,7 @@ package seedu.fitnus.validator; import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.NonPositiveValueException; /** * Validates whether an integer value complies with the condition stated. @@ -11,11 +12,11 @@ public class IntegerValidation { * Validates whether the integer value is a positive integer. * * @param value integer value to check - * @throws NegativeValueException if the value is less than or equals to zero + * @throws NonPositiveValueException if the value is less than or equals to zero */ - public static void checkIntegerGreaterThanZero (int value) throws NegativeValueException { + public static void checkIntegerGreaterThanZero (int value) throws NonPositiveValueException { if (value <= 0) { - throw new NegativeValueException(); + throw new NonPositiveValueException(); } } diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 55c7c96762..3b87c00c8b 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -2,13 +2,14 @@ import org.junit.jupiter.api.Test; import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteInfoException; -import seedu.fitnus.exception.UnregisteredDrinkException; +import seedu.fitnus.exception.InvalidDateException; import seedu.fitnus.exception.NegativeValueException; -import seedu.fitnus.exception.UnregisteredMealException; +import seedu.fitnus.exception.NonPositiveValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.exception.IncompleteExerciseException; -import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exercise.ExerciseIntensity; @@ -48,7 +49,7 @@ public void parseInfoDrink_unregisteredDrink_exceptionThrown() throws Incomplete } @Test - public void parseEditMeal_validInputs_success() throws IncompleteEditException, NegativeValueException { + public void parseEditMeal_validInputs_success() throws IncompleteEditException, NonPositiveValueException { String command = "editMeal 3 s/120"; Parser.parseEditMeal(command); // Meal list starts from 1, however the array index starts from 0, hence the n - 1 @@ -57,7 +58,7 @@ public void parseEditMeal_validInputs_success() throws IncompleteEditException, } @Test - public void parseEditDrink_validInputs_success() throws IncompleteEditException, NegativeValueException { + public void parseEditDrink_validInputs_success() throws IncompleteEditException, NonPositiveValueException { String command = "editDrink 1 s/500"; Parser.parseEditDrink(command); // Drink list starts from 1, however the array index starts from 0, hence the n - 1 @@ -66,7 +67,7 @@ public void parseEditDrink_validInputs_success() throws IncompleteEditException, } @Test - public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NegativeValueException { + public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NonPositiveValueException { String command = "editDrink s/100"; try { Parser.parseEditDrink(command); @@ -76,7 +77,7 @@ public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NegativeVal } @Test - public void parseEditWater_validInputs_success() throws IncompleteEditException, NegativeValueException { + public void parseEditWater_validInputs_success() throws IncompleteEditException, NonPositiveValueException { String command = "editWater s/500"; Parser.parseEditWater(command); assertEquals(500, Parser.editWaterSize); @@ -111,7 +112,7 @@ public void parseExerciseStorage_validInputs_success() { } @Test - public void parseExercise_validInputs_success() throws IncompleteExerciseException, NegativeValueException, + public void parseExercise_validInputs_success() throws IncompleteExerciseException, NonPositiveValueException, UnregisteredExerciseException { String command = "exercise e/cycling d/100 i/LOW"; Parser.parseExercise(command); @@ -146,7 +147,7 @@ public void parseDrinkNutrient_validInputs_success() throws NegativeValueExcepti } @Test - public void parseExerciseCalories_validInputs_success() throws NegativeValueException { + public void parseExerciseCalories_validInputs_success() throws NonPositiveValueException { String data = "Running,14,10,7"; Parser.parseExerciseCalories(data); assertEquals("running", Parser.exerciseCaloriesDescription); From 625285d4dea7163b32465af3120a7125c675940b Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 18:17:05 +0800 Subject: [PATCH 197/274] Update UserTest after reorganisation of classes --- .../seedu/fitnus/drink/DrinkListTest.java | 2 + .../fitnus/exercise/ExerciseListTest.java | 2 + .../java/seedu/fitnus/meal/MealListTest.java | 2 + src/test/java/seedu/fitnus/user/UserTest.java | 545 +++++------------- 4 files changed, 165 insertions(+), 386 deletions(-) create mode 100644 src/test/java/seedu/fitnus/drink/DrinkListTest.java create mode 100644 src/test/java/seedu/fitnus/exercise/ExerciseListTest.java create mode 100644 src/test/java/seedu/fitnus/meal/MealListTest.java diff --git a/src/test/java/seedu/fitnus/drink/DrinkListTest.java b/src/test/java/seedu/fitnus/drink/DrinkListTest.java new file mode 100644 index 0000000000..c44da56e50 --- /dev/null +++ b/src/test/java/seedu/fitnus/drink/DrinkListTest.java @@ -0,0 +1,2 @@ +package seedu.fitnus.drink;public class DrinkListTest { +} diff --git a/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java new file mode 100644 index 0000000000..a444a59ca5 --- /dev/null +++ b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java @@ -0,0 +1,2 @@ +package seedu.fitnus.exercise;public class ExerciseListTest { +} diff --git a/src/test/java/seedu/fitnus/meal/MealListTest.java b/src/test/java/seedu/fitnus/meal/MealListTest.java new file mode 100644 index 0000000000..0fd91a598b --- /dev/null +++ b/src/test/java/seedu/fitnus/meal/MealListTest.java @@ -0,0 +1,2 @@ +package seedu.fitnus.meal;public class MealListTest { +} diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 8afde5eb32..02284684a3 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -1,386 +1,159 @@ -//package seedu.fitnus.user; -// -//import seedu.fitnus.Date; -//import seedu.fitnus.Drink; -//import seedu.fitnus.Exercise; -//import seedu.fitnus.ExerciseIntensity; -//import seedu.fitnus.meal.Meal; -// -//import seedu.fitnus.Water; -// -//import seedu.fitnus.exception.IncompleteDeleteException; -//import seedu.fitnus.exception.IncompleteDrinkException; -//import seedu.fitnus.exception.IncompleteEditException; -//import seedu.fitnus.exception.IncompleteExerciseException; -//import seedu.fitnus.exception.IncompleteMealException; -//import seedu.fitnus.exception.InvalidListIndexException; -//import seedu.fitnus.exception.NegativeValueException; -//import seedu.fitnus.exception.UnregisteredDrinkException; -//import seedu.fitnus.exception.UnregisteredExerciseException; -//import seedu.fitnus.exception.UnregisteredMealException; -//import seedu.fitnus.storage.Storage; -// -//import java.io.ByteArrayOutputStream; -//import java.io.PrintStream; -//import java.util.ArrayList; -// -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -//import seedu.fitnus.storage.StorageManager; -////import static org.junit.jupiter.api.Assertions.fail; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.junit.jupiter.api.Assertions.assertFalse; -//import static org.junit.jupiter.api.Assertions.assertThrows; -// -//public class UserTest { -// User testUser; -// String todayDate; -// StorageManager testStorageManager; -// ArrayList testMealList; -// ArrayList testDrinkList; -// ArrayList testWaterList; -// ArrayList testExerciseList; -// private Storage testMealStorage; -// private Storage testDrinkStorage; -// private Storage testExerciseStorage; -// private Storage mealNutrientStorage = new Storage("./db", "./db/Meal_db.csv"); -// private Storage drinkNutrientStorage = new Storage("./db", "./db/Drink_db.csv"); -// private Storage exerciseCaloriesStorage = new Storage("./db", "./db/Exercise_db.csv"); -// -// private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); -// -// @BeforeEach -// public void setUp() throws UnregisteredExerciseException { -// testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); -// testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); -// testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); -// -// testUser = new User(); -// testStorageManager = new StorageManager(testMealStorage, testDrinkStorage, testExerciseStorage, -// mealNutrientStorage, drinkNutrientStorage, exerciseCaloriesStorage); -// -// testMealList = testUser.mealList; -// testDrinkList = testUser.drinkList; -// testExerciseList = testUser.exerciseList; -// testWaterList = testUser.waterList; -// -// Date currentDate = new Date(); -// todayDate = currentDate.getDate(); -// -// testMealList.add(new Meal("kaya toast", 4, todayDate)); -// testMealList.add(new Meal("laksa", 10, todayDate)); -// testDrinkList.add(new Drink("kopi", 100, todayDate)); -// testWaterList.add(new Water( 100, todayDate)); -// testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH, "30-01-2024")); -// -// System.setOut(new PrintStream(outputStream)); -// } -// -// @Test -// public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, -// NegativeValueException { -// String command = "eat m/kaya toast s/3"; -// testUser.handleMeal(command); -// -// assertFalse(testMealList.isEmpty()); -// -// assertEquals("kaya toast", testMealList.get(2).getName()); -// assertEquals(3, testMealList.get(2).getServingSize()); -// } -// -// @Test -// public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, -// UnregisteredDrinkException, NegativeValueException { -// String command = "drink d/kopi s/500"; -// testUser.handleDrink(command); -// -// assertEquals("kopi", testDrinkList.get(1).getName()); -// assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); -// } -// -// -// @Test -// public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, -// UnregisteredExerciseException, NegativeValueException { -// String command = "exercise e/running d/30 i/HIGH"; -// testUser.handleExercise(command); -// -// assertEquals("running", testExerciseList.get(1).getName()); -// assertEquals(30, testExerciseList.get(1).getDuration()); -// assertEquals(ExerciseIntensity.HIGH, testExerciseList.get(1).getIntensity()); -// } -// -// @Test -// public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { -// testUser.handleViewCalories(); -// String expectedOutput = "Total Calories: 5507"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { -// testUser.handleViewCarbohydrates(); -// String expectedOutput = "Total Carbohydrates: 912 grams"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewProteins(); -// String expectedOutput = "Total Proteins: 215 grams"; -// String actualOutput = outputStream.toString().trim(); -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { -// testWaterList.add(new Water (500, todayDate)); -// -// testUser.handleViewWaterIntake(); -// String expectedOutput = "Total water intake today: 600 ml"; -// String actualOutput = outputStream.toString().trim(); -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewFiber(); -// String expectedOutput = "Total Fiber: 80 grams"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleViewFat_correctFatCalculation_viewFatAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewFat(); -// String expectedOutput = "Total Fat: 129 grams"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { -// System.setOut(new PrintStream(outputStream)); -// -// testUser.handleViewSugar(); -// String expectedOutput = "Total Sugar: 106 grams"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { -// testUser.handleCaloriesBurnt(); -// String expectedOutput = "Total calories burnt: 240"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(actualOutput, expectedOutput); -// } -// -// @Test -// public void handleListMeals_emptyList_printListAccurate() { -// testMealList.clear(); -// testUser.handleListMeals(); -// -// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + -// " >> nothing so far :o"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListMeals_validList_printListAccurate() { -// testUser.handleListMeals(); -// -// String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + -// "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + -// "2. laksa (serving size: 10) | date: " + todayDate ; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListDrinks_emptyList_printListAccurate() { -// testDrinkList.clear(); -// testWaterList.clear(); -// testUser.handleListDrinks(); -// -// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + -// " >> nothing so far :o"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// -// @Test -// public void handleListDrinks_validList_printListAccurate() { -// testUser.handleListDrinks(); -// -// String expectedOutput = "here's what you have drank today" + System.lineSeparator() + -// "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + -// "Total water intake today: 100 ml"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListExercise_emptyList_printListAccurate() { -// testExerciseList.clear(); -// testUser.handleListExercises(); -// -// String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + -// " >> nothing so far :o"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// -// @Test -// public void handleListExercise_validList_printListAccurate() { -// testUser.handleListExercises(); -// -// String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + -// "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListEverything_allEmptyLists_printListAccurate() { -// testMealList.clear(); -// testDrinkList.clear(); -// testExerciseList.clear(); -// testUser.handleListEverything(); -// -// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + -// " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + -// "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + -// "here's the exercises you've done today" + System.lineSeparator() + -// " >> nothing so far :o"; -// String actualOutput = outputStream.toString().trim(); -// -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleListEverything_validList_printListAccurate() { -// testUser.handleListEverything(); -// -// String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + -// "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + -// "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + -// "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + -// "Total water intake today: 100 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + -// "here's the exercises you've done today" + System.lineSeparator() + -// "1. swimming | duration: 20 | intensity: HIGH | date: 30-01-2024"; -// String actualOutput = outputStream.toString().trim(); -// assertEquals(expectedOutput, actualOutput); -// } -// -// @Test -// public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { -// Exception exception = assertThrows(InvalidListIndexException.class, () -> { -// String command = "editMeal 5 s/10"; -// testUser.handleEditMealServingSize(command); -// }); -// } -// -// @Test -// public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, -// NegativeValueException, IncompleteEditException { -// String command = "editMeal 2 s/100000000"; -// testUser.handleEditMealServingSize(command); -// -// int mealIndex = 2 - 1; -// assertEquals("laksa", testMealList.get(mealIndex).getName()); -// assertEquals(100000000, testMealList.get(mealIndex).getServingSize()); -// } -// -// @Test -// public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, -// NegativeValueException, IncompleteEditException { -// String command = "editDrink 1 s/100000000"; -// testUser.handleEditDrinkServingSize(command); -// -// int drinkIndex = 0; -// assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); -// assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); -// } -// -// @Test -// public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, -// IncompleteDeleteException { -// Exception exception = assertThrows(IncompleteDeleteException.class, () -> { -// String command = "deleteMeal "; -// testUser.handleDeleteMeal(command); -// }); -// } -// -// @Test -// public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, -// IncompleteDeleteException { -// Exception exception = assertThrows(NumberFormatException.class, () -> { -// String command = "deleteMeal "; -// testUser.handleDeleteMeal(command); -// }); -// } -// -// @Test -// public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, -// IncompleteDeleteException { -// String command = "deleteMeal 1"; -// testUser.handleDeleteMeal(command); -// assertEquals(1, testMealList.size()); -// assertEquals("laksa", testMealList.get(0).getName()); -// } -// -// @Test -// public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { -// Exception exception = assertThrows(InvalidListIndexException.class, () -> { -// String command = "deleteDrink 5"; -// testUser.handleDeleteDrink(command); -// }); -// } -// -// @Test -// public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, -// IncompleteDeleteException { -// String command = "deleteDrink 1"; -// testUser.handleDeleteDrink(command); -// assertEquals(0, testDrinkList.size()); -// } -// -// @Test -// public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, -// IncompleteDeleteException { -// String command = "deleteExercise 1"; -// testUser.handleDeleteExercise(command); -// assertEquals(0, testExerciseList.size()); -// } -// -// @Test -// public void handleClear_validCommand_clearListsSuccessful() { -// testUser.handleClear(); -// assertEquals(0, testMealList.size()); -// assertEquals(0, testDrinkList.size()); -// } -//} +package seedu.fitnus.user; + +import seedu.fitnus.date.Date; +import seedu.fitnus.drink.Drink; +import seedu.fitnus.exercise.Exercise; +import seedu.fitnus.exercise.ExerciseIntensity; +import seedu.fitnus.meal.Meal; + +import seedu.fitnus.exception.UnregisteredExerciseException; +import seedu.fitnus.storage.Storage; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.fitnus.storage.StorageManager; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UserTest { + User testUser; + String todayDate; + StorageManager testStorageManager; + ArrayList testMealList; + ArrayList testDrinkList; + ArrayList testExerciseList; + private Storage testMealStorage; + private Storage testDrinkStorage; + private Storage testExerciseStorage; + + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + @BeforeEach + public void setUp() throws UnregisteredExerciseException { + testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); + testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); + testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); + + testUser = new User(); + + testMealList = testUser.myMealList.mealList; + testDrinkList = testUser.myDrinkList.drinkList; + testExerciseList = testUser.myExerciseList.exerciseList; + + Date currentDate = new Date(); + todayDate = currentDate.getDate(); + + testMealList.add(new Meal("kaya toast", 4, todayDate)); + testMealList.add(new Meal("laksa", 10, todayDate)); + testDrinkList.add(new Drink("kopi", 100, todayDate)); + testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH, todayDate)); + + System.setOut(new PrintStream(outputStream)); + } + + @Test + public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { + testUser.handleViewCalories(); + String expectedOutput = "Total Calories: 5507"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { + testUser.handleViewCarbohydrates(); + String expectedOutput = "Total Carbohydrates: 912 grams"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewProteins(); + String expectedOutput = "Total Proteins: 215 grams"; + String actualOutput = outputStream.toString().trim(); + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFiber(); + String expectedOutput = "Total Fiber: 80 grams"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewFat_correctFatCalculation_viewFatAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewFat(); + String expectedOutput = "Total Fat: 129 grams"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { + System.setOut(new PrintStream(outputStream)); + + testUser.handleViewSugar(); + String expectedOutput = "Total Sugar: 106 grams"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + + @Test + public void handleListEverything_allEmptyLists_printListAccurate() { + testMealList.clear(); + testDrinkList.clear(); + testExerciseList.clear(); + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + " >> nothing so far :o" + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 0 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListEverything_validList_printListAccurate() { + testUser.handleListEverything(); + + String expectedOutput = "here's what you have consumed today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate + System.lineSeparator() + + "3. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 0 ml" + System.lineSeparator() + " ~~~" + System.lineSeparator() + + "here's the exercises you've done today" + System.lineSeparator() + + "1. swimming | duration: 20 | intensity: HIGH | date: " + todayDate; + String actualOutput = outputStream.toString().trim(); + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleClear_validCommand_clearListsSuccessful() { + testUser.handleClear(); + assertEquals(0, testMealList.size()); + assertEquals(0, testDrinkList.size()); + assertEquals(0, testExerciseList.size()); + + } +} From 3dd5d6cca78ab5128ad4796efe7a46f19ff06010 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 18:18:15 +0800 Subject: [PATCH 198/274] Remove unused variables in UserTest --- src/test/java/seedu/fitnus/user/UserTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 02284684a3..4814a3a1be 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -7,7 +7,6 @@ import seedu.fitnus.meal.Meal; import seedu.fitnus.exception.UnregisteredExerciseException; -import seedu.fitnus.storage.Storage; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -15,28 +14,19 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.fitnus.storage.StorageManager; import static org.junit.jupiter.api.Assertions.assertEquals; public class UserTest { User testUser; String todayDate; - StorageManager testStorageManager; ArrayList testMealList; ArrayList testDrinkList; ArrayList testExerciseList; - private Storage testMealStorage; - private Storage testDrinkStorage; - private Storage testExerciseStorage; private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @BeforeEach public void setUp() throws UnregisteredExerciseException { - testMealStorage = new Storage("./src/test/resources", "src/test/resources/MealList.txt"); - testDrinkStorage = new Storage("./src/test/resources", "src/test/resources/DrinkList.txt"); - testExerciseStorage = new Storage("./src/test/resources", "src/test/resources/ExerciseList.txt"); - testUser = new User(); testMealList = testUser.myMealList.mealList; From 7e35c72e7559183150efadb7f51e299cc55c81f3 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 18:28:13 +0800 Subject: [PATCH 199/274] Update MealListTest after reorganisation of classes --- .../java/seedu/fitnus/meal/MealListTest.java | 127 +++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/fitnus/meal/MealListTest.java b/src/test/java/seedu/fitnus/meal/MealListTest.java index 0fd91a598b..0550da815f 100644 --- a/src/test/java/seedu/fitnus/meal/MealListTest.java +++ b/src/test/java/seedu/fitnus/meal/MealListTest.java @@ -1,2 +1,127 @@ -package seedu.fitnus.meal;public class MealListTest { +package seedu.fitnus.meal; + +import seedu.fitnus.date.Date; + +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteMealException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NonPositiveValueException; +import seedu.fitnus.exception.UnregisteredMealException; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class MealListTest { + MealList testerMealList; + String todayDate; + ArrayList testMealList; + ArrayList testMealListAll; + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + @BeforeEach + public void setUp() { + testerMealList = new MealList(); + + testMealList = testerMealList.mealList; + testMealListAll = testerMealList.mealListAll; + + Date currentDate = new Date(); + todayDate = currentDate.getDate(); + + testMealList.add(new Meal("kaya toast", 4, todayDate)); + testMealList.add(new Meal("laksa", 10, todayDate)); + + System.setOut(new PrintStream(outputStream)); + } + + @Test + public void handleMeal_validInputs_correctlyAddMeal() throws IncompleteMealException, UnregisteredMealException, + NonPositiveValueException { + String command = "eat m/kaya toast s/3"; + testerMealList.handleMeal(command); + + assertFalse(testMealList.isEmpty()); + + assertEquals("kaya toast", testMealList.get(2).getName()); + assertEquals(3, testMealList.get(2).getServingSize()); + } + + @Test + public void handleListMeals_emptyList_printListAccurate() { + testMealList.clear(); + testerMealList.handleListMeals(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListMeals_validList_printListAccurate() { + testerMealList.handleListMeals(); + + String expectedOutput = "here's what you have eaten today" + System.lineSeparator() + + "1. kaya toast (serving size: 4) | date: " + todayDate + System.lineSeparator() + + "2. laksa (serving size: 10) | date: " + todayDate ; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleEditMealServingSize_invalidMealIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "editMeal 5 s/10"; + testerMealList.handleEditMealServingSize(command); + }); + } + + @Test + public void handleEditMealServingSize_validCommand_editMealSuccessful() throws InvalidListIndexException, + IncompleteEditException, NonPositiveValueException { + String command = "editMeal 2 s/1000000"; + testerMealList.handleEditMealServingSize(command); + + int mealIndex = 2 - 1; + assertEquals("laksa", testMealList.get(mealIndex).getName()); + assertEquals(1000000, testMealList.get(mealIndex).getServingSize()); + } + + @Test + public void handleDeleteMeal_noIndexInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(IncompleteDeleteException.class, () -> { + String command = "deleteMeal "; + testerMealList.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_noIntegerInput_exceptionThrown() throws InvalidListIndexException, + IncompleteDeleteException { + Exception exception = assertThrows(NumberFormatException.class, () -> { + String command = "deleteMeal "; + testerMealList.handleDeleteMeal(command); + }); + } + + @Test + public void handleDeleteMeal_validCommand_deleteMealSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteMeal 1"; + testerMealList.handleDeleteMeal(command); + assertEquals(1, testMealList.size()); + assertEquals("laksa", testMealList.get(0).getName()); + } + } From 2cb12c14c2fa1394198d403699be2708e7885181 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 18:33:23 +0800 Subject: [PATCH 200/274] Update DrinkListTest after reorganisation of classes --- .../seedu/fitnus/drink/DrinkListTest.java | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/fitnus/drink/DrinkListTest.java b/src/test/java/seedu/fitnus/drink/DrinkListTest.java index c44da56e50..8344a8d7b8 100644 --- a/src/test/java/seedu/fitnus/drink/DrinkListTest.java +++ b/src/test/java/seedu/fitnus/drink/DrinkListTest.java @@ -1,2 +1,115 @@ -package seedu.fitnus.drink;public class DrinkListTest { +package seedu.fitnus.drink; + +import seedu.fitnus.date.Date; + +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteDrinkException; +import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NonPositiveValueException; +import seedu.fitnus.exception.UnregisteredDrinkException; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class DrinkListTest { + DrinkList testerDrinkList; + String todayDate; + ArrayList testDrinkList; + ArrayList testDrinkListAll; + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + @BeforeEach + public void setUp() { + testerDrinkList = new DrinkList(); + + testDrinkList = testerDrinkList.drinkList; + testDrinkListAll = testerDrinkList.drinkListAll; + + Date currentDate = new Date(); + todayDate = currentDate.getDate(); + + testDrinkList.add(new Drink("kopi", 100, todayDate)); + + System.setOut(new PrintStream(outputStream)); + } + + @Test + public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, + UnregisteredDrinkException, NonPositiveValueException { + String command = "drink d/kopi s/500"; + testerDrinkList.handleDrink(command); + + assertEquals("kopi", testDrinkList.get(1).getName()); + assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); + } + +// @Test +// public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { +// testDrinkList.add(new Drink ("water", 500, todayDate)); +// +// testerDrinkList.handleViewWaterIntake(); +// String expectedOutput = "Total water intake today: 600 ml"; +// String actualOutput = outputStream.toString().trim(); +// assertEquals(actualOutput, expectedOutput); +// } + + @Test + public void handleListDrinks_emptyList_printListAccurate() { + testDrinkList.clear(); + testerDrinkList.handleListDrinks(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + + @Test + public void handleListDrinks_validList_printListAccurate() { + testerDrinkList.handleListDrinks(); + + String expectedOutput = "here's what you have drank today" + System.lineSeparator() + + "1. kopi (volume: 100ml) | date: " + todayDate + System.lineSeparator() + System.lineSeparator() + + "Total water intake today: 0 ml"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleEditDrinkServingSize_validCommand_editDrinkSuccessful() throws InvalidListIndexException, + IncompleteEditException, NonPositiveValueException { + String command = "editDrink 1 s/100000000"; + testerDrinkList.handleEditDrinkServingSize(command); + + int drinkIndex = 0; + assertEquals("kopi", testDrinkList.get(drinkIndex).getName()); + assertEquals(100000000, testDrinkList.get(drinkIndex).getDrinkVolumeSize()); + } + + @Test + public void handleDeleteDrink_invalidDrinkIndex_exceptionThrown() throws InvalidListIndexException { + Exception exception = assertThrows(InvalidListIndexException.class, () -> { + String command = "deleteDrink 5"; + testerDrinkList.handleDeleteDrink(command); + }); + } + + @Test + public void handleDeleteDrink_validCommand_deleteDrinkSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteDrink 1"; + testerDrinkList.handleDeleteDrink(command); + assertEquals(0, testDrinkList.size()); + } + } From 9f6ed11f2d42b063112d2cf4e5aea980406dc3e3 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 18:37:59 +0800 Subject: [PATCH 201/274] Update ExerciseListTest after reorganisation of classes --- .../seedu/fitnus/drink/DrinkListTest.java | 12 +-- .../fitnus/exercise/ExerciseListTest.java | 91 ++++++++++++++++++- 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/test/java/seedu/fitnus/drink/DrinkListTest.java b/src/test/java/seedu/fitnus/drink/DrinkListTest.java index 8344a8d7b8..aaaba148c4 100644 --- a/src/test/java/seedu/fitnus/drink/DrinkListTest.java +++ b/src/test/java/seedu/fitnus/drink/DrinkListTest.java @@ -49,17 +49,7 @@ public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkEx assertEquals("kopi", testDrinkList.get(1).getName()); assertEquals(500, testDrinkList.get(1).getDrinkVolumeSize()); } - -// @Test -// public void handleViewWaterIntake_correctWaterCalculation_viewWaterAccurate() { -// testDrinkList.add(new Drink ("water", 500, todayDate)); -// -// testerDrinkList.handleViewWaterIntake(); -// String expectedOutput = "Total water intake today: 600 ml"; -// String actualOutput = outputStream.toString().trim(); -// assertEquals(actualOutput, expectedOutput); -// } - + @Test public void handleListDrinks_emptyList_printListAccurate() { testDrinkList.clear(); diff --git a/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java index a444a59ca5..2d9d50314d 100644 --- a/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java +++ b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java @@ -1,2 +1,91 @@ -package seedu.fitnus.exercise;public class ExerciseListTest { +package seedu.fitnus.exercise; + +import seedu.fitnus.date.Date; + +import seedu.fitnus.exception.IncompleteDeleteException; +import seedu.fitnus.exception.IncompleteExerciseException; +import seedu.fitnus.exception.InvalidListIndexException; +import seedu.fitnus.exception.NonPositiveValueException; +import seedu.fitnus.exception.UnregisteredExerciseException; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ExerciseListTest { + ExerciseList testerExerciseList; + String todayDate; + ArrayList testExerciseList; + ArrayList testExerciseListAll; + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + @BeforeEach + public void setUp() throws UnregisteredExerciseException { + testerExerciseList = new ExerciseList(); + + testExerciseList = testerExerciseList.exerciseList; + testExerciseListAll = testerExerciseList.exerciseListAll; + + Date currentDate = new Date(); + todayDate = currentDate.getDate(); + + testExerciseList.add(new Exercise("swimming", 20, ExerciseIntensity.HIGH, todayDate)); + + System.setOut(new PrintStream(outputStream)); + } + + @Test + public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteExerciseException, + UnregisteredExerciseException, NonPositiveValueException { + String command = "exercise e/running d/30 i/HIGH"; + testerExerciseList.handleExercise(command); + + assertEquals("running", testExerciseList.get(1).getName()); + assertEquals(30, testExerciseList.get(1).getDuration()); + assertEquals(ExerciseIntensity.HIGH, testExerciseList.get(1).getIntensity()); + } + + @Test + public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { + testerExerciseList.handleCaloriesBurnt(); + String expectedOutput = "Total calories burnt: 240"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(actualOutput, expectedOutput); + } + + @Test + public void handleListExercise_emptyList_printListAccurate() { + testExerciseList.clear(); + testerExerciseList.handleListExercises(); + + String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + + " >> nothing so far :o"; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleListExercise_validList_printListAccurate() { + testerExerciseList.handleListExercises(); + + String expectedOutput = "here's the exercises you've done today" + System.lineSeparator() + + "1. swimming | duration: 20 | intensity: HIGH | date: " + todayDate; + String actualOutput = outputStream.toString().trim(); + + assertEquals(expectedOutput, actualOutput); + } + + @Test + public void handleDeleteExercise_validCommand_deleteMealSuccessful() throws InvalidListIndexException, + IncompleteDeleteException { + String command = "deleteExercise 1"; + testerExerciseList.handleDeleteExercise(command); + assertEquals(0, testExerciseList.size()); + } } From e8b013d51ab41b7a31d6eda3ccc987c07abe12c5 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Fri, 12 Apr 2024 18:44:57 +0800 Subject: [PATCH 202/274] Fix Checkstyle Errors --- src/main/java/seedu/fitnus/parser/Parser.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index e890800d1b..99b5210304 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,11 +1,13 @@ package seedu.fitnus.parser; +import seedu.fitnus.date.Date; import seedu.fitnus.date.DateValidation; import seedu.fitnus.drink.Drink; -import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; +import seedu.fitnus.user.User; +import seedu.fitnus.validator.IntegerValidation; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; @@ -21,13 +23,7 @@ import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.meal.Meal; -import seedu.fitnus.exercise.Exercise; -import seedu.fitnus.exercise.ExerciseIntensity; -import seedu.fitnus.date.Date; - -import seedu.fitnus.user.User; -import seedu.fitnus.validator.IntegerValidation; +import seedu.fitnus.exception.FutureDateException; import java.text.ParseException; From 3a0b358b33a6c5507c2443037647fe9378ab73fc Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Fri, 12 Apr 2024 18:47:06 +0800 Subject: [PATCH 203/274] Remove unused import of Date Class --- src/main/java/seedu/fitnus/parser/Parser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 99b5210304..6d8c8d3be3 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -1,6 +1,5 @@ package seedu.fitnus.parser; -import seedu.fitnus.date.Date; import seedu.fitnus.date.DateValidation; import seedu.fitnus.drink.Drink; import seedu.fitnus.meal.Meal; From c24ddc7f07bf86a47a4af679c796bb48b3808abe Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 19:07:53 +0800 Subject: [PATCH 204/274] Fix merge conflicts --- src/main/java/seedu/fitnus/parser/Parser.java | 117 +++++++++--------- src/main/java/seedu/fitnus/user/User.java | 5 +- 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 6d8c8d3be3..2d3e27f996 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -99,86 +99,87 @@ public Parser(User user) { * @param command The command entered by the user. */ public void handleCommand(String command) { + String trimmedCommand = command.trim(); try { - if (command.equals("help")) { + if (trimmedCommand.equals("help")) { handleHelp(); - } else if (command.startsWith("eat")) { - user.myMealList.handleMeal(command); - } else if (command.startsWith("drink")) { - user.myDrinkList.handleDrink(command); - } else if (command.startsWith("exercise")) { - user.myExerciseList.handleExercise(command); - } else if (command.startsWith("newMeal")) { - user.myMealList.handleAddNewMealNutrient(command); - } else if (command.startsWith("newDrink")) { - user.myDrinkList.handleAddNewDrinkNutrient(command); - } else if (command.startsWith("newExercise")) { - user.myExerciseList.handleAddNewExerciseCalories(command); - }else if (command.equals("allMeals")) { + } else if (trimmedCommand.startsWith("eat")) { + user.myMealList.handleMeal(trimmedCommand); + } else if (trimmedCommand.startsWith("drink")) { + user.myDrinkList.handleDrink(trimmedCommand); + } else if (trimmedCommand.startsWith("exercise")) { + user.myExerciseList.handleExercise(trimmedCommand); + } else if (trimmedCommand.startsWith("newMeal")) { + user.myMealList.handleAddNewMealNutrient(trimmedCommand); + } else if (trimmedCommand.startsWith("newDrink")) { + user.myDrinkList.handleAddNewDrinkNutrient(trimmedCommand); + } else if (trimmedCommand.startsWith("newExercise")) { + user.myExerciseList.handleAddNewExerciseCalories(trimmedCommand); + }else if (trimmedCommand.equals("allMeals")) { Meal.listAvailableMeals(); - } else if (command.equals("allDrinks")) { + } else if (trimmedCommand.equals("allDrinks")) { Drink.listAvailableDrinks(); - } else if (command.equals("allExercises")) { + } else if (trimmedCommand.equals("allExercises")) { Exercise.listAvailableExercises(); - } else if (command.startsWith("infoMeal")) { - Meal.handleInfoMeal(command); - } else if (command.startsWith("infoDrink")) { - Drink.handleInfoDrink(command); - } else if (command.startsWith("infoExercise")) { - Exercise.handleInfoExercise(command); - } else if (command.equals("calories")) { + } else if (trimmedCommand.startsWith("infoMeal")) { + Meal.handleInfoMeal(trimmedCommand); + } else if (trimmedCommand.startsWith("infoDrink")) { + Drink.handleInfoDrink(trimmedCommand); + } else if (trimmedCommand.startsWith("infoExercise")) { + Exercise.handleInfoExercise(trimmedCommand); + } else if (trimmedCommand.equals("calories")) { user.handleViewCalories(); - } else if (command.equals("caloriesBurnt")) { + } else if (trimmedCommand.equals("caloriesBurnt")) { user.myExerciseList.handleCaloriesBurnt(); - } else if (command.equals("carbs")) { + } else if (trimmedCommand.equals("carbs")) { user.handleViewCarbohydrates(); - } else if (command.equals("protein")) { + } else if (trimmedCommand.equals("protein")) { user.handleViewProteins(); - } else if (command.equals("sugar")) { + } else if (trimmedCommand.equals("sugar")) { user.handleViewSugar(); - } else if (command.equals("fat")) { + } else if (trimmedCommand.equals("fat")) { user.handleViewFat(); - } else if (command.equals("viewWater")) { + } else if (trimmedCommand.equals("viewWater")) { user.myDrinkList.handleViewWaterIntake(); - } else if (command.equals("fiber")) { + } else if (trimmedCommand.equals("fiber")) { user.handleViewFiber(); - } else if (command.equals("listMeals")) { + } else if (trimmedCommand.equals("listMeals")) { user.myMealList.handleListMeals(); - } else if (command.equals("listMealsAll")) { + } else if (trimmedCommand.equals("listMealsAll")) { user.myMealList.handleListMealsAll(); - } else if (command.startsWith("listMeals") && command.contains("d/")) { - user.myMealList.handleListMealsDate(command); - } else if (command.equals("listDrinks")) { + } else if (trimmedCommand.startsWith("listMeals") && trimmedCommand.contains("d/")) { + user.myMealList.handleListMealsDate(trimmedCommand); + } else if (trimmedCommand.equals("listDrinks")) { user.myDrinkList.handleListDrinks(); - } else if (command.equals("listDrinksAll")) { + } else if (trimmedCommand.equals("listDrinksAll")) { user.myDrinkList.handleListDrinksAll(); - } else if (command.startsWith("listDrinks") && command.contains("d/")) { - user.myDrinkList.handleListDrinksDate(command); - } else if (command.equals("listExercises")) { + } else if (trimmedCommand.startsWith("listDrinks") && trimmedCommand.contains("d/")) { + user.myDrinkList.handleListDrinksDate(trimmedCommand); + } else if (trimmedCommand.equals("listExercises")) { user.myExerciseList.handleListExercises(); - } else if (command.equals("listExercisesAll")) { + } else if (trimmedCommand.equals("listExercisesAll")) { user.myExerciseList.handleListExercisesAll(); - } else if (command.startsWith("listExercises") && command.contains("d/")) { + } else if (trimmedCommand.startsWith("listExercises") && trimmedCommand.contains("d/")) { user.myExerciseList.handleListExercisesDate(command); - } else if (command.equals("listEverything")) { + } else if (trimmedCommand.equals("listEverything")) { user.handleListEverything(); - } else if (command.equals("listEverythingAll")) { + } else if (trimmedCommand.equals("listEverythingAll")) { user.handleListEverythingAll(); - } else if (command.startsWith("listEverything") && command.contains("d/")) { - user.handleListEverythingDate(command); - } else if (command.startsWith("editMeal")) { - user.myMealList.handleEditMealServingSize(command); - } else if (command.startsWith("editDrink")) { - user.myDrinkList.handleEditDrinkServingSize(command); - } else if (command.startsWith("editWater")) { - user.myDrinkList.handleEditWaterIntake(command); - } else if (command.startsWith("deleteMeal")) { - user.myMealList.handleDeleteMeal(command); - } else if (command.startsWith("deleteDrink")) { - user.myDrinkList.handleDeleteDrink(command); - } else if (command.startsWith("deleteExercise")) { - user.myExerciseList.handleDeleteExercise(command); - } else if (command.equals("clear")) { + } else if (trimmedCommand.startsWith("listEverything") && trimmedCommand.contains("d/")) { + user.handleListEverythingDate(trimmedCommand); + } else if (trimmedCommand.startsWith("editMeal")) { + user.myMealList.handleEditMealServingSize(trimmedCommand); + } else if (trimmedCommand.startsWith("editDrink")) { + user.myDrinkList.handleEditDrinkServingSize(trimmedCommand); + } else if (trimmedCommand.startsWith("editWater")) { + user.myDrinkList.handleEditWaterIntake(trimmedCommand); + } else if (trimmedCommand.startsWith("deleteMeal")) { + user.myMealList.handleDeleteMeal(trimmedCommand); + } else if (trimmedCommand.startsWith("deleteDrink")) { + user.myDrinkList.handleDeleteDrink(trimmedCommand); + } else if (trimmedCommand.startsWith("deleteExercise")) { + user.myExerciseList.handleDeleteExercise(trimmedCommand); + } else if (trimmedCommand.equals("clear")) { user.handleClear(); } else if (command.equals("recommend")) { user.handleRecommendations(); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 9a3b3f576e..83e8868668 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -2,13 +2,14 @@ import seedu.fitnus.drink.Drink; import seedu.fitnus.drink.DrinkList; +import seedu.fitnus.drink.Water; import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.meal.Meal; import seedu.fitnus.meal.MealList; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseList; import seedu.fitnus.parser.Parser; -import seedu.fitnus.drink.Water; + import seedu.fitnus.exception.InvalidDateException; import java.text.ParseException; @@ -20,6 +21,7 @@ public class User { public static final int RECOMMEND_WATER_INTAKE = 2600; public static final int RECOMMEND_CALORIE_INTAKE = 2200; + public static MealList myMealList; public static ExerciseList myExerciseList; public static DrinkList myDrinkList; @@ -234,6 +236,7 @@ public void handleClear() { System.out.println("All entries have been deleted"); } + /** * Handles when user would like to see what is recommended to them, * only regarding the calorie and water intake. From 45f90d366ba3a4dec952f7f1b3fbb305fa8fac8c Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 19:09:54 +0800 Subject: [PATCH 205/274] Fix PED bug issue #92 on unrecognised commands with whitespaces --- src/main/java/seedu/fitnus/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 2d3e27f996..722cdf4fd4 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -99,7 +99,7 @@ public Parser(User user) { * @param command The command entered by the user. */ public void handleCommand(String command) { - String trimmedCommand = command.trim(); + String trimmedCommand = command.trim(); try { if (trimmedCommand.equals("help")) { handleHelp(); From 2d17b75abc49cbdc2ae8d2634c5b8892c651afdc Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 22:24:02 +0800 Subject: [PATCH 206/274] Fix PED bug issue #95 of view count overflowing int value --- .../exception/ExceedTypeLongException.java | 5 ++ .../java/seedu/fitnus/exercise/Exercise.java | 10 ++-- .../seedu/fitnus/exercise/ExerciseList.java | 7 ++- src/main/java/seedu/fitnus/parser/Parser.java | 9 +++- src/main/java/seedu/fitnus/ui/Ui.java | 2 +- src/main/java/seedu/fitnus/user/User.java | 52 +++++++++++++------ .../fitnus/validator/IntegerValidation.java | 11 +++- src/test/java/seedu/fitnus/user/UserTest.java | 13 ++--- 8 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/ExceedTypeLongException.java diff --git a/src/main/java/seedu/fitnus/exception/ExceedTypeLongException.java b/src/main/java/seedu/fitnus/exception/ExceedTypeLongException.java new file mode 100644 index 0000000000..cb2d1b9d10 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/ExceedTypeLongException.java @@ -0,0 +1,5 @@ +package seedu.fitnus.exception; + +public class ExceedTypeLongException extends Exception { + +} diff --git a/src/main/java/seedu/fitnus/exercise/Exercise.java b/src/main/java/seedu/fitnus/exercise/Exercise.java index 522b1f2e2d..72b4ad3e78 100644 --- a/src/main/java/seedu/fitnus/exercise/Exercise.java +++ b/src/main/java/seedu/fitnus/exercise/Exercise.java @@ -11,7 +11,7 @@ public class Exercise { private String name; private int duration; // Duration in minutes private ExerciseIntensity intensity; - private int caloriesBurnt; + private long caloriesBurnt; private String dateAdded; /** @@ -51,7 +51,7 @@ private void setCaloriesBurnt() throws UnregisteredExerciseException { if (details == null) { throw new UnregisteredExerciseException(); } - this.caloriesBurnt = duration * details[intensity.ordinal()]; + this.caloriesBurnt = (long) duration * details[intensity.ordinal()]; } /** @@ -103,11 +103,11 @@ public String getDate() { } /** - * Returns an integer value of the amount of calories burnt from the exercise. + * Returns a long value of the amount of calories burnt from the exercise. * - * @return an integer value of the amount of calories burnt from the exercise + * @return a long value of the amount of calories burnt from the exercise */ - public int getCaloriesBurnt() { + public long getCaloriesBurnt() { return caloriesBurnt; } diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java index 221e90ffe9..9c2f8519b7 100644 --- a/src/main/java/seedu/fitnus/exercise/ExerciseList.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -1,6 +1,7 @@ package seedu.fitnus.exercise; import seedu.fitnus.date.Date; +import seedu.fitnus.exception.ExceedTypeLongException; import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteExerciseException; @@ -9,6 +10,7 @@ import seedu.fitnus.exception.NonPositiveValueException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.parser.Parser; +import seedu.fitnus.validator.IntegerValidation; import java.text.ParseException; import java.util.ArrayList; @@ -163,11 +165,12 @@ public void handleExercise(String command) throws IncompleteExerciseException, U /** * Prints the number of calories the user has burnt today. */ - public void handleCaloriesBurnt() { - int caloriesBurnt = 0; + public void handleCaloriesBurnt() throws ExceedTypeLongException { + long caloriesBurnt = 0; for (Exercise exercise: exerciseList) { caloriesBurnt += exercise.getCaloriesBurnt(); } + IntegerValidation.checkNoOverflowForSum(caloriesBurnt); System.out.println("Total calories burnt: " + caloriesBurnt); } } diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 722cdf4fd4..be488a70a9 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -2,6 +2,7 @@ import seedu.fitnus.date.DateValidation; import seedu.fitnus.drink.Drink; +import seedu.fitnus.exception.ExceedTypeLongException; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; @@ -99,7 +100,7 @@ public Parser(User user) { * @param command The command entered by the user. */ public void handleCommand(String command) { - String trimmedCommand = command.trim(); + String trimmedCommand = command.trim(); try { if (trimmedCommand.equals("help")) { handleHelp(); @@ -181,7 +182,7 @@ public void handleCommand(String command) { user.myExerciseList.handleDeleteExercise(trimmedCommand); } else if (trimmedCommand.equals("clear")) { user.handleClear(); - } else if (command.equals("recommend")) { + } else if (trimmedCommand.equals("recommend")) { user.handleRecommendations(); } else { throw new InvalidCommandException(); @@ -233,6 +234,10 @@ public void handleCommand(String command) { System.out.println("Specified date is invalid. Please try another date."); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); + } catch (ExceedTypeLongException e) { + System.out.println("the count you would like to view has exceeded our data limits, are you sure you have " + + "consumed so much? Please do a quick check to update your listMeals and/or listDrinks before " + + "viewing again :')"); } } diff --git a/src/main/java/seedu/fitnus/ui/Ui.java b/src/main/java/seedu/fitnus/ui/Ui.java index 5cf9c2f48f..5c031cbc7c 100644 --- a/src/main/java/seedu/fitnus/ui/Ui.java +++ b/src/main/java/seedu/fitnus/ui/Ui.java @@ -69,7 +69,7 @@ public static void showLine() { public void readCommand() { String command = input.nextLine(); showLine(); - if (command.equals("exit")) { + if (command.trim().equals("exit")) { handleExit(); } else { parser.handleCommand(command); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 83e8868668..28754b7396 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -3,12 +3,14 @@ import seedu.fitnus.drink.Drink; import seedu.fitnus.drink.DrinkList; import seedu.fitnus.drink.Water; +import seedu.fitnus.exception.ExceedTypeLongException; import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.meal.Meal; import seedu.fitnus.meal.MealList; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseList; import seedu.fitnus.parser.Parser; +import seedu.fitnus.validator.IntegerValidation; import seedu.fitnus.exception.InvalidDateException; @@ -36,32 +38,44 @@ public User() { * Prints the user's total calorie intake of the day. * The method sums up the calories from meals and drinks, and subtracts calories burnt from exercise. */ - public void handleViewCalories() { - int caloriesCount = 0; + public void handleViewCalories() throws ExceedTypeLongException { + long caloriesIntakeCount = 0; for (Meal meal: myMealList.mealList) { - caloriesCount += meal.getCalories(); + caloriesIntakeCount += meal.getCalories(); } for (Drink drink: myDrinkList.drinkList) { - caloriesCount += drink.getCalories(); + caloriesIntakeCount += drink.getCalories(); } - for (Exercise exercise: myExerciseList.exerciseList) { - caloriesCount -= exercise.getCaloriesBurnt(); + IntegerValidation.checkNoOverflowForSum(caloriesIntakeCount); + + try { + int caloriesBurntCount = 0; + for (Exercise exercise : myExerciseList.exerciseList) { + caloriesBurntCount += exercise.getCaloriesBurnt(); + } + IntegerValidation.checkNoOverflowForSum(caloriesBurntCount); + + long caloriesCount = caloriesIntakeCount - caloriesBurntCount; + System.out.println("Total Calories: " + caloriesIntakeCount); + } catch (ExceedTypeLongException e) { + System.out.println("the amount of calories you burnt has exceeded our data limits. please do a quick " + + "check to make sure your exerciseList is accurate!"); } - System.out.println("Total Calories: " + caloriesCount); } /** * Prints the user's total carbohydrate intake of the day. * The method sums up the carbohydrates from meals and drinks. */ - public void handleViewCarbohydrates() { - int carbohydratesCount = 0; + public void handleViewCarbohydrates() throws ExceedTypeLongException { + long carbohydratesCount = 0; for (Meal meal: myMealList.mealList) { carbohydratesCount += meal.getCarbs(); } for (Drink drink: myDrinkList.drinkList) { carbohydratesCount += drink.getCarbs(); } + IntegerValidation.checkNoOverflowForSum(carbohydratesCount); System.out.println("Total Carbohydrates: " + carbohydratesCount + " grams"); } @@ -69,14 +83,15 @@ public void handleViewCarbohydrates() { * Prints the user's total protein intake of the day. * The method sums up the protein from meals and drinks. */ - public void handleViewProteins() { - int proteinCount = 0; + public void handleViewProteins() throws ExceedTypeLongException { + long proteinCount = 0; for (Meal meal: myMealList.mealList) { proteinCount += meal.getProtein(); } for (Drink drink: myDrinkList.drinkList) { proteinCount += drink.getProtein(); } + IntegerValidation.checkNoOverflowForSum(proteinCount); System.out.println("Total Proteins: " + proteinCount + " grams"); } @@ -84,11 +99,12 @@ public void handleViewProteins() { * Prints the user's total fiber intake of the day. * The method sums up the fiber from meals. */ - public void handleViewFiber() { - int fibreCount = 0; + public void handleViewFiber() throws ExceedTypeLongException { + long fibreCount = 0; for (Meal meal: myMealList.mealList) { fibreCount += meal.getFiber(); } + IntegerValidation.checkNoOverflowForSum(fibreCount); System.out.println("Total Fiber: " + fibreCount + " grams"); } @@ -96,14 +112,15 @@ public void handleViewFiber() { * Prints the user's total fat intake of the day. * The method sums up the fat from meals and drinks. */ - public void handleViewFat() { - int fatCount = 0; + public void handleViewFat() throws ExceedTypeLongException { + long fatCount = 0; for (Meal meal: myMealList.mealList) { fatCount += meal.getFat(); } for (Drink drink: myDrinkList.drinkList) { fatCount += drink.getFat(); } + IntegerValidation.checkNoOverflowForSum(fatCount); System.out.println("Total Fat: " + fatCount + " grams"); } @@ -111,14 +128,15 @@ public void handleViewFat() { * Prints the user's total sugar intake of the day. * The method sums up the sugar from meals and drinks. */ - public void handleViewSugar() { - int sugarCount = 0; + public void handleViewSugar() throws ExceedTypeLongException { + long sugarCount = 0; for (Meal meal: myMealList.mealList) { sugarCount += meal.getSugar(); } for (Drink drink: myDrinkList.drinkList) { sugarCount += drink.getSugar(); } + IntegerValidation.checkNoOverflowForSum(sugarCount); System.out.println("Total Sugar: " + sugarCount + " grams"); } diff --git a/src/main/java/seedu/fitnus/validator/IntegerValidation.java b/src/main/java/seedu/fitnus/validator/IntegerValidation.java index e7eee85619..d08368bdb9 100644 --- a/src/main/java/seedu/fitnus/validator/IntegerValidation.java +++ b/src/main/java/seedu/fitnus/validator/IntegerValidation.java @@ -1,5 +1,6 @@ package seedu.fitnus.validator; +import seedu.fitnus.exception.ExceedTypeLongException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.NonPositiveValueException; @@ -7,7 +8,8 @@ * Validates whether an integer value complies with the condition stated. */ public class IntegerValidation { - +// public static final long MIN_LONG_VALUE = -9223372036854775808; +// public static final long MAX_LONG_VALUE = 9223372036854775807; /** * Validates whether the integer value is a positive integer. * @@ -25,4 +27,11 @@ public static void checkIntegerGreaterOrEqualThanZero (int value) throws Negativ throw new NegativeValueException(); } } + + public static void checkNoOverflowForSum(long value) throws ExceedTypeLongException { + if (value < 0) { + throw new ExceedTypeLongException(); + } + } + } diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 4814a3a1be..57ae77ae65 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -2,6 +2,7 @@ import seedu.fitnus.date.Date; import seedu.fitnus.drink.Drink; +import seedu.fitnus.exception.ExceedTypeLongException; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; import seedu.fitnus.meal.Meal; @@ -45,7 +46,7 @@ public void setUp() throws UnregisteredExerciseException { } @Test - public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() { + public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() throws ExceedTypeLongException { testUser.handleViewCalories(); String expectedOutput = "Total Calories: 5507"; String actualOutput = outputStream.toString().trim(); @@ -54,7 +55,7 @@ public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() } @Test - public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() { + public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() throws ExceedTypeLongException { testUser.handleViewCarbohydrates(); String expectedOutput = "Total Carbohydrates: 912 grams"; String actualOutput = outputStream.toString().trim(); @@ -63,7 +64,7 @@ public void handleViewCarbohydrates_correctCarbsCalculation_viewCarbsAccurate() } @Test - public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { + public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() throws ExceedTypeLongException { System.setOut(new PrintStream(outputStream)); testUser.handleViewProteins(); @@ -73,7 +74,7 @@ public void handleViewProtein_correctProteinCalculation_viewProteinAccurate() { } @Test - public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { + public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() throws ExceedTypeLongException { System.setOut(new PrintStream(outputStream)); testUser.handleViewFiber(); @@ -84,7 +85,7 @@ public void handleViewFiber_correctFiberCalculation_viewFiberAccurate() { } @Test - public void handleViewFat_correctFatCalculation_viewFatAccurate() { + public void handleViewFat_correctFatCalculation_viewFatAccurate() throws ExceedTypeLongException { System.setOut(new PrintStream(outputStream)); testUser.handleViewFat(); @@ -95,7 +96,7 @@ public void handleViewFat_correctFatCalculation_viewFatAccurate() { } @Test - public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() { + public void handleViewSugar_correctSugarCalculation_viewSugarAccurate() throws ExceedTypeLongException { System.setOut(new PrintStream(outputStream)); testUser.handleViewSugar(); From 49565025b78fb07cb2cba81944fde0a571905f82 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 22:55:31 +0800 Subject: [PATCH 207/274] Update data type of variables to long --- src/main/java/seedu/fitnus/drink/Drink.java | 50 ++++++++--------- src/main/java/seedu/fitnus/meal/Meal.java | 60 ++++++++++----------- src/main/java/seedu/fitnus/user/User.java | 6 ++- 3 files changed, 59 insertions(+), 57 deletions(-) diff --git a/src/main/java/seedu/fitnus/drink/Drink.java b/src/main/java/seedu/fitnus/drink/Drink.java index 023d51f275..e2faf57a28 100644 --- a/src/main/java/seedu/fitnus/drink/Drink.java +++ b/src/main/java/seedu/fitnus/drink/Drink.java @@ -11,11 +11,11 @@ public class Drink { private String name; private int drinkVolume; private String dateAdded; - private int calories; - private int carbs; - private int sugar; - private int protein; - private int fat; + private long calories; + private long carbs; + private long sugar; + private long protein; + private long fat; /** * Constructor for a Drink, requires the name and volume of the drink, @@ -61,11 +61,11 @@ public Drink(String name, int volume, String currentDate) { */ private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); - calories = nutrients[0] * drinkVolume / 100; - carbs = nutrients[1] * drinkVolume / 100; - sugar = nutrients[2] * drinkVolume / 100; - protein = nutrients[3] * drinkVolume / 100; - fat = nutrients[4] * drinkVolume / 100; + calories = (long) nutrients[0] * drinkVolume / 100; + carbs = (long) nutrients[1] * drinkVolume / 100; + sugar = (long) nutrients[2] * drinkVolume / 100; + protein = (long) nutrients[3] * drinkVolume / 100; + fat = (long) nutrients[4] * drinkVolume / 100; } /** @@ -133,47 +133,47 @@ public int getDrinkVolumeSize() { } /** - * Returns an integer value of the amount of calories in the drink. + * Returns a long value of the amount of calories in the drink. * - * @return an integer value of the amount of calories in the drink + * @return a long value of the amount of calories in the drink */ - public int getCalories() { + public long getCalories() { return calories; } /** - * Returns an integer value of the amount of carbohydrates in the drink. + * Returns a long value of the amount of carbohydrates in the drink. * - * @return an integer value of the amount of carbohydrates in the drink + * @return a long value of the amount of carbohydrates in the drink */ - public int getCarbs() { + public long getCarbs() { return carbs; } /** - * Returns an integer value of the amount of sugar in the drink. + * Returns a long value of the amount of sugar in the drink. * - * @return an integer value of the amount of sugar in the drink + * @return a long value of the amount of sugar in the drink */ - public int getSugar() { + public long getSugar() { return sugar; } /** - * Returns an integer value of the amount of protein in the drink. + * Returns a long value of the amount of protein in the drink. * - * @return an integer value of the amount of protein in the drink + * @return a long value of the amount of protein in the drink */ - public int getProtein() { + public long getProtein() { return protein; } /** - * Returns an integer value of the amount of fat in the drink. + * Returns a long value of the amount of fat in the drink. * - * @return an integer value of the amount of fat in the drink + * @return a long value of the amount of fat in the drink */ - public int getFat() { + public long getFat() { return fat; } diff --git a/src/main/java/seedu/fitnus/meal/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java index 51febee401..9e9d114727 100644 --- a/src/main/java/seedu/fitnus/meal/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -11,12 +11,12 @@ public class Meal { private String name; private int servingSize; private String dateAdded; - private int calories; - private int carbs; - private int protein; - private int fat; - private int fiber; - private int sugar; + private long calories; + private long carbs; + private long protein; + private long fat; + private long fiber; + private long sugar; /** * Constructor for a Meal, requires the name and serving size of the meal, @@ -68,12 +68,12 @@ public Meal(String name, int servingSize, String currentDate) { */ private void setNutrientValues(String name) { int[] nutrients = nutrientDetails.get(name); - calories = nutrients[0] * servingSize; - carbs = nutrients[1] * servingSize; - protein = nutrients[2] * servingSize; - fat = nutrients[3] * servingSize; - fiber = nutrients[4] * servingSize; - sugar = nutrients[5] * servingSize; + calories = (long) nutrients[0] * servingSize; + carbs = (long) nutrients[1] * servingSize; + protein = (long) nutrients[2] * servingSize; + fat = (long) nutrients[3] * servingSize; + fiber = (long) nutrients[4] * servingSize; + sugar = (long) nutrients[5] * servingSize; } /** @@ -86,56 +86,56 @@ public String getName() { } /** - * Returns an integer value of the amount of calories in the meal. + * Returns a long value of the amount of calories in the meal. * - * @return an integer value of the amount of calories in the meal + * @return a long value of the amount of calories in the meal */ - public int getCalories() { + public long getCalories() { return calories; } /** - * Returns an integer value of the amount of carbohydrates in the meal. + * Returns a long value of the amount of carbohydrates in the meal. * - * @return an integer value of the amount of carbohydrates in the meal + * @return a long value of the amount of carbohydrates in the meal */ - public int getCarbs() { + public long getCarbs() { return carbs; } /** - * Returns an integer value of the amount of protein in the meal. + * Returns a long value of the amount of protein in the meal. * - * @return an integer value of the amount of protein in the meal + * @return a long value of the amount of protein in the meal */ - public int getProtein() { + public long getProtein() { return protein; } /** - * Returns an integer value of the amount of fat in the meal. + * Returns a long value of the amount of fat in the meal. * - * @return an integer value of the amount of fat in the meal + * @return a long value of the amount of fat in the meal */ - public int getFat() { + public long getFat() { return fat; } /** - * Returns an integer value of the amount of fiber in the meal. + * Returns a long value of the amount of fiber in the meal. * - * @return an integer value of the amount of fiber in the meal + * @return a long value of the amount of fiber in the meal */ - public int getFiber() { + public long getFiber() { return fiber; } /** - * Returns an integer value of the amount of sugar in the meal. + * Returns a long value of the amount of sugar in the meal. * - * @return an integer value of the amount of sugar in the meal + * @return a long value of the amount of sugar in the meal */ - public int getSugar() { + public long getSugar() { return sugar; } diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 28754b7396..d77eed12fa 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -47,16 +47,18 @@ public void handleViewCalories() throws ExceedTypeLongException { caloriesIntakeCount += drink.getCalories(); } IntegerValidation.checkNoOverflowForSum(caloriesIntakeCount); + assert caloriesIntakeCount >= 0: "total calories intake has to be a non-negative value"; try { - int caloriesBurntCount = 0; + long caloriesBurntCount = 0; for (Exercise exercise : myExerciseList.exerciseList) { caloriesBurntCount += exercise.getCaloriesBurnt(); } IntegerValidation.checkNoOverflowForSum(caloriesBurntCount); + assert caloriesBurntCount >= 0: "total calories burnt has to be a non-negative value"; long caloriesCount = caloriesIntakeCount - caloriesBurntCount; - System.out.println("Total Calories: " + caloriesIntakeCount); + System.out.println("Total Calories: " + caloriesCount); } catch (ExceedTypeLongException e) { System.out.println("the amount of calories you burnt has exceeded our data limits. please do a quick " + "check to make sure your exerciseList is accurate!"); From 50962c748e81ff99dfb2346d6c88a778cbb862c3 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 23:03:24 +0800 Subject: [PATCH 208/274] Update calorie count in recommendation to be long --- src/main/java/seedu/fitnus/user/User.java | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index d77eed12fa..6a7b14d88a 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -22,7 +22,7 @@ */ public class User { public static final int RECOMMEND_WATER_INTAKE = 2600; - public static final int RECOMMEND_CALORIE_INTAKE = 2200; + public static final long RECOMMEND_CALORIE_INTAKE = 2200; public static MealList myMealList; public static ExerciseList myExerciseList; @@ -274,24 +274,22 @@ public void handleRecommendations() { System.out.println("Great! You are on track with the water intake!"); } System.out.println(" ~~"); - int caloriesCount = 0; + + long caloriesIntakeCount = 0; for (Meal meal: myMealList.mealList) { - caloriesCount += meal.getCalories(); + caloriesIntakeCount += meal.getCalories(); } for (Drink drink: myDrinkList.drinkList) { - caloriesCount += drink.getCalories(); - } - for (Exercise exercise: myExerciseList.exerciseList) { - caloriesCount -= exercise.getCaloriesBurnt(); + caloriesIntakeCount += drink.getCalories(); } - int caloriesDifference = RECOMMEND_CALORIE_INTAKE - caloriesCount; - if (caloriesCount < RECOMMEND_CALORIE_INTAKE) { + long caloriesDifference = RECOMMEND_CALORIE_INTAKE - caloriesIntakeCount; + if (caloriesIntakeCount < RECOMMEND_CALORIE_INTAKE) { System.out.println("We recommend eating more food. Please eat " + caloriesDifference + " more calories"); - } else if (caloriesCount > RECOMMEND_CALORIE_INTAKE && caloriesCount < RECOMMEND_CALORIE_INTAKE + 200) { + } else if (caloriesIntakeCount > RECOMMEND_CALORIE_INTAKE && caloriesIntakeCount < RECOMMEND_CALORIE_INTAKE + 200) { System.out.println("Great! You are on track with the calorie intake!"); } else { System.out.println("You are " + -caloriesDifference - + " calories above the recommended calorie amount, consider exercising!"); + + " calories above the recommended calorie intake amount, consider exercising!"); } } } From 0424d0258e943e38b02888bc71d953f08990be55 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Fri, 12 Apr 2024 23:14:06 +0800 Subject: [PATCH 209/274] Fix checkstyle error in IntegerValidation --- src/main/java/seedu/fitnus/validator/IntegerValidation.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/seedu/fitnus/validator/IntegerValidation.java b/src/main/java/seedu/fitnus/validator/IntegerValidation.java index d08368bdb9..e75775f5e2 100644 --- a/src/main/java/seedu/fitnus/validator/IntegerValidation.java +++ b/src/main/java/seedu/fitnus/validator/IntegerValidation.java @@ -8,8 +8,6 @@ * Validates whether an integer value complies with the condition stated. */ public class IntegerValidation { -// public static final long MIN_LONG_VALUE = -9223372036854775808; -// public static final long MAX_LONG_VALUE = 9223372036854775807; /** * Validates whether the integer value is a positive integer. * From 5b9596232d123f19a9324b0c3452a9842a12fc76 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Fri, 12 Apr 2024 23:15:14 +0800 Subject: [PATCH 210/274] Fix checkstyle error in User --- src/main/java/seedu/fitnus/user/User.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 6a7b14d88a..99d1b90260 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -285,7 +285,8 @@ public void handleRecommendations() { long caloriesDifference = RECOMMEND_CALORIE_INTAKE - caloriesIntakeCount; if (caloriesIntakeCount < RECOMMEND_CALORIE_INTAKE) { System.out.println("We recommend eating more food. Please eat " + caloriesDifference + " more calories"); - } else if (caloriesIntakeCount > RECOMMEND_CALORIE_INTAKE && caloriesIntakeCount < RECOMMEND_CALORIE_INTAKE + 200) { + } else if (caloriesIntakeCount > RECOMMEND_CALORIE_INTAKE + && caloriesIntakeCount < RECOMMEND_CALORIE_INTAKE + 200) { System.out.println("Great! You are on track with the calorie intake!"); } else { System.out.println("You are " + -caloriesDifference From c45ef3d23879ff7f6e0631054714965e179bd8cb Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Fri, 12 Apr 2024 23:19:15 +0800 Subject: [PATCH 211/274] Fix checkstyle error in ExerciseListTest --- src/test/java/seedu/fitnus/exercise/ExerciseListTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java index 2d9d50314d..6275455cc9 100644 --- a/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java +++ b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java @@ -2,6 +2,7 @@ import seedu.fitnus.date.Date; +import seedu.fitnus.exception.ExceedTypeLongException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.InvalidListIndexException; @@ -50,7 +51,8 @@ public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteE } @Test - public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() { + public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() + throws ExceedTypeLongException { testerExerciseList.handleCaloriesBurnt(); String expectedOutput = "Total calories burnt: 240"; String actualOutput = outputStream.toString().trim(); From 3bdc0df0bbfc75f8e829d28cac53e41149d7e7c2 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sat, 13 Apr 2024 22:52:35 +0800 Subject: [PATCH 212/274] Update UserGuide --- docs/UserGuide.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 9954dd4f33..7f56255e38 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -12,6 +12,10 @@ To use the app please follow the setup procedures below: 3. Navigate to the folder you just created. 4. Run the JAR file. +Note: +1. All files under 'data' and 'db' folders should not be modified by user +2. Enter "exit" to properly close the program and save the data + ## Table of Contents * [User Guide: FitNUS](#user-guide-fitnus) From ca6a8bacf3eff7d4c6175527d4944311eac8363f Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 14 Apr 2024 16:28:36 +0800 Subject: [PATCH 213/274] Fix bugs and documentations relating to Water.java class --- README.md | 2 +- db/Drink_db.csv | 9 ++++---- docs/UserGuide.md | 8 +++---- src/main/java/seedu/fitnus/drink/Drink.java | 14 ++++++++++--- .../java/seedu/fitnus/drink/DrinkList.java | 19 ++++++++++------- .../IncompleteEditWaterException.java | 8 +++++++ .../exception/InvalidEditWaterException.java | 8 +++++++ .../java/seedu/fitnus/exercise/Exercise.java | 10 +++++++-- src/main/java/seedu/fitnus/meal/Meal.java | 10 +++++++-- src/main/java/seedu/fitnus/parser/Parser.java | 21 ++++++++++++------- .../java/seedu/fitnus/parser/ParserTest.java | 10 +++++---- 11 files changed, 85 insertions(+), 34 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/IncompleteEditWaterException.java create mode 100644 src/main/java/seedu/fitnus/exception/InvalidEditWaterException.java diff --git a/README.md b/README.md index 7e9489fa5a..fef4168009 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ high/medium/low intensity workout defined per minute and can be inputted immedia 7. View daily fat consumed: `fat` 8. View daily sugar consumed: `sugar` 9. View daily fiber consumed: `fiber` -10. View daily water consumption: `viewWater` +10. View daily water consumption: `water` 11. View daily calories consumed: `caloriesBurnt` 12. View daily calories and water intake recommendation, based on current intake: `recommend` diff --git a/db/Drink_db.csv b/db/Drink_db.csv index 9e4aff223f..7e38d058a9 100644 --- a/db/Drink_db.csv +++ b/db/Drink_db.csv @@ -1,18 +1,19 @@ +water,0,0,0,0,0 +sprite,270,42,7,8,2 +iced lemon tea,95,21,1,1,1 +milo,124,20,3,3,1 +kopi,141,26,2,3,1 soursop juice,117,25,3,1,1 kopi c,117,20,1,4,0 kalamansi juice,168,42,0,0,1 coke,153,32,1,2,1 kopi o,67,15,1,0,0 -milo,124,20,3,3,1 plum juice,57,13,1,0,1 -kopi,141,26,2,3,1 teh c bing,231,24,15,1,1 guava juice,143,38,0,0,1 tiger beer,42,3,1,0,0 teh tarik,124,21,3,3,0 sugarcane juice,192,52,0,0,1 teh,151,29,4,1,1 -sprite,270,42,7,8,2 -iced lemon tea,95,21,1,1,1 bandung,153,32,1,2,1 diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 7f56255e38..7fddad71f3 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -46,7 +46,7 @@ Note: * [1.3.7 View daily fat consumed: `fat`](#137-view-daily-fat-consumed-fat) * [1.3.8 View daily sugar consumed: `sugar`](#138-view-daily-sugar-consumed-sugar) * [1.3.9 View daily fiber consumed: `fiber`](#139-view-daily-fiber-consumed-fiber) - * [1.3.10 View daily water consumption: `viewWater`](#1310-view-daily-water-consumption-viewwater) + * [1.3.10 View daily water consumption: `water`](#1310-view-daily-water-consumption-viewwater) * [1.3.11 View daily calories consumed: `caloriesBurnt`](#1311-view-daily-calories-consumed-caloriesburnt) * [1.3.12 View daily calories and water intake recommendation: `recommend`](#1312-view-daily-calories-and-water-intake-recommendation-recommend) * [1.4 For listing arrays](#14-for-listing-arrays) @@ -106,7 +106,7 @@ View nutrients and calories: - View daily fat consumed: fat - View daily sugar consumed: sugar - View daily fiber consumed: fiber -- View daily water consumption: viewWater +- View daily water consumption: water - View daily calories burnt: caloriesBurnt List Commands: @@ -344,9 +344,9 @@ Display current total fiber intake (g) for the day Total Fiber: 20 grams ~~~ -### 1.3.10 View daily water consumption: `viewWater` +### 1.3.10 View daily water consumption: `water` Display current total water intake (in ml) for the day -**Format**: `viewWater` +**Format**: `water` **Expected output**: ~~~ Total water intake today: 0 ml diff --git a/src/main/java/seedu/fitnus/drink/Drink.java b/src/main/java/seedu/fitnus/drink/Drink.java index e2faf57a28..c4a7171437 100644 --- a/src/main/java/seedu/fitnus/drink/Drink.java +++ b/src/main/java/seedu/fitnus/drink/Drink.java @@ -5,9 +5,10 @@ import seedu.fitnus.parser.Parser; import java.util.HashMap; +import java.util.LinkedHashMap; public class Drink { - public static HashMap nutrientDetails = new HashMap<>(); + public static HashMap nutrientDetails = new LinkedHashMap<>(); private String name; private int drinkVolume; private String dateAdded; @@ -35,6 +36,7 @@ public Drink(String name, int volume, String currentDate) { } static { + nutrientDetails.put("water", new int[]{0, 0, 0, 0, 0}); nutrientDetails.put("sprite", new int[]{270, 42, 7, 8, 2}); nutrientDetails.put("iced lemon tea", new int[]{95, 21, 1, 1, 1}); nutrientDetails.put("milo", new int[]{124, 20, 3, 3, 1}); @@ -93,10 +95,16 @@ public static void handleInfoDrink(String command) throws UnregisteredDrinkExcep * only called when the user first enters the program. */ public static void printAvailableDrinks() { + int count = 0; System.out.print("Available drinks: "); for (String drink : nutrientDetails.keySet()) { - System.out.print(drink); - System.out.print(", "); + if (count < 3) { + System.out.print(drink); + System.out.print(", "); + count ++; + } else { + break; + } } System.out.print("etc."); System.out.println(); diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index d3ff94c287..8e97b02733 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -5,7 +5,9 @@ import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteEditWaterException; import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.exception.InvalidEditWaterException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.NonPositiveValueException; @@ -45,7 +47,7 @@ public void handleAddNewDrinkNutrient(String command) throws NegativeValueExcept int fat = Parser.drinkNutrientFat; Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); - System.out.println("Added " + description + " to available drinks"); + System.out.println("Added " + description + " to available drinks."); } /** @@ -89,7 +91,7 @@ public void handleViewWaterIntake() { for (Water water: waterList) { waterIntake += water.getWater(); } - System.out.println("Total water intake today: " + waterIntake + " ml"); + System.out.println("Total water intake today: " + waterIntake + " ml."); } /** @@ -196,7 +198,6 @@ public void handleListDrinksDate(String command) throws InvalidDateException, Fu public void handleEditDrinkServingSize(String command) throws InvalidListIndexException, NonPositiveValueException, IncompleteEditException { Parser.parseEditDrink(command); - if (Parser.editDrinkIndex >= drinkList.size() || Parser.editDrinkIndex < 0) { throw new InvalidListIndexException(); } @@ -205,7 +206,7 @@ public void handleEditDrinkServingSize(String command) throws InvalidListIndexEx Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize, drinkDate); drinkList.set(Parser.editDrinkIndex, updatedDrink); - System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); + System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml."); } @@ -216,7 +217,8 @@ public void handleEditDrinkServingSize(String command) throws InvalidListIndexEx * @throws NonPositiveValueException if the provided serving size is a negative value * @throws IncompleteEditException if the user did not comply with the required command format */ - public void handleEditWaterIntake(String command) throws NonPositiveValueException, IncompleteEditException { + public void handleEditWaterIntake(String command) throws NonPositiveValueException, IncompleteEditWaterException, + InvalidEditWaterException { Parser.parseEditWater(command); Date currentDate = new Date(); for (Water water: waterList) { @@ -224,7 +226,10 @@ public void handleEditWaterIntake(String command) throws NonPositiveValueExcepti water.editWaterIntake(Parser.editWaterSize); } } - System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); + if (waterList.isEmpty()) { + throw new InvalidEditWaterException(); + } + System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml."); } /** @@ -247,7 +252,7 @@ public void handleDeleteDrink(String command) throws InvalidListIndexException, String drinkName = drinkList.get(drinkIndex).getName(); drinkList.remove(drinkIndex); - System.out.println("Removed " + drinkName + " from drinks"); + System.out.println("Removed " + drinkName + " from drinks."); } diff --git a/src/main/java/seedu/fitnus/exception/IncompleteEditWaterException.java b/src/main/java/seedu/fitnus/exception/IncompleteEditWaterException.java new file mode 100644 index 0000000000..2d9e0409c8 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/IncompleteEditWaterException.java @@ -0,0 +1,8 @@ +package seedu.fitnus.exception; + +/** + * Exception class thrown when the user did not comply with the required format to edit a water object. + * Class is inherited from Exception. + */ +public class IncompleteEditWaterException extends Exception{ +} diff --git a/src/main/java/seedu/fitnus/exception/InvalidEditWaterException.java b/src/main/java/seedu/fitnus/exception/InvalidEditWaterException.java new file mode 100644 index 0000000000..e28a2aa16a --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/InvalidEditWaterException.java @@ -0,0 +1,8 @@ +package seedu.fitnus.exception; + +/** + * Exception class thrown when the user did not enter any water for the day and proceed to edit the water intake. + * Class is inherited from Exception. + */ +public class InvalidEditWaterException extends Exception { +} diff --git a/src/main/java/seedu/fitnus/exercise/Exercise.java b/src/main/java/seedu/fitnus/exercise/Exercise.java index 72b4ad3e78..41f431f08e 100644 --- a/src/main/java/seedu/fitnus/exercise/Exercise.java +++ b/src/main/java/seedu/fitnus/exercise/Exercise.java @@ -138,10 +138,16 @@ public static void handleInfoExercise(String command) throws UnregisteredExercis * only called when the user first enters the program. */ public static void printAvailableExercises() { + int count = 0; System.out.print("Available exercises: "); for (String exercise : exerciseDetails.keySet()) { - System.out.print(exercise); - System.out.print(", "); + if (count < 3) { + System.out.print(exercise); + System.out.print(", "); + count++; + } else { + break; + } } System.out.print("etc."); System.out.println(); diff --git a/src/main/java/seedu/fitnus/meal/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java index 9e9d114727..d1c37fb8cf 100644 --- a/src/main/java/seedu/fitnus/meal/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -173,10 +173,16 @@ public static void handleInfoMeal(String command) throws UnregisteredMealExcepti * only called when the user first enters the program. */ public static void printAvailableMeals() { + int count = 0; System.out.print("Available meals: "); for (String meal : nutrientDetails.keySet()) { - System.out.print(meal); - System.out.print(", "); + if (count < 3) { + System.out.print(meal); + System.out.print(", "); + count ++; + } else { + break; + } } System.out.print("etc."); System.out.println(); diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index be488a70a9..171f87ab05 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -2,28 +2,30 @@ import seedu.fitnus.date.DateValidation; import seedu.fitnus.drink.Drink; -import seedu.fitnus.exception.ExceedTypeLongException; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; import seedu.fitnus.user.User; import seedu.fitnus.validator.IntegerValidation; +import seedu.fitnus.exception.ExceedTypeLongException; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteEditWaterException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.IncompleteMealException; import seedu.fitnus.exception.InvalidCommandException; import seedu.fitnus.exception.InvalidDateException; +import seedu.fitnus.exception.InvalidEditWaterException; import seedu.fitnus.exception.InvalidListIndexException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.NonPositiveValueException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; -import seedu.fitnus.exception.FutureDateException; import java.text.ParseException; @@ -140,7 +142,7 @@ public void handleCommand(String command) { user.handleViewSugar(); } else if (trimmedCommand.equals("fat")) { user.handleViewFat(); - } else if (trimmedCommand.equals("viewWater")) { + } else if (trimmedCommand.equals("water")) { user.myDrinkList.handleViewWaterIntake(); } else if (trimmedCommand.equals("fiber")) { user.handleViewFiber(); @@ -198,7 +200,7 @@ public void handleCommand(String command) { "the format MUST be [exercise e/EXERCISE d/DURATION i/INTENSITY].\n" + " > DURATION should be in minutes and INTENSITY can only be HIGH/MEDIUM/LOW."); } catch (UnregisteredDrinkException e) { - System.out.println("Sorry that drink is not registered in the database.Please check the spelling and " + + System.out.println("Sorry that drink is not registered in the database. Please check the spelling and " + "try again"); } catch (UnregisteredMealException e) { System.out.println("Sorry that meal is not registered in the database. Please check the spelling and " + @@ -238,6 +240,11 @@ public void handleCommand(String command) { System.out.println("the count you would like to view has exceeded our data limits, are you sure you have " + "consumed so much? Please do a quick check to update your listMeals and/or listDrinks before " + "viewing again :')"); + } catch (InvalidEditWaterException e) { + System.out.println("Make sure to add water for the day before editing it."); + } catch (IncompleteEditWaterException e) { + System.out.println("Please specify the new volume of water.\n" + + "The format should be [editWater s/NEW_VOLUME(ML)]."); } } @@ -271,7 +278,7 @@ public static void handleHelp() { System.out.println("- View daily fat consumed: fat"); System.out.println("- View daily sugar consumed: sugar"); System.out.println("- View daily fiber consumed: fiber"); - System.out.println("- View daily water consumption: viewWater"); + System.out.println("- View daily water consumption: water"); System.out.println("- View daily calories burnt: caloriesBurnt"); System.out.println(); System.out.println("List Commands: "); @@ -478,10 +485,10 @@ public static void parseEditDrink(String command) throws NonPositiveValueExcepti * @throws NonPositiveValueException If a negative value is encountered. * @throws IncompleteEditException If the command is incomplete. */ - public static void parseEditWater(String command) throws NonPositiveValueException, IncompleteEditException { + public static void parseEditWater(String command) throws NonPositiveValueException, IncompleteEditWaterException { int waterSizePosition = command.indexOf("s/") + 2; if (waterSizePosition <= 1) { //-1 + 2 - throw new IncompleteEditException(); + throw new IncompleteEditWaterException(); } editWaterSize = Integer.parseInt(command.substring(waterSizePosition).trim()); IntegerValidation.checkIntegerGreaterThanZero(editWaterSize); diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 2842847849..b7a86ac397 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -1,8 +1,10 @@ package seedu.fitnus.parser; import org.junit.jupiter.api.Test; + import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteEditException; +import seedu.fitnus.exception.IncompleteEditWaterException; import seedu.fitnus.exception.IncompleteExerciseException; import seedu.fitnus.exception.IncompleteInfoException; import seedu.fitnus.exception.InvalidDateException; @@ -13,7 +15,6 @@ import seedu.fitnus.exception.UnregisteredMealException; import seedu.fitnus.exercise.ExerciseIntensity; - import java.text.ParseException; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -80,9 +81,10 @@ public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NonPositive } @Test - public void parseEditWater_validInputs_success() throws IncompleteEditException, NonPositiveValueException { - String command = "editWater s/500"; - Parser.parseEditWater(command); + public void parseEditWater_validInputs_success() throws NonPositiveValueException, + IncompleteEditWaterException { + String command_2 = "editWater s/500"; + Parser.parseEditWater(command_2); assertEquals(500, Parser.editWaterSize); } From 3648c1d3f1e2672e6393d34ce333467db471e146 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 14 Apr 2024 16:39:22 +0800 Subject: [PATCH 214/274] Minor change in printing output --- src/main/java/seedu/fitnus/drink/DrinkList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index 8e97b02733..95408de531 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -91,7 +91,7 @@ public void handleViewWaterIntake() { for (Water water: waterList) { waterIntake += water.getWater(); } - System.out.println("Total water intake today: " + waterIntake + " ml."); + System.out.println("Total water intake today: " + waterIntake + " ml"); } /** From afd847e7ebebe119fa5a12ce17a0a50ff45eb415 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sun, 14 Apr 2024 19:44:26 +0800 Subject: [PATCH 215/274] Add sequence diagram for Ui class in DG --- docs/DeveloperGuide.md | 13 +++++ docs/diagrams/ParserSequenceDiagram.puml | 47 ++++++++++++++++++ .../diagrams_png/ui/ParserSequenceDiagram.png | Bin 0 -> 31289 bytes src/main/java/seedu/fitnus/parser/Parser.java | 2 +- src/main/java/seedu/fitnus/ui/Ui.java | 4 +- 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 docs/diagrams/ParserSequenceDiagram.puml create mode 100644 docs/diagrams/diagrams_png/ui/ParserSequenceDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e2fee1e6f9..9803102380 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -27,6 +27,19 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a - `Meal`: Meals intake and its nutritional values created by user - `Water`: Water intake created by user +### Ui Component +#### Sequence Diagram +_Note: The following sequence diagram captures the interactions only between the Fitnus, Ui and Parser classes_ + +![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ui/ParserSequenceDiagram.png) +When the user first starts the application, the Ui class will be constructed. Within the Ui class, Scanner and Parser +similarly will be constructed. + +The Ui class will continuously read the user input: +- If the user input DOES NOT correspond to "exit", Ui will pass the user input to Parser class. Parser class will both + parse and handle the command. +- Else if the user input corresponds to "exit", Ui will handle the exit. + ### Exercise Component ![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseClassDiagram.png) diff --git a/docs/diagrams/ParserSequenceDiagram.puml b/docs/diagrams/ParserSequenceDiagram.puml new file mode 100644 index 0000000000..573d5fea0a --- /dev/null +++ b/docs/diagrams/ParserSequenceDiagram.puml @@ -0,0 +1,47 @@ +@startuml +'https://plantuml.com/sequence-diagram + +participant ":Fitnus" as Fitnus +participant ":Ui" as Ui +participant "input:Scanner" as Scanner +participant ":Parser" as Parser + +hide footbox + +Fitnus -> Ui **: start application +activate Ui +Ui -> Scanner**: Scanner() +activate Scanner +Ui -> Parser**: Parser() +activate Parser + +Fitnus -> Ui: printWelcomeMessage() +Ui --> Fitnus + +loop !isExit +Fitnus -> Ui: readCommand() + +Ui -> Scanner: nextLine() +Scanner --> Ui: command + +'Ui --> Ui ++: showLine() +'Ui --> Ui --: + +alt input is not exit command +Ui -> Parser: parseCommand(command) +Parser --> Ui: command handled + +else input is exit command +deactivate Parser + +Ui -> Ui ++: handleExit() +Ui -> Scanner: close() +destroy Scanner +Ui --> Ui --: exit handled +end +end + + +Ui --> Fitnus --: exit application + +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/ui/ParserSequenceDiagram.png b/docs/diagrams/diagrams_png/ui/ParserSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..4dd039ed4b5e4d1d0215e40c1a0a6d137edadd94 GIT binary patch literal 31289 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 z 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 VmmJpafjgWL271Q2xjNQC{{q9|z=i+- literal 0 HcmV?d00001 diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 171f87ab05..948ccb5a56 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -101,7 +101,7 @@ public Parser(User user) { * * @param command The command entered by the user. */ - public void handleCommand(String command) { + public void parseCommand(String command) { String trimmedCommand = command.trim(); try { if (trimmedCommand.equals("help")) { diff --git a/src/main/java/seedu/fitnus/ui/Ui.java b/src/main/java/seedu/fitnus/ui/Ui.java index 5c031cbc7c..28bcc3f982 100644 --- a/src/main/java/seedu/fitnus/ui/Ui.java +++ b/src/main/java/seedu/fitnus/ui/Ui.java @@ -59,7 +59,7 @@ public void handleExit() { /** * Prints the divider line between messages. */ - public static void showLine() { + public void showLine() { System.out.println(LINE); } @@ -72,7 +72,7 @@ public void readCommand() { if (command.trim().equals("exit")) { handleExit(); } else { - parser.handleCommand(command); + parser.parseCommand(command); } showLine(); } From 87a882dba359b1e155ef56b985d7a72d4424bd2d Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 14 Apr 2024 20:31:27 +0800 Subject: [PATCH 216/274] Add class diagrams --- docs/DeveloperGuide.md | 2 +- docs/diagrams/DrinkListClassDiagram.puml | 65 ++++++++++++++++++ docs/diagrams/ExerciseClassDiagram.puml | 56 --------------- ...ram.puml => ExerciseListClassDiagram.puml} | 34 +++++---- docs/diagrams/MealListClassDiagram.puml | 51 ++++++++++++++ .../diagrams_png/DrinkListClassDiagram.png | Bin 0 -> 68723 bytes .../diagrams_png/ExerciseClassDiagram.png | Bin 43505 -> 0 bytes .../diagrams_png/ExerciseListClassDiagram.png | Bin 0 -> 38300 bytes 8 files changed, 133 insertions(+), 75 deletions(-) create mode 100644 docs/diagrams/DrinkListClassDiagram.puml delete mode 100644 docs/diagrams/ExerciseClassDiagram.puml rename docs/diagrams/{WaterClassDiagram.puml => ExerciseListClassDiagram.puml} (61%) create mode 100644 docs/diagrams/MealListClassDiagram.puml create mode 100644 docs/diagrams/diagrams_png/DrinkListClassDiagram.png delete mode 100644 docs/diagrams/diagrams_png/ExerciseClassDiagram.png create mode 100644 docs/diagrams/diagrams_png/ExerciseListClassDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e2fee1e6f9..dcfbc680ad 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -28,7 +28,7 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a - `Water`: Water intake created by user ### Exercise Component -![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseClassDiagram.png) +![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseListClassDiagram.png) 1. Upon starting up the application, User will call `loadExercises` to fetch all data from `ExerciseList.txt` and add it into `exerciseListAll`. 2. A `User` class consists of zero to as many `Exercise` objects in the ArrayList. diff --git a/docs/diagrams/DrinkListClassDiagram.puml b/docs/diagrams/DrinkListClassDiagram.puml new file mode 100644 index 0000000000..dd92883d72 --- /dev/null +++ b/docs/diagrams/DrinkListClassDiagram.puml @@ -0,0 +1,65 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor CLASS_ARROW_COLOR +skinparam classBackgroundColor CLASS_DIAGRAM_COLOR +skinparam classAttributeIconSize 0 + +Class DrinkList { + + drinkList: ArrayList + + drinkListAll: ArrayList + + waterList: ArrayList + + waterListAll: ArrayList + + DrinkList() + + handleAddNewDrinkNutrient(command: String): void + + handleDrink(command: String): void + + handleViewWaterIntake(): void + + printDrinkList(startIndex: int, drinkListToPrint: ArrayList): void + + handleListDrinks(): void + + handleListDrinksAll(): void + + handleListDrinksDate(command: String): void + + handleEditDrinkServingSize(command: String): void + + handleEditWaterIntake (command: String): void + + handleDeleteDrink (command: String): void +} + +Class Drink { + + nutrientDetails: HashMap + - name: String + - dateAdded: String + - drinkVolume: int + - carbs: long + - sugar: long + - calories: long + - protein: long + - fat: long + + + Drink(name: String, volume: int, currentDate: String) + + handleInfoDrink (command: String): void + + printAvailableExercises(): void + + listAvailableDrinks(): void + + getNutrientDetails(): HashMap + + getName(): String + + getDrinkVolumeSize(): int + + getCalories(): long + + getCarbs(): long + + getSugar(): long + + getProtein(): long + + getFat(): long + + getDate(): String + - setNutrientValues(name: String): void +} + +Class Water { + - waterIntake: int + - dateAdded: String + + Water(amount: int, dateAdded: String) + + getWater(): int + + addWaterIntake(amount: int): void + + editWaterIntake(amount: int): void + + getDate(): String +} + +DrinkList -down-> "*" Drink +DrinkList --> "*" Water +@enduml \ No newline at end of file diff --git a/docs/diagrams/ExerciseClassDiagram.puml b/docs/diagrams/ExerciseClassDiagram.puml deleted file mode 100644 index 9c6f7d5b5e..0000000000 --- a/docs/diagrams/ExerciseClassDiagram.puml +++ /dev/null @@ -1,56 +0,0 @@ -@startuml -!include style.puml -skinparam arrowThickness 1.1 -skinparam arrowColor CLASS_ARROW_COLOR -skinparam classBackgroundColor CLASS_DIAGRAM_COLOR - -Class User { - # exerciseList: ArrayList - # exerciseListAll: ArrayList - # etc... - - + loadExercise (exerciseStorage: Storage): void - + loadExerciseCalories (exerciseCaloriesStorage: Storage): void - + saveExercise (exerciseStorage: Storage): void - + saveExerciseCalories (exerciseCaloriesStorage: Storage): void - + printExerciseList (exerciseListToPrint: ArrayList): void - + handleListExercises (): void - + handleListExercisesAll (): void - + handleListExercisesDate (command: String): void - + handleDeleteExercisesDate (command: String): void - + handleExercises (command: String): void - + handleCaloriesBurnt(): void - + etc()... -} - -Class Exercise { - - name: String - - duration: int - - intensity: ExerciseIntensity - - caloriesBurnt: int - - dateAdded: String - + exerciseDetails: HashMap - + Exercise(name: String, duration: int, intensity: ExerciseIntensity, currentDate: String) - + getName(): String - + getDuration(): int - + getIntensity(): ExerciseIntensity - + getDate(): String - + getCaloriesBurnt(): int - + handleInfoExercise(command: String): void - + printAvailableExercises(): void - + listAvailableExercises(): void - + getExerciseDetails(): HashMap - - setCaloriesBurnt(): void - - isValidIntensity(intensity: ExerciseIntensity): boolean -} - -Class "<>\nExerciseIntensity" as ExerciseIntensity { - HIGH - MEDIUM - LOW -} - -User -down-> "*" Exercise - -Exercise "*" *-down-> "1" ExerciseIntensity -@enduml \ No newline at end of file diff --git a/docs/diagrams/WaterClassDiagram.puml b/docs/diagrams/ExerciseListClassDiagram.puml similarity index 61% rename from docs/diagrams/WaterClassDiagram.puml rename to docs/diagrams/ExerciseListClassDiagram.puml index e4ba2bb9ca..6d74eb1ade 100644 --- a/docs/diagrams/WaterClassDiagram.puml +++ b/docs/diagrams/ExerciseListClassDiagram.puml @@ -3,39 +3,37 @@ skinparam arrowThickness 1.1 skinparam arrowColor CLASS_ARROW_COLOR skinparam classBackgroundColor CLASS_DIAGRAM_COLOR +skinparam classAttributeIconSize 0 -Class User { - # exerciseList: ArrayList - # exerciseListAll: ArrayList - # etc +Class ExerciseList { + + exerciseList: ArrayList + + exerciseListAll: ArrayList - + loadExercise (exerciseStorage: Storage): void - + loadExerciseCalories (exerciseCaloriesStorage: Storage): void - + saveExercise (exerciseStorage: Storage): void - + saveExerciseCalories (exerciseCaloriesStorage: Storage): void - + printExerciseList (exerciseListToPrint: ArrayList): void - + handleListExercises (): void - + handleListExercisesAll (): void - + handleListExercisesDate (command: String): void - + handleDeleteExercisesDate (command: String): void - + handleExercises (command: String): void + + ExerciseList() + + handleListExercises(): void + + handleListExercisesAll(): void + handleCaloriesBurnt(): void - + etc() + + handleListExercisesDate(command: String): void + + handleDeleteExercisesDate(command: String): void + + handleExercises (command: String): void + + handleAddNewExerciseCalories(command: String): void + + printExerciseList(exerciseListToPrint: ArrayList): void } Class Exercise { + + exerciseDetails: HashMap - name: String - duration: int - intensity: ExerciseIntensity - caloriesBurnt: int - dateAdded: String - + exerciseDetails: HashMap + + Exercise(name: String, duration: int, intensity: ExerciseIntensity, currentDate: String) + getName(): String + getDuration(): int + getIntensity(): ExerciseIntensity + getDate(): String - + getCaloriesBurnt(): int + + getCaloriesBurnt(): long + handleInfoExercise(command: String): void + printAvailableExercises(): void + listAvailableExercises(): void @@ -50,7 +48,7 @@ Class "<>\nExerciseIntensity" as ExerciseIntensity { LOW } -User -down-> "*" Exercise +ExerciseList -down-> "*" Exercise Exercise "*" *-down-> "1" ExerciseIntensity @enduml \ No newline at end of file diff --git a/docs/diagrams/MealListClassDiagram.puml b/docs/diagrams/MealListClassDiagram.puml new file mode 100644 index 0000000000..e916180ddd --- /dev/null +++ b/docs/diagrams/MealListClassDiagram.puml @@ -0,0 +1,51 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor CLASS_ARROW_COLOR +skinparam classBackgroundColor CLASS_DIAGRAM_COLOR +skinparam classAttributeIconSize 0 + +Class MealList { + + mealList: ArrayList + + mealListAll: ArrayList + + MealList() + + handleAddNewMealNutrient(command: String): void + + handleMeal(command: String): void + + printMealList(startIndex: int, mealListToPrint: ArrayList): void + + handleListMeals(): void + + handleListMealsAll(): void + + handleListMealsDate(command: String): void + + handleEditMealServingSize(command: String): void + + handleDeleteMeal(command: String): void +} + +Class Meal { + + nutrientDetails: HashMap + - name: String + - servingSize: int + - dateAdded: String + - calories: long + - carbs: long + - protein: long + - fat: long + - fiber: long + - sugar: long + + Meal(name: String, servingSize: int, currentDate: String) + + handleInfoMeal(command: String): void + + printAvailableMeals(): void + + listAvailableMeals(): void + + getNutrientDetails(): HashMap + + getName(): String + + getCalories(): long + + getCarbs(): long + + getProtein(): long + + getFat(): long + + getFiber(): long + + getSugar(): long + + getServingSize(): int + + getDate(): String + - setNutrientValues(name: String): void +} + +MealList -down-> "*" Meal +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/DrinkListClassDiagram.png b/docs/diagrams/diagrams_png/DrinkListClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..543bcba0e928a3ebf13c20e5194bf164854cd646 GIT binary patch literal 68723 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 F{|BfTj@AGG literal 0 HcmV?d00001 diff --git a/docs/diagrams/diagrams_png/ExerciseClassDiagram.png b/docs/diagrams/diagrams_png/ExerciseClassDiagram.png deleted file mode 100644 index c3db6d88f6854d01f66b78c880fdfe9e57ba2f57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43505 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 diff --git a/docs/diagrams/diagrams_png/ExerciseListClassDiagram.png b/docs/diagrams/diagrams_png/ExerciseListClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..2555340922b2be2759442e3b6281cbfb144e1461 GIT binary patch literal 38300 zcmeFZWmuM7(>8q4-3lVDgmg)lgaT5M5&{C!-QA!d64H&*DIJocgmi~=NORJi?>fQj zy5qf{?RlPe`+k1EL|Df<)|xdlYoD2Yj^G#al33{X(IF5Bmb8?F5(EOz27w^FM1=>x z$-KK~1^!`hc&hGTU~S`SVQAz4kuM3<*6*%2ZGOgZiW2KNhn9wtc6m}c+hOgx(*q_uJC&TPIM0yOznR|A z9+-2@f5Y@W-FM91`q>vuSR#sBS(5j(3DwhoCWK}Sax%gX$ge8M5Q2PI?Exw`KjW0sZ&YqwlzN{AQoVvPHtHze(E zz)L%+{g`V?DGz(s82$v4~1}@*mPov&UorD-AgcIyz1G71mDqt=3+BJ z=-1S51@ib@?Sh6Kni+%z$l71I{GKSYFS&3TVG@1v$@BT)t?m`pTe}i!v@gln_i@8D zt(NE=*GkDU>1gtgM0<7nD@pU-h{d0$3&$P!Dgp9~2D2q3D>=p^=B+=u1Q(u*ZE~(m zIc?IquFAdAKWJAQ*_M-{HV9ngm&l3CAw>%-5~$65a|ffR+wvaMlPT9GWB9?lGTCo9 zvJ30ny|HR|i?!K91$@L_{%o+$io#-sH>FJ%=MQnq_*HVoTd$vNgbk^e+l-Xqyj&DCx8TNrVS3F7-~=b>ZiL2~MSeg7yk=JD)0&_@56g@m zzVK@-ZuAawHV8x#I2tL6lTz&*+V}OwSa44=jOIs_ry-;ev&iU*Nf?oeT`(?ww)(PT`u{JKPVWRTnxr^ zMba693D$^Jan!Wkj{;-JYL{d=mT6Iw^|{J;4=G$EDsznaTaOOCDcpWu8GR*SfuRKQrf=_El_5d~}QQ z04LUVY;>}c>tSqSL|;wKZ_1eMHJ%`HbHXkDIohVg9=U&;hEg=04o5LU>3(ML_a7gX zvbbf7>yM&5t9z^)uBSRf5h%PlI2n^frfRy2EyrjdVVuqhWBa7`au)AMo!;KakmIsEjCGxq z!FlOzzY|sPl(nd9%`0a(^iIe`7mLT!r9gq>v7)%26WYrwytJ~?=2B+0+ds@4nSuyl zIyNLg+JX~H1z+ubBxEqHHe)wPy zxPqs!P&u08#xLh59eE6SlVQ#x-K?uJW}?g&D0WAuBQ{Yxc?&er4D>WH#aJyQgoqvI z&9fa42=0$tGk`o1{O@h$-v{ZzOxYvg#(<$7S11Zn5T6qWkd_Z69Ap6wH4+Ej4-pcC z0^1WRK7^9ohw_w?5)5+r?*}E#UKC8MKD=o3f|wzLnZ76a-I>Uj&5(tDXgNC^dBz+f zgRPWLQ#bnp=PBY4zZ?{kXQSHTvlB+zqbwv!4<^*eHhkHkt7F{d=wb%f%Ds1{C3n%!&_W+BF;B zfM?`6e1rBft|4Y1Q)5i$Sn=@Z(l+_MT^FV2W*cECJZe`tkJtRj&eum}WM!YP1I2pw zt5B4bMlY%d|2r*$qT8~Vks5bV)fyRdE)y-0f@J=d$2Jq%J*-SqEvMC*)seAkpi{;S zM#8Tyu^f5T9eWl}iM1>4w<3f17^boG?V`Iz*j z4O1K;o2`&FbDeAst}S8DM)B$k16>bYuia<+A{FUEW5ZE2n*tZ5?`3p{9_16trwQ0! zRy|Df6mT3dYE<5rHdW3jf&zECV#(TLH9cyCweSe-+#*{Mzanao{CS|_Q_i$_#qPst?>99+NQ2b>_TAirX+&k|-|} zR54xuvGWr{awBs@EcS_tFF1Z#t(X&r_o`>#&f9XvTw}H+2ndAo7$7#=bUMz zqwzRR!Etf#N|x8>nR$12b?7nFZBQ|(TS*~LJE`aK^8ju&H@5WllyA^? zDtA9iz7GgMWVmBJnWEbtR~=O}C6oW7cv)Wd(+zb~9nT%KaYgtbo` zt~_8Fvh9TLoRS zR#B6I;dfEq^Jz5OUaAnL%?x8Q=(x;FtV&1I!BP6b{NuaDB;EChK}xv^8{&$!gG~X- zI>$)_3Qwz9<>&Fq6QB0hnUjPoY+31S$R(oz$;HD4KxRu#aOvbA+gIr~gwYREdm zsYWHG$_+z1YDLXT)BE5Ja0On`Z!)fb(&hFWuLh;ZjheQb*-sSD9z^JMlJ2x&w6h7# zz~SQED3wvc0#GW;v8;`)p|t#IS|&|l!&c-8ty3P6>{O-iv3x0=tTQFs;udcELNluz z<#KiLazYHE_N8f@JA@OeoJq#J-jDGGWJW&F_8eU-;xoc7CyHs{q$&iO&aS>zJR>$- zX&Me&%7q?nyfl=C{@DGFfkF?@<%1-;=anlEbjI+01n6^nkG8D9fUmvohm`W%b5Bp; z27O2AudU7s)oRO)AUr8jW56|7seNc5Ww~B)=E;vSQ<|H8Y>n(z{#VYEq8O z#n~>b^<47@l&~pR!_AmDzgdo&J{0OefcA?xw@WVdLomf{O65BCYUCvo0eni|G4d zzfu`=#9Skllv-0sC-StGe#dH`JU8=R9NMT@8B{b4Qqk5vBE(X7F8|rp*m{DVT>G#s zNrmP!etSOEvcsz;G`=+`s>^a9!YAY#a9|n-$JJ&|;So8KA3A{z2|~U>I(cfJB){kp zynnXgg@^KwUrNba0^ia+zivG&4)HPhU-yn9xzpe2o}0q;-1d;@^87@pwXZ z$iR977Pm5-UdV|E=?mtwjIbxsAZ{2eVwyALj#K+KSi~2XomF?k+4#d0Cf&UqLkM7Zu3q{1&P&C@L|KuB*Mj+B9F^u|FSWr!eo4Hd)ss>k@2Yi;p?XUB7-o>- z(|3l!ShE{xnDG;xTTI!GWN{Xn629%C#>`8^a@Qa#=Ey`1c>6~j1h=x#thMQGyPX!P z*LJ+?*|jS2pBX23eR#lrA$ssPxVRo?(-01o;^vft=)YMq7eDd!sJy~n*r_t|(k8S8ZP z^}Ddih#Jmn$D2+mG^H=YwNK|ivoCTca_3N$^KA8_53Ulou7z^u_5JJ^%4?bs4X9=v zFAb-Cegg;W9e-(U;^HJ>{y`NnL|gneW0#j2zbY`Fr~X%%f^Pc<`g)`Vhq*wpkllmh zFYYH#((U_nHo{UPXcy|Qc4NAiH4KRw7nqlbtSh?LB+7wnQsuRjUo_Guma9G%4KAZ)!F7e_qgD3gX@Nw*XJ(n4p8Xh^CFMPCJ>X(h)>x-(o-{?D7z)=t zwVgQ{+#IzWQOw4yQ%KwHXTBaMnjM;vL$8JYUh{!+oMC%^7*)u~)#UZu>OPzd^EiSI zt0qZDWd>Ksa2Sp{k)Iu;rFrVnFmlqe=!k~uhqU;#w|&qp`S6mC$zyFduTObCA&^yG zy`nz-j8>Ek`GcFE<6Hq(!(+(FeV9wKty4q_KB6B|L>6M9rl#J(wlI!68yam|p@>s= zJ@qxHPa#@8oeNbc-uGQ+VQrpVOYpB~c8HD{dHv2L$IER-$<61JB;u%k`G>gKQ=jUg zAMeIPkM)qCk+KPuDXrTZ_mXBj`mVGD))go)Rx3Yoqj9-Ccf{=PFo zqjCCrgsW79@v)Qwkx>9wS)kdd8r1n z5YDdeFpCZ$fJ!j=aXV&9DzNhf6Bj94D6ZK#Zv!Nd2~R&IbctNr27vSFn7_&k*21+c zxNl>(z{BaGBb#bY(M;rYE!3Wor%1%D?6=BYYo0?Q=LUco3oeyGoF&kh*qoh`svR30 z>$vr6L!nPrEj*C}(F#MUuMuHY0^8$&&)oLwhu_1~K+Dhol1I&D- z41Tpt7jv`}jFdYV1#x9(a{bO*Ef)h>fWpm_f6`EP`u8e5CW9Zm`^ureO;ulK znt><_DsWEB2#i1sI{QWD<}kq8HVyXAQ;;` zNAzl21l=a7wM;mJ!8TrnaWqwX4ikvN}V7y z)nJ8b-Ak9kQjCk!6hVl%U#H$?#p{X$-HmD7YY%fWNRIe<->XkC{riXmwAC2rIjnJA z_c+b3>Y-T2W6;eDuTUpq@*W#Vdg1n+i-Z>%T0!Zv2|aoRrRVu_Z)XrFG^?up z4s}6(@p5z0h`8|EC+PW1vp7Li z_IXKSb$|Wi5>YodfT=}^@&~5zGQTC=h|GX4D1j1!s-D}*F$Z6}KP!B>|{*x30NPL^m1fj zTr`B2p#oE9F7?WvoQZVO{M+kNMfbHiXKWutu=e>HejG0f9y4k(A|uS8D@HHt4+%UPF_NpEJ^jk^lW z6!6+B@O=9~@@lkM;fpZ8spe#_t64Q}#3+uqI>Zm@24CoBVyjsSw1L>0@v5})nMi(W}8j&%LR7_6V@qQQPg#RQ>x zeFIdrKGa5yelf66vU`6P_pDN?>opPyhROiks4cOk?#qp1(ekKNX|$~TtnPw_R|_`x zzQg0f-=NkBeXnU1Z=%8mCo+R55U&I=c#!(Rc%kIu>o+^Erajtc!)vudHz;Ws4l7%rBO%-Wno0G=5RS z=Pz~(PTZa{fm{E+S)eZfI}W%%0+7|pR4HO_S9d%6Oovk%`1@VmBp=I<0eIE?#Mox` z(?NU(zjYCPJb{_Z{>LpUcPI5wF`l5_8XKX(#Dgp|Cpo@0^8DJFbj$PLkeB_>G@P!w zekD0^cbn87?Fg{M&71hH+Y#p%7eoh~iEtYddb{Y0_~q6g5#%X``<;&j{(AYeUF&b5 z;BA6g+0DDzV;}LUju@|^y3tBKmxhAyyi+{pB4UwaO8wLG%gV0)#BZ8S&&0&wnZt*J zs_dMCF5j?xmM2ph3arD<#V9X+A6Cs4fJBK1vn&Ly58FPl^SX`4E>L0nC%nbylCQyj zO8%dGUTY4Li$`jujE(IA7MSdTx+wY|)y~Gwc6w_9XSF6qhA)gK%UGmV!CxWDACGL82*a#Lt%c z6WXen5StO1_Ut=v$~~929j1;m&cDxeiquZP${AT2JNBff6&@|f z7+WUFb4ZM(289lt0+jj4*v%-4PfN!gT;Q5+4|i3aHa}_ek=)y}d?<$TrRIREcnjQF zml_Uh3+nGb3Mv$6Bk#6+Sa?eungsmDYL?@|W=YgB(~T2#(UKu6oTy^sVUDjZZ*nr@ zAgb;tIX^fB*LJw)t`HQj0)>4=Ey*xwbTM#fWw6)%ce!=Wmx*p|L+A}GD%9q*uK0RV zUvA3ZfvfHQfLngW^Ia&viet*#2)`qcL}Pwpr&GQCx_s}G6$t?Vm1(KfDtnx7q^bi( zzs*!&*81QOh6(KqtgLgqrrXxI@yNSXvHa?lmU>@O6fJlXLP89=#;GRoOs>;$@(&cF zE616{E68(jzTRZiZZGcTJW`U%HYnV_!{D*w1VO1Szp*!EGHsUKS^`G>v?0nz8}M=x zgl(frGx2a;A&Psv07qCUCspgb$6&{ zdQOQwQ4m=md2WmrNv83s*YS=jefaI#T!ESW$ak_S z30JvUey04^)Ge6-oF!}ck(J*;l0+msGoOtV0zFz@$j0=Y^cybUhVXv`d9_~6S1b?t zD&ea2MviX5YN59M3!>S_DQ|+l2;oWQ*eh#HK8l?#d{vleMG{xY;+;e;p{`L!o@ZvJ zU>SdvLIC<&B5;wq+qkP&*a^wl$q#H?JUR9p>{_@B-X8M)KkV7O@?U4j&O0S%uWrn&_ zxm~GQt)**^grMcn9SURFLCN&bnum@HQw^Yn) zPZl(ivZF8uD(Mzh9jqA4Nm|QHmj+Mw^4F@^+4D_|z|9ZpROwXiS6;hot}+zl0={Hr zUuj6=*xiSELCR@WKa%OAe9-h?TKaH&a^ir{@c{c}fu^;E4x8&cty)|Zv!2$c7&fju zP}HfbUpzd7n*W43Ef@X?bK?DlIb+or$?PjnAT>Ea2R!z|& z=?E?vVryf0+OBR35?Hm~ZQ%kJYrvO;BguGRpH#?#EWcJhJpN&7O6P z$8PIO;q_Y1eJ5FS1CySQ*+#H>2WobV+Qy#U*RS{CT+$d}etCQU{x_Ib`ZWmn|ADx} zR7yrOVPvn4cJC|JzQS}#lSFq(8-v`W+@|RrOX`jFSTtR0iL;za0@w~eMh1O57ktf& zN1|orZf@U>JrPsxOEqi#U`IGy=+@zEMf0ntR>uGZFil?78A-DD=)>y+1DyAFPzx_s1*edIa(`rVu-u(H1xBX0y$aw)cJJB}gs5-dHeq z(JOvk9j@tr>`t=8IcF_}(3aIKYN_h*{Iv-4BA?~6U(Pm*N6d0P4o$RE&6(%F z1lO((F0H|H8A|`Hd8%m}lCoQ*|>eK5f1R^RHnr31l-rT)N%qtSoil9nC7~Zi$ ztYQPzw5-0NW7aC) z{;>}7f%O&FCQ+LL%NDMxPf*Uu(OygK$Hu+u9=6pMMF!y0xQwGlY zlz%U6PF@Onl)^HLi6`Xx;zGrogFBmq8tJOKso{8Z+bss#teQ8QO*B zic+H^85(gJvg5+PT^UlZa z{b!y#)lu}|42f0=9DqDc34SwA{4!-Vj~|F9?~1=O;LSsN9p1gXSFLsPo*6*60QoZs z3wl6I+3KPJ>AyX``(9m_SY4>AuovbrsmVc09C2X7>^4f?eR_Zw`rQJQG0yoA ztUqgqQ~P>CtvXH3h{m|{O|nl|e@y&Bs9v&}TU01x-9RTNKeG0JdqB)D)hh$@&o-Rc-5mDxsnT z?&z|8-QJmssMMpACS%@4kFdA1N+Y+&$g*tA%Ysm~bz5v|o>9uKmTYM#RSmZ}I`lhZ z-M98|OR3^JD#o4wZ#1>!9J8)YNU0pcmiOc)y~be}@@Af=NM_bX6kIGKueroy@U@OL0Habj^*Vu=6;by5}VWi#=gBv2LTRS&IJG33^W}QPTPrxyOGSoyNL#JT7qK zwI~=st6ah2@*pKavV-A>aibm{UFItT; zy$LWsXK{scRB}>t_9r?^RO+Up4Lt${o$i-W&N5O`Qqtz*+XG@(C>F!1W*I@DCMf)t@yc;x@Z|chZE0Z9aR1u*zSbzD=2ofrLrDFadbJ^wZ1Q;=cnZx0NdWJlDHYGk>ClYr+H4*Z z9$C^y8y4AE%qe$=gwA|u)kNxkjU`lE09(joUz}?8C2d&J?WR$WW0_~F1e!jvTGI{a z_2CYaK?_ilpTg-tUu@*iGvF_jr&B}Vx7ILX zYT-T}S+XvO#lo+j-hHm5;o+vtnd>r7i2s>RF_rqoF69||$k;-3KzA7~x(>LI^c;3b4+7)SWKykVsC*}Dz%;umS ze-c`pc|;|?{%}4}E9kRly?|Q5zr5s2-ifo?)vuGer-RsZD#*DAfC{tBx{WU7y&t_5F0jb^PDV>)gX_vlv(OmQm-TDxJA411f& zkbT}h{6#xBs9~*yp84VA9J5S6$!E#tOaEu#oS~|d)4Cnsif{Q2%$YF{ofkHo^#GfPes>22Ka+w+{0h~vS~gNKPV2o zjYKHIs=upR0k@d|ZXQtFo2->DT9wG_Z+Kj9KTEQ>p^_J!KP8#7j`tgY0^?cv8 z0D6U`Vih)04y|0dS*q9NYx$+=qeFsBR-gdk!A7F zQ1RjMtN?#DCelK>(v9sQ>?I z|GyH#XUS*J+OA=uMMZ+01_xf<$AY3Ds z%VNC5y6F-d_G=2*kwv>KCm1jHrf8|EKD{Ora3Y1xC3162zTV>h56ABpb`4Z%wvR=3 zNmVss_0i$HDxhKC=+h&`+UkW($rTL^d}_0tj3&pYl(<_r+5=YDblo>6nW~>ijgDXW zLVzp=1yHebU`j;Q_Puoj8S}n4dJ9r;=dc*m?j@M;0c?puwuci~gH%eNlygMV;V;2w|H=(l&Nq!&MxGsO>d8I(h&(0rfNV8Ha#tzTL3TGZezW*VEx zPu?@@>q!L}J325i3vA-mU9g4g^P!;N1DBRh9F;#)071MCwi>;s8m(HF_$cK2Iq9ZY}6y?D|Rs z0Xe++8Z+cc0I{1W|7Bk}S)G$Yu5vrzqO+u%mW%w91Kf06=E=%5PV1|tD;n?CBBIRX zdaG6~8ThelBG4m)tD$om?u|*V!D}(jChd0MrvjKDyNn|F8sLvUJA6u)a{Bt|)Ix5e z>5>eNz;Qru>7`8GtbJT(0tp@nBpn^_${{{y#h$nLqt8bl z?kLJ(`%nO=2|=X9fw({bDOSW^fYe751vYAYYW|X(OvwI{TPFoDrLR9Kl4$})bY(izU&74Rl$e>qcUWiAsPcphHb*OM?Zjh7Z%HAv(urKaLw zPPr}INs~#U@KHzl^8&zN21Vtsm#p47dsR_6d9utZseneh!n4h9cUlLdg<32`?_$L6 zs(8K=QS;hu`_kkkp^8s8$eB-GSbMaI!6@L+6=y`v^*}Bi{*d0yRJ$Pg)u>e`&XYoT zQTRDyCh?LC*>`{myCgd{rGvLM8+7rd;*4qNM!C#z!e87(Fp44%x zIZN_Sd&LZd1_Grlt4#G_9jAFl2G*&sP2kA>MT&@4*PHHbwMF$SAQT<%Yh)~*xv%j! zL+{xl;8+|VP*fbJ#knxB+k?%Kr=5AY84;|HmT&t+Dyu40lWlv&>-O`|6j4>~=uZ9m z{YN$sNIm2~D<}l=jR4jq0dau`8VP|Y;06H8gz>sYBC;g&%S(0w5FrrC#D5tB0o@dk zIkX$i7liu{6I1H^P2_^Oyo<-r1Q8K7F;A&&d7)cy@UNmtVLta}U|wb7!G{|Km&A>{ zT;Q^G)qfrV3*dmJfo6q=WNw#>j6Z1Qi2-|oY_IhU4nmn4oJpye1`gBW>YW;z zTn*q_j5h8!ls6z__I7t>qr`#s1QxeL#~E)xod>+EAmaK#PI!EH;jfo9m_9WBG76Q)qBu0;|+$2K) z)g-|P1(-j!+8d-i^KCyMadlT{&Z)rBU~2EgV1! z|0RkE=<*?`@i^k5^iJ$NAJ{v5SJ1@whreCMpC<*94LK{!S=8%PwwEG(0vGI>eOp5- zt>W2-L&JaSKADA<0xMs?-T^1&NAukerh=vUM|{A3K_oge52zO1_w!!4E&Dw#G4Sf+ z5pL*hui6^dkb6|dzGDS2)dA@!XfcV3Ez)p5A@h>L&jduLCqi#DMVMioBKk{rQNqpp zKm*Q`cnS50Ft4iy^(Di>w}7CH{uYz285ilv1z}jKOr|f^;1Dy_D*b!9$BLl*U7JC- z%E#37$$Gl>5KwYhmfkD@cfzRVDq431*iDhLYT50q?012Kl+p`il4?Q=Ecq-$rmi=! z&J5FqYP+Gc3_2NkRnv3xE)XC{ETP5%Y+v2kVQ6US_0MIOb!4E657enJBHx>e_krM` zPlTlu=FBSLKQUKt3_2dKDY(`>1XQ0IJ6u@DhK#yKl5T$DggwX^c~(jlvbcBkWC7vf zGI3E!9k@J(aeNBP*LsdyD3IbM{Nh4liz#@VZ9$O+rPq@k5Z$+q5ApU306jy4*Rpq% zAV=!`(Z%J$(0;72pcA}6bmXYbc?V~-WOrZx7s)~p^xKaIJkUh$Py+0hKgX0six`~B z@E1d8VEM~kh~?M4^`ehYIqw@imY27*QMeX$zdr3Uh&5$zFTMcuW{<%pU?vCZ+_3sZ z=qym(N78_t!~Y5tq0UZ*SBCBzKDPelww~V;{c7_@Boayy3%;JlBIcv%S%3fxp_HYR z>V3oAmyROfHV*2Gp5p=OczyD!=V0%s1gMdmjM(IWpVtIv5uiE>a)ZH5Niea{|JOGC z4aHBT&ZxLjKmY=1!BM=EiTl+Vc#utlMG5PEm=>55uWX(3GjZxxUOP_FwtUHNIrQ!XdSPD3xws5cCE-X&DpMb>+ZQdcA3Qb-cvn z|L37FVju^J04a1OCA-d2RxjIELZB(5A}0hId7av!u11!m-X!dtlm*WdRf+kfn6^cu z0)dPZJQIZa86%Pg(HsvcZ((q3LMWw0e3Be>P@Nk%VysJ0BV( zx!nCYUwjEQu#_Kq6-HK3jsSK`jzm}X$ zme_3T8b&5Y>y`iqc_KrN6ntDd^~*OrRWW&n7sRUjAER>YS<#^C`psdUDsq3*a2G!4 zFOQN5gvju}x|B0gt1{`O)-&4{+WAbAWms5mGv-^jwcXd5%@v}vDaqn}{4J;*@Lf#V zNf@t{6Qw|{KEYMAfoUOll1{NbQSG}@aDrT%iUlG-ho$M%QejSW<=pj36&^xRE12u> z?CDaeqUgGMa{{ip-btOr>DnUxhl~-_Op{v8#tBt!GEI__`}yzJ>YdVrXF*$9DQhEZ zlZ$_qoe`~hxzRvKgU#7g!bUaO>EeP>#CEHuLDAgx9Z2?r5;|3ABu8#Dww!v!1*q0yJ6J6gij-)FLDj5|yQQW1$o%^`(5n5yhnT!8{gAA%9 z&R#1GO5RkqGLhTWC!E9VZqPCnkr31KThH-ya*D1apoSVPF|g{S;^5hNpNe?M zcwS0zgn{>s1l=`UnuUX%3Y}=omS3~dLm&Zf@0L-bX{FT%N~cspf%k8bdj&02GgWw{ zq&fQ4xL8DpQ-hzu$zA`MEkMODKKJ$GftEUg@;s@b;C}LH0DJ)B80VIRy8Jf@RiTBw ze67r7ClVg=#N_6_aAM`G{BuKOVR9Sr0V=P8+#{z+SdR+VKYCQ6-^%2k@&S*MR;G^t zZMt9-h%>iJ7|Od?z&aQ9olOfeFd8!4oufg5`1F^UDMd&K?EGPZlJKau_i7AZHVPjZ zn8vZrXxeRd;$S#$y}Xvz<+#s!kE8xJ<3gZp%AWEPP%TpSwzJ<+r^{Ip9a*!nj0xVh zwXEqGg4DPrf5*)F1c7b0MeX0mEr%Xyf}#Vi+n?#gSe*BjyM!)L28?aaO93t1WRkDg zYT9kHT8}#+Sk<~-`rWF3Q=;Ve!KZUaeT}CIU9lkNCvxueb@}~z(lIu9Vtn*4OY!7# z^-SEE2~1dzk%~tbV7vOM54>&tkH4Eq#E|3eKyWQVmu@GE2bYD|00>Lgsc`StWI}xI zQz9eL^Hqw1R40Hkia5Ug-@p{Z5RfSWuHgdpKOn=ueS#SE1MFEmX#gZkMT^jsO3?hF zeI)^~OfUc_0Gys8~wRJi==cZ}}&>J-) zdVoYk^oeV|iv9O8>6a_oO1;`6+~WNG{HxhmTr&ns`F7yma97mv?obywIs@(?s8ea# zu5H``yP$w~3f<^^Odhu1)0Y6y2nKNz*1f~>ZR`!oGr#>S+6*gq@vTmC5x^M`Hd?NS zH6Ojp%;zs2y`Jnr!n1#y4BHgAWgkj(n0b+Zz`E^44{d z!5wuy5sFT$Ycn(ZX4umDXU`2uPduNVEHZz+Uh~@8w1%+M{--qX;PNG6gqdk0b7QZW zH8-|Eyz-{n>U^qGZX-OEiBC0atCijq>nr8Jmy{PdVZ)+Z)@R91I|B7x0(i8DO9%OZUKg12% zj2~O3Cd3H2FJcQznBO-?Ypyl*d>uT&7u(#yMz+>*$ zN4{87YIuV?>M;kA;P-=~F`7q)5%_d&}#!H^^mV(sRB6#@3b{ zz+|`ve{h^U495*&42=j-jQ<4?SJt+4(KaoCAx)5~6Jm(^ZC z)%d;^GKIzL?d0bPRqCBt`#H=Pyp97$=hY6gE&ih#^Vwg0Ang1|;1QHzYVmCjL56vA z1+zZz4o$f$;rUDAAs|=i9qvmxz#zkmQ&IGcstAbrftLx$$ICh|3c6W& z3z}trvFDC-&PCm6goVFp;c8s|p)YeXxADbA)*#bu5fm(Og5KgR=^m&$5LO+w(BCgx z*(L%M#e?}$f^n+d53=74%+eZ6S4z;HRtQGY3`(^d0w?tWhB(_;)t~i=gKJAcv+6Al zdqUfLue^MmO#qGtbIUMvrIqV<*A79S>9_((#Zbb;2>s@Hl6*ooIj6aBp2go>F1b&k zp@sBC>Yg6!`=+5BiPaWDpq2SKixcd_5Om-D5FdO86fQ3F0VPY|iS7Yf>0KCkYw_U? zc}p1FUO~n=`JTY(z4fJZ4Fu7y^J=WF2p^wNc?Tehx6I0c^@48r|0cZwTG-KDq9hR& zw4W(3BSUa^Dk%f2s5g$OG=3+P?9#6690t_0wG;BhKdS^W>GBy=X%P@ID!MkZov=~D z)$0Xl?-2d4LaxMwEDD!V3k{LGY!C0e^XYC8hR@)W@B$hVL+w$$TDYCD4vCo<{~2Qv!Lt@4{_Z0}-7&Ds@+KCJx3yT8k)$U z`xb^^dy{l3L>XiF_6CH(_M4NxDibZJ?b zX8&Aq530^j&(HM}AHwB-7fX~QAy5I>ZxzGD@J%Cn&Y}CY^#pFKRXq-4KLS=qjKeT( z`LMDDrkTpOxt~@|Yy`0^!&VC)CN4%T=kW^kKYQvN7tzThS$PY;HeTVya8w6G#u%Bt zS94YY`FGd_^>?@8Uub@CVnQfGeA4qe@S#*J3%pUe%^8!z%B@& zxl0&FnrW9Lue~bz-nqPkX$g-+8}y;RSwVt+mz7eMVxAzbJk5KWETehXlky(7E&AQm z#Pjd*8vE1TVu9kSO+g0(eN76c5p9#O4*vG{F3o@K`y z&%OSoxIL+Y^m%aAgBt}wXte}|zFi~th1V`JV-$4+TS-~h%G-%D7iZa3BX-Q8a!Lqg znfd@Ob(99Lr_w)|v448ZPf|_R|7tO}pBqa@k-r>xgiEiVi^9ujVcp-nR(D zPFED9k z3ODgWoZADe2odPvKhc&xcp!zZd26bmzv@OsE;qF%IX_w8R#Z+4xR~fG;d_3Wy%;@L zN`u`j$eN&s?x=t>iK|3WKS-{bd+Jj-QJ+$Y>#&mtg^g9!ujA_^vUTp5?0tT?6_lu)ndP=Y%knGH(| z^Ui&Yn`v7}xuyw<@TG*CLwdj}1%UO&=b0l|aQlD-2Iilj{-+GEAE*t%J_wY4zwAKD zk&rMImPwW%_#dL6zheQxo@JiveD1T538BECZgLRkr^o$Tl-O>`h~sk$Xj}J?%p1|&}?%&D=wMPQiOMt*Z0#ZnE@$sOMF{+%1v}y05K(u;O<3t+X-q$*6 zrPEgBAQkyA1F)O7JN@+tI&QTl&itS$dBkwy-Xt=r;#8S;`t zNm&wP!6e=s1yK*++bu_+jADj$*>B=<40MqSwQ$L7q%|2>gHD_b+CckJuKMf#Hkrxd ziQW>RB7=&`D}TIsCx$aw&BoPLp`hC{TerpT57|AE@~K`Rsub+_M}9h=9DMi(;UT%g zb7{-z(*3s1>u6fd5(5g)XsMgbN7S=j;>v_Ea=wr5V?y;fG_Ii8dD+_}27vh!*EcKf z#sD`aC&b7F|M?t=>ov$aC{6(6YhP7=q_P_cBKbiSVrYGKmy!tISCHDOhkdW6v-@oS zwd$_ljz#t%fkO8qtN4K$@QsuAI-16bDdHO*Aito=nXx|=*<|8evi9#IB%v=I-U1^!S-K^WG(E!o)T-LlS= zHJN~4*dLQAqB^%L)=qA+jHu5^`YnL3?SBzd>{JYD2G**d8y}-8bWjO z#~LHYwr`el>Ai)U%i2bqbOBO%8n!B-cSjOXR5a7_@oyqgjA& zR@^tfX>fL{)rNi1=PWTUuRH31?CPF2{r#sS;L{P($bXuaPm9{<(lJD<>FF;(ALqev z$9=hkcfyy(XA<9DK9&AI&AoM4Ro~V&i~NT+m3iL*9m;G69x2W@Nh0!NUg)5&p) zGaW@6NFP;sC!W-OE4e9rl58^zSSn=M(H2MO3Yt2SC62Q$vH{^+c;|w0vvBEFBWh@@ z1~?@EyeuBWe%$Jp2fDHk^pToNF?oWQ8@a;yh9cwO(gd>BJh;qA$!$hvU1!|-xEpYm)KiGusYe&%|s=gBo;;M@iZ06zz zuDTxj)X+!}Q_`vHdr!y58?4cng|1>pvc>VoP9pBv7%hPF*SwZJQ7+$8Ls6SUr{hIe z*5VuXW)qtro3h*vzj9(XM_ptosE!|kl4JJj#-qFK&;KPSm3O`@qqf{DHDK5+nfy4h zC%b2ljkD7x{l{S%AcrzL8SFxnh=A86!#H0G4}E_G@}oUG4cdU#DzqLPC}+q~VD_Yh z?fO9Gwu1lc;!iO*P1|JGXPd9_JMQgn4kRPh@a#3Q5#3MLzc(q5yv-OdObFM-sG{3G zL5#FkBjjy#Oye!;B8e*`rSh3pLYIbYmj6i~gQYq_Elbpmko8&j>p$AF z-pCaiq#1}Y1+iED8hmtRvu4_C!XYko53~G)Woi@CXQjMnD?8<5^UgDQ&>)$pt#9z9 zgdXQlxE5{R4ADq8#XN`_P5T1!47?ed7zeK#v>HB@^=#{zCQbwZLnz6#Jsa&wE?w;m1!rwW{2(93I)r^?=V?F`c2`u#khvJ7CAl zl@?=&qWVQ|p#f)f@2dE~Av##8wpve@abHnmzt)(IyPe!q#7Y5`q~l=X#&d~_vw>%6 z?`eQFVlY)H;bRBm3}rBfxX7lf55$;r-gJ^8Q<(bkBQC!#HFB73Kaymkx?Q%kD)Ytx zMP(EeH8i7P=4wM5ZKpLY$qR`%0J(Hu8_Wx@N8k`6IPkB!&PezE=E~2r<~AbeJ5N+h z-RFG(UYSi>o!FB}e2EsCDg|SIQD&7mBn}YTi#BYKC0d4=`~xjqgg^t^xD;gdY*r-2whfxr`F5)^zih= zJoA5wyZ`IjV*_WzViBVRrPTeFmst+;rEvAL`SKZV-&7{-QlM~pyxjv zYgO*hVaCCM?+8;^Gdz20t9-nv56_;~N@X?A{{-!_C4K;2vGm*Ag2D08Y=bo~1L^7M zVC}0-K2cv!3jzI&TBflQD8krBs-BN`~d47X^V-l~Rz61}M)1X!u zoAus&(TX|pp=IlUQ^YWF$gu*N^Dxf5AuWenQb9q+cCT3?U{^sI=!bQUc$Z)g5dNvZjM=Bp}KXy zGuHi4nU(D^%7cgl3U@(3O_e#yik0Rk{(bS*#pRbqCUC}li4)Ijm=BzSBuA4F6o{di zy<~8%o>{&-# z=PAyU;CMc41cY2SK`O~8qgfEb2T5e`!_3JnZJ)K|8NGZAU@%W^2(I|4at~vzBgk z_{E2q_rc&?2tdDFzlH=*CRAUSQxC}Y@>K1S-A+54`1{5g+YHFKA<*OOHIN7}*+Jvd zB2M%~%`*ehST)_)bgX&QwdP-qQsw;kDF!^TVO|4ol;_JUPzArpN?$Ji0VNpN6Cm*P zA?Qq{=(i&1B=58`e^<#JEa6cP;0}&sCjmi7a4t#|`0vZ0!IA^@fSx7^LJR<*imD>D z&f_nMimz&VFxQ*UWrTv{Uk@b{9H~S=y7k`y3)e>xkdEW3CVI4M?8TrZ2!aAil!*~r zfQbNB^(UO6 zl~+NeqB!T@9@CaOI9Y+3E>j}WH4%@5OEs1D>0fmC+p>d96lnxyVA3)X>%<_tc2brelwpu5+nY#!RU~={E5NfW<_T?BD%7 z1x+#|?dXEx%KZh8SCfD?Eb>NS08qYzLoBM?Q)!n}*g&^v%MpKl8@gs@@ee}osn)wA zYr3c%YNtK$FYv))x3jXmK1S!!I8=3g6yz8&;lOb6u*2Lz;Wn5RM~S&8${kg99?eIf zF2Ok9e_p}MudrDDi#bv>%@cLP3<0<~cTW{dPdhro7ELNv=DXLrG#iC&W{%N(T*aE) z@ZeZmyIIMGO-6Bxm?o7N&i}*?bU$uK-HZuN^E;sEm)P_UQvVJ|;myD&qxsRBl2`#V zHSYHoR?|bZeQS@Q2t}o%;8BooeiKK0Tx1F zXQW(3!&==76L!@rl<)%q`vU~ZqL1lRlGt{yVY&|rMrr%sWQ89KeHCxV9|GPey{zrv$ zvI4!}#1Y53YY2A!_-`mnYScm=zPj_2m9Q(H2Nm{|@OSn4xy8ygL zj6Gy*g7$4bbd~iFBP0tMew7eM#^=At9!r|8`Uu|utgzs`8$5=DeHP642O#eQL38@R z?9bM@kQk}olw=FZTe(Clez;-dGmuS>SG9h=NH^+f;B~31oq>L#ikGcX*!Jpidrsl- z!&COlwyp(YSjV!e_jZ6++Sg5m|J>l3m9#mD%&F`4AdY*X)@O&>lkkHmGfTjgDTKB` z!R3CZ8y7Sy{%>%2w|Ph5F`#Sdt#2ETlNoi4Vzq(gEXR*H_CU7%5D{k4n5q3Tao#*- zvE*8}Gd2Ts!^0qH23=3qfM?BC*^_>GID0**i>M>a>S15k)4X=mVp%6ty1Wn8cV08) z+fH63-IM{gd*(t=9e%(?#wnw+1!2{Hj_^>|=&@A9gA1qEUf`g`Cv6zE&NM!$TK_FT zuE-2_UXE!Z9ZTX*3ss%R8TMKWnMiG&F$9hqUCH7ncK& zB&iJd3Se^Rw_i~Pw`K+Z*c?uJn>?E<#TG{ho~o;_PxUfdsLQv^6a$1<&w!&z6KeWV zjEw;q6mkZ%phUTIdERn(v-Gg?pGwNbm|vBY+%KI8sJRe#PFh<*{nd{FK!sB(vdJn3 zIiEC6HY-J+oV>P6cOCHmHe9XgZ@RB|%i33YjvHZ_Sb+BPj)0jGAf{Wn+sE>rI097l z!P6WcsQjQ-J;u5KT`wWXHlh`9M z2OHcoCvVxgbu#!t#}?rBg?id$=2=W^vVU6nwNE{1_@+DdZ`Fyxr^1_7iF90u_QAia z6O*1<64I;7#R1=KHWrM%I7t3gzk<9? z+>kX0FP(zKKepd0`-hqdP$d_RvLag7lD(i1C|#xiG=&&w}oXE26S$URGchjTEI&OCLTT1_CZl!<#qt`oznfMTkc~s zpqni8{NpAA8Qjg*_MX<^`AtPWl5qXXU%KLQGr*PLnnc$o+Z5*@U2)7J_r- z`7ZJRdX{=X_G;sHYO8z!JdzT>4F6-!TL#G=&D{XOz44jfGsGuCb?|QFWQ=|K_y3SH zt0(#oIsiJW_=Mf2ZUd&DRU8rycCO~?t2RY1oFRRo;MKTa!vlz8hop|i#u?!I0FFqU z(uD8Y@zJRqA}Gd}BkgD5vD!C6?fRmY5-dP{bahHN&P!7Up=cawHJJpBRdY7X+ntaU zvyT$Tm;(8% zQWV9;$%?trq;T=+<!^ z3bJAfT|*&?AVYej+2NGzYu8VF4PTK)2H_eueoD__hsPwR&l`uXqc4kxr-{aGpJF$< zYRYXx=8uyXpXV2VKY6xcOok5Kds>J>?T6iegL~!((GJ_1$DWskYmVeY(h&z94+r!M&1iy3XH@ zdFBhVG6}l3=pP)a9^%uhU>!}x9l;|f28oJIEw#BN1ev!P&pKba2J>;8<+|8v5JpmR z-S@E1kk^{%_pPuEaiRRz9+fy~)kZySR6c)>N0uM8FI<|u_HsGl1!UCui{G57;L^m|dn~XpSotU?!}vu}K7uve^4id>~@+ zux#Cp+U?d|<%L+K++b9jnhe@YBs?hUq|~zDeor=);V%1KBV4eX*ZHhHNDRWes9-xM{5?3x<`~N3c;U zo)qqs2Ca-P`W}z%Xz{u9Z3tBE8$aulY-kvMNm#qg;cD(_tXw*1eeC14z|h;&pXeUz z_Y5Xfr90Y>zna%QU%78uI3dVy<_$(_Hs#O?t07z&599OnS)8ZCVyp4N{wI;kd1*|? zw-5CvKR6RnIS3Ycu&^f>PXsU;D-T^b3?*e|^*L3Ho2cK@6F?G;N`8T!S6{qoRAOuV zAWvqpfTzQ8{EUt!yDR-bIi8U{9*`o%j;1zVs}e8V;Ylwe7wO9v`!Un~C5tXNRxs9m z@jea*2hV9j0`xmY_4B8_QQQz=s?$k9#_YlVQaqM|^^t|%%G;hMwmplED8~lffq^{= z;*}yB80q^NTzMASNzG=g5%%xn8=hv3tsXnL1UK)$URXb0La7Y&+-)5v43Kx{nRk!Y zdJi4K6vbDUe;6QM>ycd}s|=U)?VuMq&-Uy_{j7aGT6VQYNmiMeog^D}0h1LW>qDq+ z@2au;LOVqF2{nCFuO*~}*cMd9#%rr|_ntb9rs}bUc`Y-Yz%N0Xj%YV4U={+NJ1`dnX-g)Wh(YS3HID-?uO585vlH?iZ6^&eT=Y3MEpNy`} zedf0Zqg1)y+JYM*?vNFxUZN&i?|fq19KbV`u01ZS&RNPIPQ{mXD^3;KebmBj98(@C zt|1|#1BMWaP(l(H8FcN1D*GhyWB@*t1D2hdWvFG{%@#-hB~LOOyLzou^scmsG$ELw zHplO2_Kso_25O{Z^7p7;41_lGOH;D5#|IdNH1FfKC-r2l_JwLF`RenIkCd_(I99Y4 zVl~0U6dT{-22%ys9F6RCc*O8DPR;x68sx9bxfMfX;@s1)3)0P(H^*yu_1ZW3;%uB} zxpA^zWv;9+FgEZ&WIyDYF>0!hm8Qw`#lm8Y`Lso()3hru<=n9Vg_UcjoJx(1;D!-J zNj2YU*>|-*g|r)-w(a`r%Wly$)y^pS5A2OCBvajrdrep6UDgDhd}HFs1k=lS7i#iZ z^;W!|6o#a0tl|=WNZ$Hpe-WFqC>fuanYAh6GEpP96!%9P-fVI@gX$p*=I3|iq>FSE z&Ju_GW{X?EaS#D=i$2v&Ffa_Uaj$c1q%-Vx33$!NUyao+%CW73clVFMl@Wu?#~d%U@jVH&^0^$JDZ^91B#fR zF(tPq0aHw->v(+Q&Lb=n9Q0*^SR$5N$B~TWyi1z;D1K*mPXgu<5Io;qY&=v%j>B~l z1IF6#-92ER!Dk`Xe>C1EFe<7-57i6cm%Rglbw+?OTo|%%2|ll4Ag$$2z~8< z8tdFT9E--r%3I@c0=QpsEc-Jh0^@vqI8okE5Z!+j8j2yV73EcA&4QdBh_#F%s@SoB zWFiUWv3}s54(u$H2ZM++btsPMx%NtItcJFx7@YyKkf$_e0T;4Nm5G%Ma$IcQGO?S_ z$=0+#X>?o>ok#>Gmw#x|MhxA^;%JjHr8`RGBosa4NzGh4pQ z68mx0u*^j)UV?#fSYoel_H(-uGbzw$5=rR4G&&p#ZS9j;#s_4E*`^n(ReROptc7>J zT!*~O65=d#tIK*Ox~)+td&~ThveWWImCp}s-?as-Iaohs#1eXSHIi%$lw$6A(}#uC z`$suWq-{R6kvu}HJ}a5?bLiC=tgwF8)6)e)BWx>>7z8Fj}O z^hYB8eKeM=yf<;R#V8W)aTiQcs&F2H<6v~R1JD<`Pm z-|?etUqFILZYU>Fy%&5yb@dN?xT~@wr?2?5l(g<$D#(76l5hVXtc{kD!qHpS5d#U=QlyVwjs-C`RX(y%Bu=*BnwNq8gvld6ZfxdeO zczO%m^LK!O$UZP)Uaj+;12t&4k+*9OwikS#GGHd$^Is1+si2N*e_IAg#xjXXe=4~$ zIiq3^87xw{ENjBm*JRsJ6O$*qX00I`J71DtPopqvK%65aUHLE$Nhj|enWjalf!uy| z6BqgV$Z~EDVKHPpT`j9ErZGn>pMt~sK&6{~?p#5?(s?P8Sg`+buE7$dKtg`%^ z;VKVstpCBCy=~qtFX42wFO)PXM0S#et0Ht>xO}tWG-p8l%*LrtD_1lcx`zSE=Ze5K zd*d~6w+G63b4ZIS!6vH-w_M+-ps=Oy+x3Pjoc38HtW8#@_``$NZv|7KbG)6J(SibR zZ)6C?vW2i=lp%@g%3}qH7w3&6KGudVI(-=elARyq13NljvXddc-KI>2ul$d6x|{iT z?F2_l1?ZY+Y(o5F*ZGSC>{(QIR($oU7PWHg{MJvk+{S`S=XnbYwXys1zmGA>sVs98 zID`w&5q^QLeWf^J+t%%3XL#{I{y_Oj{$KK-UI{}RFu#NnBM#j@)L&|3DL_vUlXpYR zV`&W#RQG;c#+)XR02jsrt}1E72nckpCp87qAix-wpwEVWM<5a{!>o&x!@4Z3RME(` zNA8x0$rS&z@=K{63KO!os$@RBn@hp{@?Y_QEYBFhtz^&h7?W(yf~8 z2o-X&0_VnOQsf2woMeyKSKKgDm+x+0Cr!Y;nyfR=YV%!UhT@wtgsLp87yL^c2$hbv zwRm@Z!1_T>q)M7PePuIBgPU!-PfB~x-Cz|QlP7mDPrUl(4h{3@#RVUK&r6y#lPX=) zNPc;XKCY*7J8R#&4GkY-(Y6MMQ00;EF9TkG2(MMI74Tuy=4{x^u4E!*B94%5NfcDK zFr1}glL#hUiZWa^GlYxtYkg;V_jB|;Ra{_FYccc$iic`dd5iVF;Fue@sU@{%|4Ls! zqNXP^J%`PmWNtH3x>Qn7nk=U>FQsIKN;xYJt`thiD0r;CF6i`LbdDY(gqPZ;bpXz6 zF+GstEZh9p14&Xw1%bIReh}4wb^IfCkL9e@$@K1J{PStM=zbo>VJ3x<;;clCy4Gh+ zJGOo(I$+1z$y*|g0xUfU`z~mHOhL)Hq&V=<-k*vH{%PWGC<)^H2z;;wf=_jntGHk5 z{e4ba6Tvymhge9#Oq^m-*K-aDyo3!qj!w$Ci((_br|Si3k(T8JN;0iSNROqqVoMe( zm4d})eDR1jYU3eM-F#Nm@{Zg-JpG`aKpZtZ1A<+ZF%#fY_jW}$-VCYrHX3^G9%hqN za-g<jOd2K#R+YRZfG+Z*6R# zvk1)$dILX;AX5dA;+ZK^(mE@s1rK#zV6B(`-!&z+~K2$?9mynx#K^qbE|o8f{NORM za()^M(A9JMbaTnk@0KEYlOCbMw&T?c!xf?C?>j^stWQ?LxGjgYoTqOWKBI9s;bxZA zg({zMdP7M0GIdA6_z8HI;6g5!8Z6Fcg1u1E!IYVQlJcoC57A)?Z}XvR-F#+qcK7?6 z!rPo7sV*;Vek>&)L*r7V`#7tPj$0prkmO+x7p?UYEKSw6H}>h{LrfysZY0&dvR%E< zLxLR}z24$u#v7N;_WSemB&{&;i)rS&2Ewrdm{<-P>o=J)&(=P25d#pSB4S zjSOy}i-i{7xukn97o%{ryg~^!)*s_1&*$*2jg(RThV2 z6YeFSEIN!MHtIsB_J{FF4v~J%O;%8IXTKlX6>^#6w9^X{q97+w?lrU~&zG8w5Vscc z&Q=TTs892%x*T`XZr8+o-yYvcIk9GDDz8^^0S}~O3zeRd!U$)3IoZu^Wkx2IySJtk zr9^&)+7UJ=WHRcVD{{xR+3v#Rea|Y-iY(YE{EQiaL)!bK*ye$|pQ+%~+SaN^|L{%( z6>cn{tVND-9cSvmTOvz-bq_vBH{WWxsj1T<#u9H@4O{GFaj9D_JsGPO8tjGs zhrVd$0z2YTqRcT`Rz0hxv5$T~wYP3PgM26tZH7psAFSES2-W+D(Ver5?(#GDZ5B|BFmf8*3vj3#+#N(q9U~YHRA}Q-2RNL+SuF7N;7l8Nx2Ho{)uG z!tJtr!Rxm1^6d>~@?0S@_K#1GAEZnNLZTkfN;wi}pF(Jd(w{{Re15HUW_W8L)Zt}0 z_?0XF&wJqf|Jb)%8!6`D18>AZE;jZA^)kzQ2e@`^j}KN1Q$f|}%)a3Cfl`OV$-TKTuM?btZN48MvnZ&lIQFCl zt2<*@$AMw*PiG_j_V_-oThYL+E}{WWh^ym&g7a53L%6l*2tHuanHB=)qa@ zUI&|TmKi+@dwj3_fS*haBgdd4OB|1sx>ea+{Vo)%`eZR2(x2a%7Lv)Ox$c{NLUen8 z7UomLkmg}Gn;rwb*ePH0d{ZH%eFA)hiLqDG3Bp#Dtj|1T&R<!4b;+(T>iKt(V zTtXeBBk8V_55~`Eie)wR?`5UrBU`AvHsgjXWkCN; z*`i`=y+KZ)4frvL*>g#Yk369NWk=mH`Q)s$>q4}V%3~%UMIIg9*$uKNwYdNNw%3n# z9p%0SO`Uar*MomV30&W(OkxR3J*7wz&H>I?;pEkDA#&7E_78s`iME;`9dvtIkI+k<+So-5h<= z?uX}yv$JzL(ABRZdv#;x>h^I@Gzs=4ANu?W>!Ts+aVM}|+U|-x46-E{d$p&*zv|Fq` zdtP$in52;IJ_bIT&ZthvmI2BRJCQP1OoVEU*H9s1qk+tS`2Jtq#~n*awfv^M%VKhP z<}p28tkHmhj!tSYgEtfEOlCi5tprHvKxz_YzfFf?T!hx+Xlo{Fe+gsxJUXX$%%u=G z0*DA(qRRUQo=JBQzWQggYIi1cp9WHRM-)of0{r_@x5_(X=$vNB!0jf&JFc%02th#< zK4()B0di}T0!bHHpQ=d_rb&r#5U@*(=8DL@0wSq;YE@%h5D`2P#jaC=%D38{-7jh5 zLBVaVbC@qa`chrPqCe~8SNd;Pw}tmy!zV+i_Q{{@+p8eFxNRtj@T%3)!+>J1#kDme zH(+HU8v%g=NP-d#m&8t?ll+0n9TyrV6^x4jq=&BXZ_-u`yd9=q(twkhd9vL0Gzc$5 zKr`YAdQTU`r`S~>D1-LQbsuc8_ws`UrBkt zz+aIM^zdyam?1Tu&%snl3Hw~Ye*P}dQY2g{$}J&qX)wXllJJ}H;a6zjDi_|NGW-e| ze(!Z~#ROM59=KAv24u{HU!lRJM+R4_FTlf$;41z4|38}gHUm`QQmkKdXEA4r^0&}= zd=5Wk%WWo-aV{u;oOiE@U4PdfaocHq6d$~VBhY~2hNk-r0s{79DREI%2q3E53HLce z{PiUkJ^T%CfhX_5m8A#N^9mJQEy2|z3s)8)=*b9vRSDE{m;3T!yZIJj@n<5O^(-C{ z3Q(JR4cz{GxGZD3f0?t8g&1d`Z!#_EI>H%{g!0Y>U~+Wux$NnP78gq=$^*V$C=n!Zad~ zV}=vb0TsUey1Mq#e23};P)^eDUPm~BzswP!lq^1df=(n@W?QSY#~zdS#0Cjr>n0Fx z>$vvvv^MZYcvdqFJ(EhLCUVZ@Nz&%jOM)qZ^eHO@mO|jVL=Zkjd+oTPMkR5HBD1oy)U}7d+C>+o9v`B z>as>VWrM(i5P-x&N5zr%?ugk*$e+4@HSSWKn@#@91cD|4=p2$N_lChLT_9@3H%4eU0$LMMoV*{XzE;k4X8sAJsL1x@x4@>tbl~_h=0n;^V$5 zGX+s~c8%4wb5xlS;e5pHkTGQB&`D`me`cTX`<6D7tT#1n^Y@K@wR)tLw`kiA@VjzN zLlPc3h6?$K(S1@(x0QtYxXU)Cym}BpZYoVH2XmTRKVz7kvW&MkKkLsGc_Qjwm zLh3wdA=|>5=W^kx`lQnewUEa4jZqoOeNyg&@>{VX$b^6O^`tYgH1M{*VSZ}z8cIWB z^RC*__bgjC&dFLw>Joj3LiZC0XIx(oXY}yyCq$o?RKb_zE@13J%#==F7pRBHhQ=)0 z1@gEduG77ep2W#Kr6kau2U9i%{wmlSIv->eB!dSmCFQ@;I_1KUw9jGtY)Qfjyl%_d zJHa3otZ%op1OmI!(z9{1u*C6*7GG#smYg7!uRQ{MPAZ5Q`|!Ije7NoEJ5b(YUJK9~ zh({lUZE&&1OIc_0)AFt(Y?XWXqRvfS-)Hah0ZaAxC%tBk%QI}|O@1e(G0pLYsfdTi z2)j6%Avsk3=xLvlwq`>B7_%Yb;&mvI7M8rN+dMViu3@yT`9&)WGM-$W;;&K5z`OEx zpwnSLj>jwY4S9I>2T%XhEcM!L`Q5VhBYk(G(dT;&AcZqa1z=)4k$%NeXEN(FPu#Rm zhzp4D1>%h^Rq%~@3IpWM3ATZI>2k1AHCLb1O_x28?4|obd7&*Vsk~zXS_KW5-*uGP z^%>&&Am{mrx}palJ;##(6JGv$)IgipU00i;E5w)J=rVO-Iq9k~W;R?7vQukF;C-Zr z3s~nFe=o^Tynsqg` zpjv3>PQKYo$@v_Ie>&Ov>*@j{Z?V2UyGXN}H;2Vw$g<_R`a!g+xVz_|A4qD2D#*5V ztaR0u2Bz7`Pj)e>fuHUMU1Z$8M0*~0;U*f!ZjUrBpcL*zjJ_(jR;{&KW<}WNJ6pV( z%{8jx7{eWH%Zotp0=$lY@zAVaff_*cEXZul+$2}S$#d=xyz*qgkK~I?>!D{I1b~Ij z0F??q&8ZC)lVTDoJBw}NV8B4tUiYohBkFB!UH%?&OOn^F%IfAmL$(APcc&Q=p(Yr7 zytXt~1{6LyAd=d{`ai^~L{8Qi%=q2?)J|lXAR|Rj>yFtQ9kxviABMBJsEtU*=N|_noG}bM9N)rEpt-;2S`|gi}?!395K$ z5qEEp*==)nO?(P$b2(U(38$|}az6c^ZQeGxu$*}Ng#Ge@VO8(bW>`NDvGLPmXGFtm zSN7{0(}z-e;Mn!OG?x^P4vB)$6Y8H&){G=hogXhZ7M!4ay^eLgcriOtyNuJ|-YwrR zw{8ecxt$hOKbd{niFjMi)u>`P$+PO(M+Ep>Wn=!758w>wN(8`1vIY}Uj&+VnAlASf|zi!bSxY)V{Qb}4g73voWmd3U_>o>k$hi@rIT9FB8 zA+^-J#y)lQ_ zZ26oT-49A^)1)4Qg-Zbv*PtRPS8H*jru+_bRALYA6H|2;?WMc`pO#LA%iiFl?0Db# zkzl9=$?LLR#a4rGb3!4RzuKn$(4y!Hug3u3NtX0KGruJUBxrmU<|N9mA_YP|)SqC!OSBp9X(NFwp=Y|`!WM=VTOfc5)jLYHm2H+g z-MTVz-Oo#Kw>9llP6DXn$Q$%F%xdZWC>`3Mat};)H6)_3u*MmBYcVg{t*m zj3h@3cyL`R(#~T+t;|nXun$LJpLB|EAYY8W*kX#?^1Nq`&6%2fRXL9UYCYcVE%RF= zAr`@A`>bP5x-RoX`0!f1LMI*lZZxLZl2J?;vI=S3-y+Ayx~g9u6(S=x%V&ODO4xlO zo7B15=*P6qw*L^80Bv7bD}VK8B7l2q7c`aD-7zqMIqZY-0C^gJ-3|7}Oc0Ro-T<%~ z9jzMS*yrSb5x#pBB#^&94LP!~&3h+3krfu1C9L5;`NLWr{~}NAR9>01Z^Rb$_j2N3 z-LCdt8-J|o?KyZoZ_@EyWjh{?z)T~)waw*s3i;J~!~ALoL8j$;65;icEia)8JeACR9mkq3FW$b^9uG;q9lIH#H2GnjV+ zRJVdU(PaaDF^|@cew+5JKZE(YSyjaSM|C7;YBUoAyIzuz+YS7dWPX>;&edgK3xI0u zu@_fl=oDw2PQArsFaEO{L8XfqfKJAyL>Sa;yf>r!_t2TDy^n48NhX?<-;|MGzSUBy zr|-{quHMs%FtM|Dqg+f454xBC?M=*)pQ1Gvh0GDSMY zpm-}Rk=rcIE0^+bsn2mMy1{-;qb6?bVOtX_Fx6=@L2#;-=l+#l#o=9ec?( zJ!>(@FN{+!k~| zqD1p5UbNv<>_`5;-tqpP*>(>jT7K{Gv(u=I_kNGZ|6<2$XlD4>Pkp!2{d{LCU-bji z@6dQ*GPNeBNVB*oNAXpg$EitQ|BowI1-|tAQ&S5hl{Pt ZYqiQ1kP)J0MQ|g6)MI(^qDO{){|9QKf1UsU literal 0 HcmV?d00001 From db5a720a06bcfc5a78b28678bd50d112bad8091e Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 14 Apr 2024 20:44:03 +0800 Subject: [PATCH 217/274] Update class diagram images --- docs/diagrams/ArchitectureDiagram.puml | 16 ++++++++-------- docs/diagrams/MealListClassDiagram.puml | 2 +- .../diagrams_png/ArchitectureDiagram.png | Bin 23068 -> 25087 bytes .../diagrams_png/ExerciseListClassDiagram.png | Bin 38300 -> 38757 bytes .../diagrams_png/MealListClassDiagram.png | Bin 0 -> 32942 bytes 5 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 docs/diagrams/diagrams_png/MealListClassDiagram.png diff --git a/docs/diagrams/ArchitectureDiagram.puml b/docs/diagrams/ArchitectureDiagram.puml index dd1ecacd63..e61946dafe 100644 --- a/docs/diagrams/ArchitectureDiagram.puml +++ b/docs/diagrams/ArchitectureDiagram.puml @@ -14,10 +14,10 @@ Package " "{ Class Parser PARSER_COLOR Class User USER_COLOR Class Date DATE_COLOR - Class Exercise LIST_COLOR - Class Drink LIST_COLOR - Class Meal LIST_COLOR - Class Water LIST_COLOR + Class ExerciseList LIST_COLOR + Class DrinkList LIST_COLOR + Class MealList LIST_COLOR + Class WaterList LIST_COLOR } Class "<$user>" as Icon PERSON_COLOR @@ -33,10 +33,10 @@ Ui --> Storage User -> Date User .> Parser User .> Storage -User --> Exercise -User --> Meal -User --> Drink -User --> Water +User --> ExerciseList +User --> MealList +User --> DrinkList +User --> WaterList Parser -> User Storage .> File diff --git a/docs/diagrams/MealListClassDiagram.puml b/docs/diagrams/MealListClassDiagram.puml index e916180ddd..ad28c544e9 100644 --- a/docs/diagrams/MealListClassDiagram.puml +++ b/docs/diagrams/MealListClassDiagram.puml @@ -34,7 +34,7 @@ Class Meal { + handleInfoMeal(command: String): void + printAvailableMeals(): void + listAvailableMeals(): void - + getNutrientDetails(): HashMap + + getNutrientDetails(): HashMap + getName(): String + getCalories(): long + getCarbs(): long diff --git a/docs/diagrams/diagrams_png/ArchitectureDiagram.png b/docs/diagrams/diagrams_png/ArchitectureDiagram.png index 49d782a3eef9bc5cc327a8b0d3f12ceb7d196bf0..16c8fd78344415e0452a049889ed63d43da3e749 100644 GIT binary patch literal 25087 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 TT?YS&;WzCw2B-7XZG-;<{=}Gy literal 23068 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 T(+LOTo`1NerGEvdc{}t^#f8mT diff --git a/docs/diagrams/diagrams_png/ExerciseListClassDiagram.png b/docs/diagrams/diagrams_png/ExerciseListClassDiagram.png index 2555340922b2be2759442e3b6281cbfb144e1461..85c08726fb9c964f33c297d6349fc09d55e1122e 100644 GIT binary patch literal 38757 zcmeFZbzD{7w>G+^5hVpg8VPCX29a(_32Et;1_=o%3F(mTlI{{El@ z#>%O$ixdnoY^I{_@W=O%TVNcQ4_j(;HVfRCp8dM>namC~#c+(HbWihW-^7w=V3uxu znK4_YRxUNS?6WgbO!~)0~diKW^c=0v!+B-rO@h#K4>?hl-2vmZZVq38#uBHfkZXgd^O3 z8c-`e$aPSY@J5S@JMQ3>X)q&F0ZHy>0$g$h(FEQC626zT8pj?8;&g~rw6VUz4#f27 zUYi}64+`FV=vQ2hU{RBl?S9AqJ#9X&_Z9p;n<>{Fp)WGVQOPe`mf^(QGK<}Pm{J+M&)M| zguTQ&-zxeaP`zTltM8zZ5kzrh$-YdZ&GXoj&aUx`5tBW~p|MzEic93lD1E%6*?5w+^fB$dP6*J!wzuh%v?y z8TTb#`L zDxDhX=G@VxiJ{+WjGz-ZdQ>x2Bo@!eeoevMo<&=KkY8tbtj^NKWp583x^|>}m1=n) zv(ymjLDISFe23!e#+u=!x@ufSKG`inxU?a?l7?JQ;-SZ)#yAauCsjCi%N7~*(CB_z z_ckEXXcW~qsbW_!QPw5M!SCF{K+{YO%1Xsx7-1VK?S5#|Y$0~xBL2Qw{9Kghm0R)N z_n?j!3g1;}{1Xk6%MFSZLvV$kn}w1MsL1l@gc5wIdZb79eV0@%BlDn7tZDFgkiucf zZ8o=WS^tEGK`3B(we*}QHudUapKXadu=&`d906B0)8C5vuymVIB(~*C3S- zzuJ)NtBB14cBW8ufv3$=3Ickf1#;>b{@u0j6ZM%g(&A+UJ=1Sn;o6dq+^NZk%U()T zf9bAoI2!lv4jHz{v15A{f4lCe*kLwZjI8&AgQUA+A=ic)sf6Y`wmx#QB2IbI;!+W= z@i8th7M{+sK$0p5#2X?dDy-t7v)Sb8pej~>)B^8!#}D&!ge3eeRD{o%hD%gDLt^1i~WqEp}*I!2R1)YX3tdL|PuI zs`8bb)6-j!Cq1_3UE!hFILll8t6+4|{)&wdWN-)4mgD~6>Oo-D!3ik}HiS&jo9u*) zOcLVl0`Xb$^(MOoS-6D~i2>(>00~4UlN1C?I3B+$O80}ZDfxYvW*->oOQJTqY)zC+uEyfsW0|R`PMcjA{G&_DKa`VloLd?qs`%NQr9w8RB9)ZT zZlATBUh>R_;;!sWjF&1>sM0FzoFUur*ai0+b@lTFPS8~PJ?r%0ZuKE^723r^9()E1OM3@#`zjX_f@*eq9Uog> zi>hMN46zlE6g3}Cr>Z$@D3bL`E(l{kMchz6--kNYxfab(3(-q*Q?uVi*n>y-hWv($ z?s$1#7~Ls)ec+9~?s<_cO@C=eA7YbPr^#|T8$Q%&qer=EzYm%JVCzJHp4o#@uCu-j zP5{0aS}L-o7p1$!P@ROGh~#s8Gjnmou%k~utF#iUOldux$0-Fap3j#TwPjJJ1gDs} z)MPD17Zlcv_`U8B%SO(BJ?>5ZQ@uiO{1(^AsHOG4hJm1B3%CaQL=REQ-6IK$rmHe@ z8?8#+Y_M|sae=R9dH?)4DnVoNe7?iT)2e|p-Ha@d^!LtP2$XIuCCCfhMt}X&b=7C~ zoW3D!rhZ58A|I+D?da~=|1hq_ezRlZc*VVO#>n%`i6y-nK9K(R-Ms?OH0+~BOn-bE zR+&9qZE@Uoq&ZU**(-Nc=+#gGat3mGm(*0c+H_HwpYsvQ@2oXBpJ;>b`Ks!8xvEZJ zC!+qnfuj3~e@R}W-sr% znYl@=MoTtYmDaH+EhA*!5VpXwN?$)GrfrEC4%@HrVvDEf4+=82}0U9 z!HWGB)v}%L|JzzeULAc$#*d4s$V77@u03delaszj^h{F4x@zr#Ds`m=n#%-8&s>2Qk;8&aDt50$1loz*$SNVQD;y!FY z!o|0#ywv7{+RF)Oe7<~0TG;rLBQ(Q&u#$&u%t~N?vPN0WdV!B4HJXzH3JudevD>aL z-#jF?93u;hEbTXbKqbsayOpluQt8rxGc4oM;J~X?W#}2cs;en7x__V>1{B@3kik6b zuE+YUbc+5)K`%TB!Iuu{sC`=X*5%WLdxH%0vw5t)^nXvDT!yRwrdT<}(ywvb={&v* z{9Jd`S>_w`^Y2bcXvi|%*hKCOtJ#r4)pcEkpPl8b37H5z(nmaHmupCI7@@8hQ8php zW(&nm4~-#tw`NE4>}){9$b9}w`|$e$il372BO;#oM;12#k9y#QU0fxhP+GR}sBFgW zqTt@1pn0i?j?4W02r5if29(Gn-yO1zkX)oHE-3|kE$paBbuVa|S%Z{}P4(5L(U`%8 zl+merFHMG1b6rS91>702uzZ~LPuCC572g<^?V@_wrC-h$maHB%1w7A}%|Eu?bI77A zTiNBSoWVyYOc-Sf=ye1xA2=aPdtKE%CwUz%K{cXBD=!f{e<^Fcc2j1{bD8(YNvBav zLGVT~fT?Pjjc2}ybQHVU7o&lk;fAX;uob{b)p;n;>c29N0>07mbfBZDwy4o!r`gNp z&~NghqD2XF}(d9Kl97$myt;+06__W#<;0C`N|9$xKaq+A^OR ztgBNoRUgyC&7_r zX0tqZ9`7cNIoqDCj7n@lFc~?UCgxun?mrQ>7Vi>r8ni&mHQ))e-x^lu%HS!dWJRl#(F8bcfHQa*zc~_$ z;o+8i_=1=2?)!qmuDOhPsc*FGJ4K;rc1v1Qn&xyzyXoDll7)ywYA#!YoGLWm25}K$h3%66FZW?`g9W&ZugzilUv*0h4XMrUd>Z6ICZf!0j4oruW zS&E!}rO-=F%g9eUoITGqF0@u4wb$T7wjunOE?6~cJs1C-gxsn@svMEy^caEKR!O@c z7?+2?*eO4!=gwDblHSl7zjx;SSjdMJpW0MVchQ#04*h~Ph zvC)^O>xf{5(fQgxYBz=m)Ox8GSW!g^KI@G27T%$SOTRvzH*(UNgAG(IuB9+jBFIVyS1+~89sO3a=y-N(a7#aI-al{YY$YRLfkaPQbSVr5hFFKs3C9IH}5r;Z% zHG=itLczJ-?dp$yt@YEGxGlglmADJ`1};a0>>z>X9uor(35kF6c}8% z_20vV{}radq%;^#@=_$c1t~)S!(bJWY1BV!@K-Q3lgpIdde_zw+P)!k7Ct>_1EI%1 zzw|695P?80Kf~bhrn7mB-q|=yI-|ma(R_Di>k2u+;Sv=`R;0Y4fu_ zZ7!9IT=v0p;w(z3GB8!rZu#Pqx2;&$S< zNY9NBN!3|36f1LGPR4L?pPFVe;F=A z)gr2Fsl-S8Ih5b><$&icUl$2i4(aX!;ynv6Ni|_)VzZbUwOkl{dzWy}>%GCVm0TYfaSAHsw3XQL(UO_8m4cLY!sR*FGnZW4P>Wb2vB12xXw(3KM1}# zudoTB!=1f469==NP)b9SzNCiYcPTC_jY^5b*-0Y-O9d}wXa#Z@ChA)BGeyVNSlK!S zwWKwNt!Vn6(a||?D3)$dq_&r-^lrHZB;r86KZIfEVRY-yLt?NPK;}rTTu|mvr8L#! zxposry^GuMyA>dj?FZa1!ST9BY0%e|m~?c9I3+%Mgrx=fO8C}J#o<~Iy7mDfr)8Tb zS?2>Q*24Mtt@X(EXc}6on68J^_Y~B3SuISSIgXI#1~Wn+bJsrSbuQAo(U_~*y76QK zGy#%gJ~yQ;RLCv}@j+-Hw2!O)?9yFSmujor(#O5k$lRkcC@|>_vFUjt+UWoJoMY&auV}Vv6~K*DlPzQpmElB z)OSeC&dx^PplD!lgTL!1T7K<7r7ps?Pv%?87J)O!A+O-v9Js9%E!!nWz`yYMskd6}XUAP?eFAWxfk(?tr-^ zq8h?{cvbiFsU7Ew<%e|rQ)O{it(##d0x4c*a?9Bz-ThuX)`w4_J1$q-&iLCPax1V9 z3c5(uYJ9c%u5KhXx(J{XK{RI3{;cWf)`v`+&_43}g&1y@o5v?Iu8yC5;z(2XDR5J? zcZUF$rn9id9?>7jR47G%U6m7u1kr^_mD`%DfNW6Eh_@@P)8EezVfM||rji%*^yvIT z*DJ$)@{M6*GJb}MlJ&X|@xBjQL$y6h$HqviAl`t5u#wWFniZ54IUhij9#h{5uS3?V z3Rd0X_3T@p#&5h^0~VJBNs)FXp-JdFj)1xJ;zrwvuK!MQ4$!@KO~gX5 zka-%L(N@@>YxkM4mW8V*I4=g`2VgKuyn=IE1yQ_s$Xc>r6(j=`H0y7c?`ms>z`uB- zsZ5OGekpGrT{UA^xS;jQz$azp=4Nx9U3__{d-kK#9D7R!-n*m>2Kz0!njsw<5I@xG zGkYKHu^KWN(X|Oj>Ux*)LgxQZNq|33^|m0gRu(*OZWxF_QH$`|+QCj4V`<6v%}>UH z4=a14d%3-_FcZ)wE*Qd13}8qE3=)OwIY;Q7HHbD8n%ixri4oyyA~D;JeXQAT}8G0prWFj_%uktbv|A;F$vR}=qval8521rKK$)*2o1jR2uR?nSMQAG(t}#Q855oU z@4zi50PHEuODG>a877T9uT}FW!!szNlBrip!T9t_o;7h*?o(j-wKVfFb<+u6NLyMG3jEnXzYT zdBw`}tmL)89qGQ?oZWhegbLP!k<)ernwfTj!D9#FzZ`jmFQ3r0UuGXm(n0`H+&tLZjS}s*V=>dGRM^6;Q zcOOI~GEF!>(T?{}tZRw}*F{yfaP!sYn5icJ*FRtA3~VmC-n)2u3EH2rSm zULEQn=8P`4&OFGcp}U(K9H?o4qDIA(v&*Zo*O$4IR!m`rnmDCVN31aYz}mDTzBab7 z6JkD7ED8VEbkFx={5GAlSxfgMyzDIAm+>61&p$TV7 z*?wh-@=1QS8#cADnyQi30vj~@VIS89b0%w4{iylvRtzR4dXr_u2J~syxhHCzj3SjJ zLZF~V+|<#ht1=Jfltl?$&}cd zDq2t1Vs5_8C4rD@Tbv!cu|+wwm95Q^O3hoG7!aa4P#snF^ zTtGUf^5A!TWcOU-j4FZEg3n^ShtP^iaK|!Ho>g=_B`|c@^$IJzS(+t8 z(2*k)r_7Gm#Ea|$b@r>t1T;`$Kz?rv9!?0iV_emp-dQqxgppF|z)?es`sj~Y#BZ_@ zl%0RKW5NAHGV#_HGWgd{qMbm@rJ<>=Ru0MMbXX@UcJ`eU!k9tDok6KsXnXhPvr-=? zshl2YAAby|*QeKeuE@gvG3Q$Fc>jTzB3**EvC+&rsg{B)c6V@s}TX^GQtgPG=r2q9?^M-FPUTl3! z5ATnPD`EC@WxVR@TV{p+PFE^?uesg`HRZB7!P4@i5S!onkU3nJUu1Q!+ggoDO|B+1 z=w}b!3!Xp_M`ckJ6={d7a8#|%3)>N$v(5hA>H-5=3_(qt7 zFFQM*gLvRnTvuy)%ew2C(+XU%pI{9(EIJe-seREgk#MkLO`kb@lc$_SdC@?rY;0v> z#>*?38ds-WyuJ`(V)d^n<;2LWb{FPMb+l!+vjyk$&AwW=cX#rjCZxYddw-x7bu*%u zalZDQ2BC9U{4-hnsFy(wPyd=?>+D!gO&nk;epRLzUd)g^g7$8OQ#BO`3P%$5yI^3A=bBnM2;BGn_CK+%KUyshoqxx37IET%-lQ1EDHZe#oy zL#E@@A*eEBEHx54?WbI0AX}|Yo&s`Slwc1Np~aR!G~kiG+<0EH2O02OFRS}9R(aee z+%ivj1q{O6tZ!QcBsa$0pqD4?qR7_jp1Ur&B#5C=QJ~&+hg2x&${NmTUkB-b@3C3F zlhXMV>ccaIDZs|{!Oa5r(=XSt$L50bLH&WeqpZauY1jK4<8&vqRFs?;wIBPh>gpcc zQtzeX&f&OKILZ47hUR>l_C!>$8Z zJ4d0eGT&}N@Wb8v@@*Z6qq9FD`P8_dw#`Kd zZZN#DI57Xmst=7WzM)YEC~x`9gumMSULKB6WL!nFu;yd_m;GL>V5|3bKyKWFbKi-tL#NIu&y(z#&qkuoyZ zNEwDTAcYzSLA7?mqp?+?29uSq$|_W3;v@nO)NIN$zh-n zsP`hF6&e4)x=D~fMN+G1g)5wNL-^mT+g~VR1Bu(q_Y{UL{uUkmE?HVZ`sQwjnaO=R zA*}7ZRxghv#Hl$d{$fMVPV`yizPa~seRH1#u61fk7VLQc=MVEnq;^=`UKMm7T7-#j z!cQBveBWg$v;*%Nk2bOI=e=FFmq?E9u4UWYn}r^W%+LeUfc!rmGQq9dsJ%Vl$}_xH zxu2XBFvT#{@7pa3uSNOLqM^}vX&rlO)drLLdP|Qvqj=*B-j_!MZ*O1S>mzV8L_UL> z+!lDoO~EzHhHaRH9Hy&JlQ8U@Y-f zDG^_`Z!!nbee(J;1JAdMtl$5*%*P`sq555*mUPmG3Px>&#;xl)JJ!+`tNR~tq2Ry( z>!+!rur~+J@jz^TNY?>uf&2G!Vg}fZU}=vh5gR1jUdU)bK)>_c|BI?N2xvFZYS+f7 z{vP2l9aOaF*Sj2%|HABymi}M?QnpYLa=q&U2YIeX=IQC~UX&(qy>_o&b)J*h*Tm#| zQ2Hd(Ph1k!u1Uij2fjAW4UA*Ny@qj22XlX`OE1JL1=%kzIpW-1mKB-C?3>_CTUfZu zJ1HgeeCMom#kQA=c}ECJaaKKEP+3AuMqd3Ij1!YX2UG-s(=G772{LPUD?ktAj1 zu=w&^#`=wBcRa#ZE@__H~>?$n5>Cp2FX*zM}ZEz4sOG@f>lz{Rx;jZL+ zZne)3)v5vR;%vEiZl{mHC0p)#0zx%i)gKq;ns1$YZ3m5vwqn>B;hE}Nf1kb4Fx1+q z4((ohNUjBc5!ZE2=&CHQ%tz1QelYvAo8^hZJgAje6xTwU0M`oOtZaqvki} z{Y>)!&t;xwThe!v31NgznziT=S|o)ftEo25P@Hkn&BYGC-$Hv`)MbaEK1rRO70m1x zyuNIRNa&?nd{k&gkOL$-&iX@_9*P|P^9~*gXVie1WQB)SGw=mRO?p`{v0(l<5 zdHD2gxguNnG>Y-@Z5e^A&#)mu6vgSz>EhMf4xbbgp?jW79U5uRi#)uv`daGwMIwKavQf`SMgbBP`w>se6m6y1 zCyY5Yv!y_VgVFclM*^n$8?(Vwf#B*Y6X?nH!48nWYPO?Pnb{nPb;9Z>Bwfb8(M+7qje@5>On9mK$`HuJ< z$OBx0_rEW>{wAvho?>UkbJ>KQ;N08m`{rgsl|Fy;%bfs>Lm}<66tBi^Q|*wBj+#0! zlqjA6C5Ys6oY8WaV(#}div|g}mBMcgRFsriSscW>l2}(E=H?1jiftYDUie(h?6o&w zi!4wN-+wY#+wA+c01S5)6Ie^IoD+_m?`-1;rup=&YqGIY zCAs{Sas?jaaH7#2cXNuXxxFI2JMoOwsCOKv2hKfz18s5XzO;PZJq5Mx7Tj_$Q03s8bK7S>B6&&l@#HPftIYc16hNo^uY!OS_w<9V*xfU1t=B zgH($rd92nJbj9QA%@4dKI!eoivR>a-vvs9{@nFuw=L zQ(c~Q)#w6PVTaYD@?LR=533&Dux7npK%?GeuY}Zu366x++;{?YaA;JOnS;Yu^bxn- z!7vewx$|dVk77`v>g%n6P9L9aiD1Ok2^aGwtK-fauTp6_z;2ee_%@ zhGJIYuG3ev8cY#-nO{GOtzl^@=<~297xU6Xu7WE^d{Fs3i>5YfY+1wX;;rx*^G?9e zDsQvHi1#{B6gC30z?;blGFW^$N=`%=V2KA3D=#ZeIbQZCPp9?YUTkJ9+Z`Q0IGg=a zsFD-4@Fjb_&HRapQ{RW}iIwJp1*=gJNuL@%9VxmH1siiDT;}Pg6hA4uq7XKwv}Rxj zNoC20pLEiy%^Cy91oarQGt)IwMf0`DzjuKohM`^#r@iBwdB9^L;&RpLX(7%n&C@$B zpH8iIL;Is+^;!97Chv2ft}?$ry-T`mI`OD_N>^%2Z;B z82!f@-L_zPxq1&$#*|jCltQNpn;I6I6_>X2sY-sp96*)En}G%ytiS{<5nzcsd|_xl z{!tXhjoLeil?-*D4bJJsI(VFAUfsI+A&u*4$>+1T?_9gs)vTPosNh?^Mn(&Net7-l zzxKHgX+y|jvF}}ManSrCP0-vgnVHQgssm#VxD=MF*yn15VUuk*(Z5yw)iGum*kaUm z%#uW?m24|~)tqTncQ1~YdJi|?YeDVT^Jp2rymXQ;;{QplDwWq(W**2hqbr5VV+M*3 z_GpvOT4pz3zA)Wm*%GB%2<1}-A9@tVT0)9v5C!)VF&ebcTyHO}SN zwB$@-U!}S#1Tf$GtD6jz`nqnGu6&5PsNMl*Ut_lRy$~P!nu&YGjzzu$cu&XFw zH+;SeyXyV_KkWZ!LLea^Ah?2u?ZrKql%wx+TB<85Dq34x+u7}X!4SFwlR5@W>eA=q zUKitr;R41QV}V!?n=cOeU|)N}w(Qx$q)BQrn~A)mBgcjFbZstd^Nw$J?40obX3HGT zy{?X~Je^MHN(y{LCGs&!C@@jDU?V;aDsPH05#sIdiX>CyBfhAjhkIj-e?9r*lB)}^ zw}R*F!<327)15fg!5Gz#c9cFuqXtaYty-2 zF_O?R<)w)_0!7aN+R(b!hpp)*6HvYdlw(^gMy(5ZYd}1DYdW=eIBCCnage(IeA-R8 zt9M7SJe%G2!VA{-^xo*q>)c~)Ed%SJxa3eKeimR{hwGjw_QHCs{QBP~+F;}0P^}N5 zVGAhbFM>O~C54|plnGZcf$^asn5v+200QB^1vt?VZyH$l0Av>d1c#n0x>sC&*yjC` zSffjjV=OcugeQ=Fh&M90WS6b>%dI?TaOe5EUSh%T?^!^&vpl+PQFDjr0)aj}K__yS zpDokq$6&t#pVKmOiuwNjFOceNnA85M38TS^9a>4z<|F!F=z3fc?R4BeaNe|-c=Wy? zIv3Q>YCdqcuMVvslc~LdJ&M!W<=?#k%4jhrALlL?aLxzwJ35|nHXIDt@L2>>p^{N~PdorYbc%^9yeerQ9No?n?+LJ#*mPXfwDJ&QqkcIXVb4sGI&d)CmV8g zba2frZsnXq+UQ_g+OdLOQdB2pUI}ZcumP7kTL}ll8eP3a6ZhT=^Slp_n(X@Uj{(2pTGBUzT$bpH9dicYD$7hr-H%|w%Wt0Vd#eCk(!i!yS# z>3#}jY+QZks5RN&T=*{SaGe+AO11#VnmWA?gBjm(Bd3UM(XIY1tm@x%qDz z2f!@f6PMS$%P|UgXZX~PWz+asH^jTXZNG%f|E&YXfzzg(w7lI&R+_v}ULTQTG;{%J z_>uX}NYi-hhDD=)^ut^kF6FBT+SjISfd3|p^Y_A6AG+A>-6~N5t zDz6jNWv86C>(e)cvZYpcCL}O;|4#Vl&XQuEHjbu3P<3v0uHH#Y2NZC2liw7h=t)og z4LI4Y#&-5h+AE;EmFp9<>B8`PC*jb}z7I#|G8QhE`GuT9g3Dr^8hKx$W0F9#Ou`t0 zFNw!m)pr7JdUV8k;3m32?i*H1!`M12r530_?Ed1b+8!6r>|1=zVfsOn60bAFp6Ln# zqnukL|DKVa*XYWQ+X`*GD1 zi~<6h)sIR}x6k*v-1R|8Q;GDp)B|mtH>RsO&{FZDG`4Gl+RAnN^ z!DGrS4(6=-d%J-=Va9d0fm<4RU1S*aWvp9psBq}*5y5&8G)sDH;v0V+@`uWOP)wRD zz$Gc8!?W(+satN#f3md-@8lF#@hpJKold=Ovj=gAP)#j6u#9}yTCIV|t!KmI>O08c zmGGRS3sLqNT^v&3jeip?lHB?^^f-npmX!aac6FfPQ!^H586Y4-9DQ-a0O2+5ka~UH zK*m4``-ej6vYFQ3I}_YU7H|~#t^(}roYd4++#>j0tS1snV)$kb z5?_@E`y%GT4Uch#?kR;hiCcM^W35K2iIJj+%YKmc&s{w?+w5_*HctOcIC_P>o|)>E zIz$;-1B+fuC-bjY zQry(hc$viXtj2CZ)x;1?+9F#7sU8Y7vwrNO2k2JOO=lQgz{WpGq)r`0V^imHrVI4t zV0et_yil73ITa!PGky!Z1PyZsHgj0#!focFiQ4V8Z@}?wAepp0#@YDn5@Ocj&D0Vt zp^1C9-*j+eB8GHLI6y#>r|+phAknHPP`>ed6QeE2RaD@TB%~5#QK6d)O@XpsJQuFt zjd81^B*LlJxbx*F0}3RNL5&?D|BnubOogt$DuyG<(i5CDXmdDn9)Y1Y&7FV|ihjO7 z3^~d)6`6x|Gca5dzSI03h{l%g^qnz>fXBddJr6p2%>~`lb>{<<0mR9^E(beSt*ak% zvG)rYvQ4Tny^di$W0iin3tM47q6=J|f4Xj!kXG!2UZRl@vibOdUIQ{Q$Osi|UN>hA z1uBp2c8FaC{$XQ{ZrWigsVRL{03`)Y3E`Qh?q8h`Ym-KO^x0tRr931*g3gDb+)G5h zBYQKugoL*P5}repXNsV$tR|UXBvd7*Gce&t&9H$aQk$3db2KP0$CAf3EWLTXHc%~B z{e_HW6;I=B?6`_&>Gmaj*AXg1I9~rFB2J~Ae!cRxu8~|2filv_zrVM2G9{L{mTreL zLB7Yz`%$@|4_a&A=4YS@{|&oXqUi;880riIk`lrbZ38jU2+DtVOMqie$ZNaVeb*Pp zX+^)`v|6|$Mc?(Qu6BQmt{^L&(f=!H)=hT<5Li*6PpZ*8oYHsf0(%|q`QQXpK3q&-v<1?$;A7D zo{^_{bi$=@AHxzvy5cJ3Il>dO1}U*pdo($-Puj1gMfON299An1L+9< z1y%5R05Syd@%;MZ6RJp`m+M75@YQNr;7pYR=hr{z7DV?4PHM{EY;4}@cZmUqIm#{i za-XcKmC7=TEznuZRZtSeKt)Y;7jPdOF_9C`wd7pd3hzN6Pf$eFBPz!}P(#4w7A`v-XnpVt#*BGek^^8m!<3fbYdVI zy-3ectiTDcoBB#EZY1u{pDA&N-&+6q3l7O19cb^xgmWa9oCHHwRj70R?OAzf!sTTY zs(c|vQC@{+ERH+ZQcx0AideYy?RvUd-ef$6i#K0CiTI%LuZpnL`3w-Sx8ya5|4)GC z6S9v=%l6_gK0XMf4MXu>7KkUXW;!3nL@mY-bes_Z$sp{#ArqrhFdf<11Tz)_lL-5h zA>7x~l~SdTOiB@oJ0(VMS3F!t<;PtOC~6t`6-hN+<{v&xAEbDK7A#l!;=6T~NMW`2 z9n;vsv%J^z#hyi^+|YYrz`3Y7yUd`$l*$@Z*uy-WT4lfqRS3}NyVMp3K;+#;*Cc#} zvtUpOKl6bb+`b!>MdrAn_{k$YmY91*JVKP-4(r?c3t|{_ca_3C>(^QF+8tq?h)BZ3 z&m>-p2XV_2(ZDP+Dym%2c%X~-9oArY=uoE3>c_#8Txf_x$hC5~s`7n%CARhLv>$hf zQ<@^o~2g{U}g=UfF|MglFj4r3b}fNr+guDFgZNJk`hj= z^E~?pId+%)E+JLlTv^Eua7y^boh5v5=^nU=yj&zcP74YFY#^E?kIN%QiGJq{5{Av@&j?Y%m z@M{8Kug`p@sjLjkd@5*%^SUF@1jyFC2<3LR*}Q>7Ej^vsoo7u*2O5>%?NGmfo3z!p6hnip_D*5W1VNrAubDtQX^$KF{LU7#=}&&pznt4bK!4^<<1+-_srxaVx(WTJN*d*h=@pbzuwnTWl0|YM-S?N zT3^pgt1$+*GWdmw?gOXwN6gWdGuqE4Qk~c0=L`Wd8G1zP`(Sh6AHAa{jGPvDO%tF|5vyTOuqaIc zE2*b3t%;#gFIALJtpS_EzVz?U0ll9!ezrf!bpOCm2gn|ITt$E{GpmYc4 zcq@q8m{S`MLkGNp2IX!c6QWclJm@Lj&gTg+UCi02okVk=o$B{w*xIMkk_O!o`mKEz z8$#HNe6% zG#)nE`%Z-j@g6AMP>K-c+Xbzy;`jGWc(xsU8QZv5b?-t)7QluX_J$tK}f zSU1u1znlTBD1|}ZgZGrc1rm-Vks&5Mp18at6Bu2Y)3ig{c+gZ~UV~|Cn72`D%q0cR zbNSs+GJmB1%4NoU|4V`rWSZKL-ru7vR;Ckp|MOo>D!i%jxRP{$4`w|}R|seZ{qCor z*MEgrlu*s?mZq)>;gxb9c;A3hQjP`2UIA~3d5t-0dd|>_gDmiCc44@}!b7~-PCYw& zAkw5`_R#jc>;^D1a(6dKV}25mSx&vSsC#nSYBpAU0(nH_VWU5#M3njwP4_hX87eAjQ4daackiN?k{f6X zgSAS)rZ_vd6k@(FgzIZeBM^lxttyiMMxeVpPT_>k16ww#8Ukzx=^~zU`N5G%pk9Cz zsd%&i8vahktyLaRmhN9t>#De4DIfZ=o2{EG$*o7IsIHDei>1F*1t#B2!v|Q#MG;a9 zg2fLnc*-WqFi^mz_SGjV!%-S^h?w`!T^aSjnnWC#n*~~Ok7J0hs4C5HxK1)& zRbJ-41AI2+E3A--z3qS;@|=PsG=mLGb7VlQ?*Qs&maMeCX9_4IBa*y>=@!lP_zF7B zI_HWa@+p>ObgFXAd54#|2*126_hm14+dL5z9k*zdGIjiq^3f_vq~8{364}>F{Uzr5 ze>H;~t-*}w!p=PE=g-QY#w}hhOBP-i>Kkc?pzv!_O~#QSRxYwRZVl>p zmFu==Aki`6KlxltM0L2`u7|d+91f6U3;{F&y6znTGK|0To&Q5p=^thw>~ULZlfb2O zmf#lTNivq0@GGK)*-uFqR6EzTW$v7H*)3|Kv$)i&R};!OFnAOlA3xLlC8}cOK#0lO zUOdbUxX!+O1#ohHg1y@U1oXd%*;NGESd7@Jl5971j|T!*FDn=HesK(?j|(-k8Z0ag zwhwEE0Vt_Q5$WRq8tyT|h*Jm49gWovi|+CrV-|A zZda78o(?#o$vlifDR3B|t-sp{V6t}r{%nk7dTWs~^4ZGriT*Gkc}y5Z+Oq#pfMtM$ zIL~7!gY^oTaM&ToY4~2wB{e6)Y_EBoh=M!tEBt2b8=%o@K7dkqNV8N6iO*hh7QE)A zt*aY@#Q6n47;X38-^&7TRWZ~(@6I~|QnL$e3UU2pDck(JR@S zm@imafU9I{|5md-JlSW$Evf$rstm;?-ZF=FU zHKK|B*Q67+pE45bUP;TY-1(yxlyRYByP7ay6YsaFXPI7_}P@1$CP>5dw4he*ad2hh7KSUhvJ`8G|ES)|Et(en z)@}_Ra{$7!C!!P1hZUgxu3!s%1E{i%PmO;txV_E_CFW|jXGL$@ZPsTeKJWM z{gc*3&|b_gFE8J3$@2P~a?cqD+y-9g0!;dkWbi-j78BGW$uLnwRYYP*^7}r2#sLXq zZ&Q#-|34*zL5%fRmN_za5+vG3#Jv<-axvdeK8zHV`N``3VJ+F^C#yvG?l_Sr5~HHD zg@_8mH;_hSeEn4ZZ0Pc#^H0LG>Txu{At5>(X>2FOL{Njk|?Frvt0s_K8D6J&%5A#FMhFOb}C12dG*^8MJBJh3qfM+P$XDdiD&u~P;~X#F zo0tGc4uB##7)B1;0z2!^-3tDn=Dsp4%C7qtB}5b{0Ra(^k`Sb&rKCaW20^5|TT$um z9FQ)hdjQb^q+~SP0B!IQCHYP3+}i3eV|#z^HjR3TrW9c=oyn;&pZ`4O8>MiN$rzTV4{4y zisj8xVXu612AjvFq?mIdFs?!l40EnPzVfnUm&EQBr5BIK*M)UG_JNCtRve_^#2{6# zn6^Hc`TZ;LB)CB)LSF(bw0TOcw+Db_a;(4oaKEKusQ5`D{i5&|Tb&YTP=N$|F5>#_ zpO@)3wL=xfiG8h=l@35evydOnmBfzYGZ(%S__8=C%CV{5wymB*P4`&ZbCrK?-}Nk; zs{+M6i=4-UY8BGNVhPIxK2h#&U%erK|H^y)u#dAi5NJBkr7tQyC^i)v!xG>sW;&v% zEc}FX4P-#!@?*gGFG~CnsCJ$GO5(uKG&s34C9_;wtF!dggc!;RymW8@0S2!1UJ*P( zTTd4xCI};L-Yj}8Z|H6(Z&c}$<8HMm-{@#Vn`Vs6mg;X71T8`ZwurW;X)D3HG3xT= zldg~imYeEpPAtsnzDODu2kQm;=yK&Xl7da5k=36*Jvz2v71h_|8CC%b5Fv87zumAX zg~JViI}%Q4^HzQ0@MU#%_v&5eX)ldeLO1%lX~?;Z;~I-IX;!>C3zZ;`R&#TaH;8{! zHhFiE=Ic1m`EnvT$A0Bfj+pI}g#5h4vI}l|ZHP@7W?lP)lQ^u{iL5+oxB&%)*ai?j zmc5g#rCVjFZLkwVo>E<%@Bqi!!P1>O=`Pop)`dN4RgKKp~(y!mBAEO7W(>oo75ffcMyGK^|oK7+?!qb31PVgM>-&J)@^~br90N| z!UcAS%)gf4tuiPns1dOS)ZAG;ijGoVh%+|k(`Sn%T2f3a($qXDlOnxW6})^kfi<3w z8`RIdvGXY#7Z46?KV0!{b4aCLDZMNV);Vr=)s28d0202Yq28D2cikGIvg zD2z#1uCacl?++XLAl`j@Mo+6|;1b~M5>H03tdTb}?d4%4;X?x*az(384()^%4 z*@^mdO834TN#5Zo0I7x;sgRCRPVQ4JUlenh_&a9R3})cawQD4kk%ln}PQ&^1|AH85 zA%3*V94EhB_hv$12c@|KaiTOdh)lqbkWGD3=VrwcyGi5zU}P?LImZeI&8=2xAZaW9 z<=PxjUV}a6suCa@g!H(r>K9wMLa`UtLE>2*64&5 z04#yvcRO^i<2~5FN?z|Y>2;)BnH%%wP9D=mB%J4UYbG?OYv;@PQJcD)v@2Jp1k)KI zkzlmBK8n>hAl~49&`B&cxLrSB(f*4?7fFh}p}VC8C---?q#f6s<{Qh?O1F}z=_?L@ zCB9~6>wd)wPWg*Ea>!KKh#^P|@HEuql-}O#QMm>~_K>}w`PoC(=lzZ~V{YE{$Nd~Z z5#@R#d@C;8McF0SBW|8173{qbnDZ{@xA2D=-@1{T8CW;zv(V7%&GXK1D4R0&Co+YX zFZIIJB(H4^sO7k_15y9`M}=7?t&sgaI2{SU!vuf~$vSb+W5~{R%EuX(13|sCEAh%$ zufBlt9OwiXCO_urwbT;u!cVOA=I@r;Z&;)_tTcv0=|C&6Nbh%Tg_I2KXT6gwLL4sb zV$*abVmmaYpk!C&k_;f&(kkud1Fp7!yL0!YEah0S{1x^9;zWfXh`rzF(M_bClG%g$ z_5$`dfEEFV=5%HYq9fQqMsK57S#I9&Q^l>-6*^y;->QzAgMMi6{uGd5k4 zaA?bkt8``V`qo^0K{F(BPw-Q^gPe@QJFb!fU>$y*?!LX`(d`>{F%NZ+{)}kS&>dvT zU@~iKvH{>!Goa1z|M3%od2zaxY?!!d*bi zWhV=9A2-ccyl?*6*?D6NW8(Yr1&*6uU)_)ww{9XYZVAKA6<1t8chc(ttPJNjd7OeZ5G6>6y!$(96gYb&9KfOUJ>=yTEN=ldV3OntmMS+4n+U|63L9@I1KaacqDSO8LxRAUgm3@&@}gltUhh>w>^oYt zLZS14q&B)2obRN zn0R;Q#X(jL`}y|E_h90+i;3?91W_hJFUza>4G1Zm>+T(u0x?t%x4&!ngHf{$!}9%g zUMHIpOaQ6$@}e$`nb3fI8TwkI(d5hL3RYQ3dF#M;nl&=RrI)ms#3K2)H9(i6>qjif z2pF^B&;=1Odv!6+gnc3qI8*c}zy3%LzgqjHh@=3a;S2H(GsvJu@_% zg%s2QUguq;=Wv-pKhNJn@Q={v`&E$wj`?-Ike@JE*3RK0eMfr*XY z!5ml-0L@9nG*LkpCf$$={A`uf5&=%uM9E+LsnI_K&1~>9vCc3TVb0Y#k;K$V$fWW~ zN7(rZBJ1`$k~E7E131XEZ2A#mi?G)siL**+0@ewM9+Lzs$dXg}P`5{r{}gmR%hkJq z7HA#*{y%C$Gedw&dD)>4*nr1~FPKq5!=aSjDZ8xY0E{4G; z5m5^FTfb#d>!7AekkpFdeaQd*uToL4OB}mHCS5B?53`q-;i&0fgEOg3{o9rQ)JW4n z4{&*GKipjaz(mD$oD=H`MecE0v2Xjj_rp33)5OUww64n1f|`MCDIQ2s0A-LB@UT^j zB}LT=-@L7?DZ~Y2K)~%ct`mdb?+sGj-5L?0eN2CwrXapvYw`@c1H*FBU_w3ri&nMR_efr6< z`4Y+|$Wk$2+%}3jRq<8B5=Z^ zn7dkV$0sap&HTuHFS!9o6n{akQn$h)aCaU+_zCb@2%Q%WaYsMiwFmigIq(boXjy{p z(NZ1;-j=7)IxMVcs9XOT*Q4h~Z3?KKz9hR#Ew$9YaleZ<19kB)h_hsfIzZ}%f}HQr zb%bU>-}NtK^z`ZgS5O_`O@BUvR&(a>Y6sgvy4hVlu5`r%Ph*MzxB@rvt~uaMd}V8D z+h%=F_4c0d`79^}g0#JoWa5jf-7lfKVBHCO+j@slnc`hBbij^x6tBGAT6e_yu&pyi%KR9N;K>VRrjb@d`X;Cl=| z4)nfZihuc}lN1myjSuomEVsF%9DS>U$>qx5ym)jcZ&ybHc;ZApQaAP)3g4{*!?~(4qRq=oyQjsTZgMB!EhSB)){XxCftp zELrj@AOWx&B4a11wW|Bd}aqY|J1oG1lq4btZm`_H<8Wzw7Q zsQ~To!{^5LxO^=7LvV!LD!1$uaagJ1D+O}ZI(o(_FQe*5{ zjt$E`*{^l{&(3@hsc+tNs6D0P<%Iy_nmQ4ry*Hi}PE-jWnT24e9f*#oSP> zU^QkkE3&#c`e(~sPTFLgW{l)-=gM<8;LoB>!jic35wunXZ9{ZP!Q-zb-XGUqMu;Wr zF=P6sKkU5vIYRDmEXUTa)I-T$X5w3KOTXN}T9G7p4&+TfIKb4k0jI&Pz^)YsrRQC3(9a)j$4Rea$~se{sZ6 zE-bJ+#PJF0mb^Dbrgkztm@`^xCZkiR=cO!&1rJju9uzi=9B#537;LFv7`_s$h2x1X z$4Z1I@+4*U%`>SSPiy6xngsMlupxf($>EUl2Jcv19CE}XQM%-LMn{n07~sqkB2fl?fin>wdqV|ilE#7Od| z2r-E&?;Kzy{MypMK&t$KIfvv=EiKHp19L`iU3ST&deKzibkP4&96F?lLqZ3K^rBNq_$&(kQ4N_e++;*Ukh*thc~bRnnLxwQAaD!7u( z(>-1zo0@Q(F|#~4!j_n!t-6vKg;3ho^>{Semqp999}1R%kv~C^LGexui31CFt83 zNEoshf>gP~zmRMfs1;M`x%FZ^gT`c-emb0Q`ku_MKvY^Be|i|pw6<{X71UE>mGkbL ztIocL9(#+{?ozO{F2F9fh=GXA&)P?7Hao82qDk9}vS&FrHAc5I2L8xmaVthVfU|8A z;Uo)0BV?cDKn*%P2(`^6iRf4GOFKpb5cVf>!OoigLWh3V(vF=*`7SIRcmzhs6U%di zO8h}l
f@k=9*V$dIye>kNWQ$ApDqB>tb`-tl4akNHZ1--tsB|y6Z^!$Ti0gsgdvYF$Sx|MW z1cvc_x34gV`Wu1OWNHs)8-ngvQU@#B2WqH3t6#tnua-S(Nbue^=DMJ9(Z#%!#0I$i z30m+k1IJE?NL__cuSLcNER_lODdyt+Z;wvu`(zq_3|tw-wj zh}1!+PAcKHfo;1Xv)P66jh&6{zTV{Tg4=y%by(P$Vs^%;^2Ry>TO)3h7eUUiCRuHj zF{}^Wd?6!zSOl%#DEJB?lyfVFP;ZOExC~>fBgIW5tE&ozEc&nmhHARRucKtSZ+2{O z7p4EPSw)Fq_?sRb{cAstNF3IA7yR>SJCmD@|>N zIHO&qqroVz;(jDX*F3dV(vt3!9nN9EY-;HXj#RFOBhJLyluXSu>?wt;&{Sw{F&>DCnEm%I!#Q`CXRH8gE0l zc31Nun+Gq}GU~9&?2h-LUuXqgFd3`ur_7|Vp<8;{^5z2etpar%29?BDi zh=J@06By&jFoB5~`;G;BAZdA%s%y_1v#&9l93xiQObr}F)#hbmqj7q&nqx9iSSKy~W2e)#GKnWtcLR!;h}kcwa?E!D zk{o!`XC--Fq-(M&+-qgjflkg*y>1%f4I=t(M8!0P^mnVj$zsWE`mqKyT64Au!UeRK7ih4f}YQyG_Ble{f4r-v{MM0s+6XwTN>6wL% zMF6c$dGF=F>1&|3HK~3n^CE7VH>zT|Xt5NrIaF?8`F^V9>z^Uj#>I%Qxd$SG;nwB` z1;k`|dEFW6mi~mO{dkMmB2P|cV=}1RWCRzi1l=c7IZpN<`+1?Vj83*`*mApPWM3KB z46a5_02fKWl#RxW)k;C*L^KrPR4|-t8R@to}eL0u>(y--nV0q;dPkR5-*jR)_ zYb}~={c}rM^!PZkNj@)=$x95Xh5ebIgPYD7FvDCzZUIY)k-^+9G{PNsxt}^<$B**f z8c>robvytE`|kM(v7^lrk2!NO>(lQQoXq2Ti>;&#XN(K)qF`vb%Fg&o#d%|`_c8d@;^i~rC%!^xtW>&5^NgKELn9xYbN9Qpv9wP|2(kNuW}rpRn@6-NQM#jD zY>}>ll;4i$*}A4%=VrLYQ1rPswUztu`9rDAHWF8|x}kxRm31bBfmv^em7c9x?bOC{ zksS6xnzkz{V70UIUpc+n9 z`uX<7q9P1go{f&Lb6~rztecFEkLMSwT}hkvBO?FHmcU>UgCe;f5Kqb#1eKbe8XXqz z(M_`rfw5Z`-@_Ddajc#mDA!e&HTmW>4?svpq2C9#HcjHx3f%}+J37`ngiKkSIo}5J z^W7bOo@PNN`)UDC++7U!rVH?iqO`7lW9GsozgQB@2Q&-xfv*-WBeX4`AmOUt^MjGq?~97o)*JFO<9ASDmgy+u z`OUCYlHhlICiwZm#W|UrLFeKg#WS#qcoO!;9@Dp@Jmuh46gRi_(%U!oG%;ehDiA_? zv4PeX!41FPs7*1wE)Au2&=9owh=urS*~sJj>(#YcaU-dzdkFbbz0hu={k!jOBgu(% z;I-qRp=0AtCjK=9CB2YeR%rKQQC?ysDZYkAQcLMdB4o*-Z|qr+lcMoHyM_NeIpWC; zk%&`Ys#s#Gcei~hI|)6+jur)(QM?1|RDhll=Vjxe0qO=5i}F9ZiC?h97`OXNjnB}m zB2Pqg&GWOE}s=D6KS}})CtqV=V6zhHx(Ea zaCtvp8e%SA1Be=%rY6UYfkHZ(i|W@ z$nWXKZWFAR8!Pln;k%4@m%!X^1S*jbSQER#s4SmIJeqcXda8zWxxV}^w3U-$wLgD^ zAXtstayUa&)c3$qYWH(am-|U#w&zKptQrnvBWC_-Uh|t4*1xYa=e!p39Ci@d|RgJ6iB-u(sU#_Xp!kIhjvhKVBqR4uhoY@)G3kl5xd_ z;~s_+M&>gkls}r2=2p8upYvoG4aA|1YeA>f(-LkRkSbPi z=atm*s&7ro1K>aAzSw6T_%!Z+sHglTe+ORp$@yDETZc#BR4nZh;ZuCeY+q-?OJ(}h zAJkQ29)cB2HJrxdX%XG#UImv~h#1aRU!~R~SM9{=Si=pNmKmO+A}u_4#}~3)vfO?n zwKnU9Ru)%p5Xo)mPL-zUv!K{PR@6!IC;p~~;DQ*_>+St`3}L3z>kWOZO`C)~mXVcd4X64`H6z5Szzc5{< z%F}5_T9Bu(?m_b*pR-M&W8O&%EMBL>MM7h-JB7~fv=;(aS;|*x@U3{M!Y$NH2yeVU z+b)Y&c|WOgdBF4HLZ;iDw^#y+5yRI>P??TBtu@Nlxz3)@_H=te%p1&Fl4f|*)7l>- zLeQ!5Zg&8eLu-5>ux*C9{h0jE$q>P(o0C4QK%Ohvly|^v2}p5fvHDV6(SD6YGj)L~ z&<8QPeNV+z=zPEE#K_jRA?>URmW9Ai%|B@N2j-|<_TUM0!T|ze=U;{AM1@vsRZ`R?-j2>EqSapKixyXf-c>$q(uhE?FMB%R4r1(#%4 zB%zhZ{%!Jw#vkFOx-5lKsks$qTBUSuHx^9TOYUMu%>a9&f(^o)AyTeoE_3#0o7ZCT zedeW=@+65mQ4(s%k+ob^^B6j_Z9{oE~PB8-Fs&! z!G0?Z&|)GepNLaCMP9_8`D4;q!hDrTg8 zz0WBD3BU`{;aAYj8!d^{!a-Li>GZ~ie)tq!Vd#NFl3&FT32e@c^1E9~@7;G7NA!+{ zoD_fL?vR~+WFr{leqs=ty)uITzHnov%t~BFu7+0$d&WcjV&st5q{R$*@z#qBL&asM9FJhr#(y>O$<=PbZQ(^{{%XCM; zF72n*#|<+&toY8mq%b4&cZSOOafYpJw=0HN3mfF9-_U!<_%cndoh@{r8qsrGjX$;` zdNgo?iWc1_zF8Xrj4C83o61bAm|94w0fe|hC;2*ddGpTX=1#KoYR=M4FVM?^fWKi~ zpq&Q!fS9x!0ofJkEABSFjASL)1D{1$J8Pvr>wW8jwq3be7PAM3OcZ(_RExbqUd;_V z(LHnLIv;U-VKdg?+{ClYg|Wpb1&}Nt2UagnWd_z4QSolXTdCo9%Fpy7Ib{NL zUhMP2^FLy0^O8>qZo!MprtU)1b-*A`WonQ{aql1$3tRwV{Xu7Aa7E(ejLC|}nKZwm z?#yJ!;w}3kdF6qg$wOL4$1M)CM`rM+VLt~?K}7SE+op@9d5W2IXC&x+z+kE{jc>^e zT##1by9P3g15pHGVgr79$I`nBGSY+&>8gnX#hO&5_Qq#bWQ1}ebI=Ae8N}hX-pW-o zuw7)?CQ|iT^1C$U$6C^&M|+AGtsV8(ie&&u3$BWm z{be%z`eY8*Y*P1C`k{Kw7ut~Y&lSIufXG#o%GU~=^j#d*r=k)ur>y3YW5`Hu;*VwLAY|1m9fx8z32|2J?d_=?aAo^~&M%J!P3a1mBRnRVA|5a2C@NgXmL@~8;Q@{rb}~1Gpb6FZJ&@4ib{g_C z=d#hNJI5(9Ms+yiVhYi(5k2AX)?(t#(m`;_OY{5K;hLZK9WVeieJ{+6?@KN-kIBpG z^9UR!Zx%l)F|Z%_tZV{DO*c9;oqtB8llaFp>Kx)~#dApN%x@R)6veyTsh z&N8`NU^c$FC*gs0Py#qT!A14qFO}I{QY{>*DPMmnZ{u^1>&d7^ZdPj3HU*Y(9lC%6-JK;)j8Y8->PSGY6x9f{QlpvG&>erZ@oJ3 zI#%9+=(Qt`&Pm#C+~Sd?G9=Qt<^_fk8VEFy?6T08p~5fFu8v8^JH zpG#xjxyf-KVN8BBlk7GBp}!$y7PqcT^ZG!yoBh$utObrvjS#Sl=9Zaz;yRD#&{vHa z#$}gC&d3<<(BG$aI8B?#y(a3_UZB~4B(Qhhi0>Z+A{K@~(XTIPK6%yKE0nPCD(t8qmuAE1{`XUZpov-g)RAqCQ5H>!fIgTuR06r0|| zqnQfr63cI8jouR!vuqtL@%>HB5A=PJ3a?6zr;^UKS&$!1kyCa=YeHQeoPuX9PjgQ6 zl?Btn7da)Qg)I~_g&Ue`` zr=SYCWRaSDc=huv-}Xs+y&?t-TEY;YH!m-D&M&?ZR*i-+NM~gBH58lgk~(TX=VEan z68JB9der6J;RmxX%Ucdu;2_m~pVh)B$%uGdi#{?Wv#0PK%uVpxQ3q5&F@7t@@2k_g`CDfFAFT+)<<` zA|m}2lKPGM!fha9LpI-QOyWyr7_ikw`&B6B^OI=E6>g3T@;k3evrc}1$7_W4^3vz3 z{dnh#;9d%J4YRCc&i0VTImA5AwsS4I`rfwgVUcCWIoHtkVS)mD+eE(ps>o&}AV?+O z3bvq{qgFjpb<#%x)Ky^YuY;j_jb%3nrlG9QVii^N)e;%rKi=3%6VB7hr1N2n8Zf9N zm*2GmJGpeA6E1iA(Nu>>0j{4{|ilwHCwCqU7X@4 z3OBpn5Qcw{=U2TpkaMfoTqcBTcL);ZJR`L^8dVYOjW~R$L|W9X9P3B8ta`VF;&_hY zesYr)#c_RlFE2cGC(PprKtpg@z{7kNURQ$~wDVsEs19B*=nVukZRi*HfXI=P>4@P= z$C`{n?~?psQ;xe(<07XZ5T0b*n-sikoHPOA;npA!3gj{;EuvM*#gbrHrIk2fMLWEC zoguD+|Cm=02Ro5dtbiD9a6i(l;E915E5j!rsxM6jQl%>P=CL5~+$Z*;9SSxpiTlE- zdatA+{^pM++!_6UdW$n75sYdwD(Cuw$n;2y_?6&B8F~5GB1s#mMJq(NM!6>WWu&v2 zF(_NyJ=CP_v}ULJ*eH4M+OD}6YWit zCOwwT*d^RsxA0Le)vljO*6pfX&!5LFh)=$Z;)x=5nUb=2g;(Hvb7>USQ|zHm`AaB5 zNJ1hgybmVX!gmx|Q&3O{u1SlFsPrxgn_hRJW>m&L1Cu{M4nL0|)}Qp6v^^`eVN?zs z!$kRx1Lk?!JX!NO*$GAb>h-HH^9*dp#$C>-UCVF0yoV$(C5g*opebJHFa#2@pbt1q zr}-Fxf+?CNBj$ zT7a4QQ2_&(;X+3XJB#pZ*RCy2{`f2jMhm!u{8Cg64Sekm2o=8uC`mwas|B85Xvl9b zgC{!VyF}oL?Gj+A0{L_mx!maBNe(&deeh&>8T{B3Njky*CqupQIbGHlbl^dpu!n)5n|E~`yDUs|U*XAXX zbtJQwk;_sAo&fym&tLuh68?5Eg?EkZW>7Fyzn=NF18CL60kfk$Ti!cS&h0HJdoHD- z=;33Hg|cx4{Fw4&wds5w(ny_1ALu8}1-_aEJ(sM=U(mSpltCK&BT?qLu z`Hl*RzEo?!OL~aQ+gCcBoB!xsDG^JBl?NT=00r=3`#2H6`Nu$(q(x<5s{>w=g$MBaxzUZ zxnJkYP!@%C^=jfOzvo8tm91HfkCzRkJ}O~g_bejLo8$F-Shp5^ zMA!yHxROV!)+zO^QJ4Xn%(T3;Tp;e+^~RFO{~Uj=#lZHoaSTNR<@!~Ppy`K8-8X{* zQ>F&5qgbLY<7;4DXAo$Pc$sRTds+4s)mwT%2|qz4=+&R%4$1`UtkVrc=il3x7j(iNCoHElvsiN$5eLiUNTj+6o$&At;T1 z7y90fyngTIH90Z5?mTbh_eoAm*zPCoV)5sn7|lNBGmVVcq^MC*y)(>)jbZb`iR#)26#T`B2k#w_X#VQ(>o$1b^O= zXMFCwB=>oa*o)WxNM{S9EDmf*_?YO*ntja&)H?{5HAHK*0{lfe_v#&=7iJ)e+XC^C zCj$PQd#T^;uz$?tD3mnWWzT_+6FXtt1jQy@5Iu=T_fp*r=*PA}tl!I*OBI?}U9GgYR^?K0nGVDVdTv}+ zj$Ilee+A2;@g^2>T_l?b31=mjDvC$I%Oeq8v$i{3G+|K3a|(Mph0M0pqfj_3GtY=l z?SouSOUF))STgk0-p#u$HdhCnaIdl01L=`LN>6}`_Io)+DNyl|QTRxMomYugcWkk& z%k6c?8d-oM0A=CIlkffAZCI6(hi+X3Lp4;9sAgoc$*!W8jZu(d3GsuSIqnQBuWw#1 zw2AxX3<@l7U@JslVt@gJ20uo(;wV#aIcV*!TA5`Ryp3kv(6B8Y8bqB@bn-otz zwcX{n&%E(XS77~YAgA|p|8##0A!~p6V1fFiC87>{QWi%H$< z#(b(nfw3s)B$t9sENCUS=5!juXmkNF@E{ulttzR*cN==Oe7#gh$@NB7=uw<=*T?wZ zyC?I#{{9TZ|KR|CjQB)w{p#1N!?YzgLGbDO>(FL+XUGM+SBJ)4###IJwChn&?19MX z^|g-?FJqCKA<}vo;^O8p!>ihh(f_6Q`vV#SdgKxsNHx!x*#4gK3_JfARg8{Rzmtdl zzBb&b?}^%8w2C-LexD$)twB;-LgA&_tY?JZS*EvrN%dzi zYj865oD#2-$=`-bcMe+;!_P8`LAAW3euL41?n1vIRaTRJFptiA&`&03<8!T3Ov_{E zVQfC#6n}m|SKvtq_u>mdP+bQdH(AtW>qHrsD@pcO%0OLAqoMNvnjXrE-`ir0Yo!l= z4trfDIy&l8Zr~v#+z09l5f0nj7g`o6t9gD|Z&!_lDwba>dOPN1(raY*W@P|bnom0y z6(F){#o9R##bGi>jo)+=A=8IlTYGJKoJ5y-L&#{A$o=~?c2bpfImm2JJigGq$mQPr zaDT!?KB>Y|9u$CK`)i(bgaGC$KtxjKB*1}tJ!i{m+ykB|4f<`oTj$ZOJn>k;a;#b; zh43A`>-5Q2ZE6PP-+p)EbuX^>sySaZ{uw(`_Cji(&K?t`r=YsvMhcPT$WbkBY+n{^<4N_^SmzCJj+Rad z(W12SITs+AIO0)Id#^{m-eodn`qx?>)KYWI5_?Ho!_KD4*234TR&1G$pS%VO3JN^E zI@L}fNl-6bCmN2oxM~xb6lwGnG`{xcr_?{AKlgk!e~_b$%Ml@P1@urv_uo+HSmQ_s z($U}_67e{il?R0gdBP+bs4b9v2p$7vT+mq%kAG`x^r9mq)H$`@c#~T&QXt>W=e$~b zsPS$v1oEJ)tR6JVn;-a(orJKG2iOFWNI_mpCFiu8UJ1W>z8m1&UmnAmWpFD8N#sjBN^lgbW#Xd$KyE zr0j?OYYkdvaLpUcrDh(3Kl|Nbwc!BCzZgbUAfZDJ5nG`8`O}x6^MA6eDwbiA32b}z z3uQIv4lwAD*D+UqJ05JjZ?uX@qY!?`_90Lfk;fiPVrTyQ=eCX;x=PJ7wLWa-L z@3RjS?T&(*Q{svlWd|a*@gg0sfBQTMw?*HpV>2kNNKg5MWS1RGM(JQM;QZbMr4P67 z_WXYMf4?KqR9u~w;4&~@zI{hfd{U)Z+jM^Xh?6UZ>N0ZM-`6;(_NEnqWbODwKxXn9z9cjA$ZoMq{m^`zSK+r zu`eYkEmry5_)H2>$W7oL5R@1^hl_i3jRdAW_e(2d{G21LjqCMSNvhDW9mq zYAoDa?6(~XS|sXSO0G6*n)|}WXvyoH0}d+`LZ||3L|m#wS0;USVgIs~+3yDLjN#WOs19&_l_9v?6prrTKm&hv)6Zg*w9@j>Yc(nmw*A3({0Z*lo5BiLv%L;Y{o!;E9ex3H$naOq7w5z$4UQn97)3Sy=Qi6Kj#YGS5?p{<1?A!WQ^c- zT0umQz)|62-5v}2dJY!xcVzb(=$u#!|JoV$JIY?5g&Op+(W_d69=VDTImX+KCnLbc zc)=j49p=+jl&6o3(~Cto<8gTo$L!PF-c7OZb-p1id*totE{p2PFCSz-9fW?HoDP`<=@Yak4Sn zG+bNz0|Xn?E$f4-#j5TrR9{ry@pJvwfUQY!%sgyeV)9+UmH@mghmb^WB zJ&@(a;RskS{~!7ktnFDJ{ba@QZffQW)~|bOwII|gtKV3H-uGxXJMfXXi#+v9EZ%1x zU1Jg|9BZ|+OD~Nz{@&Z^1%vtx l1w{=E1;D=0|HH$^IXxr}ZZ~w30lbGIEukR(LDazae*u+rg+2fP literal 38300 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 ZYqiQ1kP)J0MQ|g6)MI(^qDO{){|9QKf1UsU diff --git a/docs/diagrams/diagrams_png/MealListClassDiagram.png b/docs/diagrams/diagrams_png/MealListClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7611d1cb0f66fc5542958c96d79f39428fb30ba2 GIT binary patch literal 32942 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 literal 0 HcmV?d00001 From 80219c1fe4677ea9e4cdcbd049498716f5d58a54 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sun, 14 Apr 2024 20:53:02 +0800 Subject: [PATCH 218/274] Add sequence diagram for Storage class in UG --- docs/DeveloperGuide.md | 7 ++ docs/diagrams/ParserSequenceDiagram.puml | 2 +- .../StorageManagerSequenceDiagram.puml | 82 ++++++++++++++++++ .../StorageManagerSequenceDiagram.png | Bin 0 -> 70265 bytes 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 docs/diagrams/StorageManagerSequenceDiagram.puml create mode 100644 docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 9803102380..e87009437c 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -40,6 +40,13 @@ The Ui class will continuously read the user input: parse and handle the command. - Else if the user input corresponds to "exit", Ui will handle the exit. +### Storage Component +#### Sequence Diagram +_Note: The following sequence diagram captures the interactions only between the Ui, Storage and StorageManager +classes when loading and saving data. +XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ +![Storage Class Diagram](../docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png) + ### Exercise Component ![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseClassDiagram.png) diff --git a/docs/diagrams/ParserSequenceDiagram.puml b/docs/diagrams/ParserSequenceDiagram.puml index 573d5fea0a..b19f6c7255 100644 --- a/docs/diagrams/ParserSequenceDiagram.puml +++ b/docs/diagrams/ParserSequenceDiagram.puml @@ -8,7 +8,7 @@ participant ":Parser" as Parser hide footbox -Fitnus -> Ui **: start application +Fitnus -> Ui **: Ui() activate Ui Ui -> Scanner**: Scanner() activate Scanner diff --git a/docs/diagrams/StorageManagerSequenceDiagram.puml b/docs/diagrams/StorageManagerSequenceDiagram.puml new file mode 100644 index 0000000000..c5f40f789c --- /dev/null +++ b/docs/diagrams/StorageManagerSequenceDiagram.puml @@ -0,0 +1,82 @@ +@startuml +'https://plantuml.com/sequence-diagram + +participant ":Ui" as Ui +participant ":StorageManager" as StorageManager + +participant "xyzNutrientStorage:Storage" as xyzNutrientStorage +participant "xyzStorage:Storage" as xyzStorage + +hide footbox +!pragma teoz true +' +'Ui -> mealStorage**: Storage(...) +'Ui -> drinkStorage**: Storage(...) +'Ui -> exerciseStorage**: Storage(...) +'Ui -> mealNutrientStorage**: Storage(...) +'Ui -> drinkNutrientStorage**: Storage(...) +'Ui -> exerciseCaloriesStorage**: Storage(...) +activate Ui +Ui -> StorageManager**: StorageManager(...) +activate StorageManager + +alt successful case +StorageManager -> StorageManager: loadXYZNutrient(xyzNutrientStorage) +activate StorageManager +StorageManager -> xyzNutrientStorage: readFile() +activate xyzNutrientStorage +xyzNutrientStorage --> StorageManager: read pre-defined nutritional contents +deactivate xyzNutrientStorage +StorageManager --> StorageManager: loaded pre-defined nutritional contents +deactivate StorageManager + +else FileNotFoundException caught +StorageManager -> xyzNutrientStorage ++: createFile() +xyzNutrientStorage --> StorageManager --: created file to store pre-defined nutritional contents +end + +||| + +alt successful case +StorageManager -> StorageManager: loadXYZ(xyzStorage) +activate StorageManager +StorageManager -> xyzStorage: readFile() +activate xyzStorage +xyzStorage --> StorageManager: read user's previously saved data +deactivate xyzStorage +StorageManager --> StorageManager: loaded user's previously saved data +deactivate StorageManager + +else FileNotFoundException caught +StorageManager -> xyzStorage ++: createFile() +xyzStorage --> StorageManager --: created file to store user's data +end + +||| + +alt input is not exit command +else user input is exit +Ui -> Ui ++: handleExit() +Ui -> StorageManager: saveXYZ() +StorageManager -> xyzStorage++: get saved data in textContent of Storage +xyzStorage -> xyzStorage ++: writeFile(...) + +xyzStorage --> xyzStorage --: data saved into file +xyzStorage --> StorageManager --: saved user's xyz data +& StorageManager --> Ui: saved user's xyz data + +||| + +Ui -> StorageManager: saveXYZNutrients() +StorageManager -> xyzNutrientStorage++: get saved data in textContent of Storage +xyzNutrientStorage -> xyzNutrientStorage ++: writeFile(...) + +xyzNutrientStorage --> xyzNutrientStorage --: data saved into file +xyzNutrientStorage --> StorageManager --: saved user's xyzNutrient data +& StorageManager --> Ui: saved user's xyzNutrient data +deactivate StorageManager +deactivate Ui +Ui --> Ui --: exit handled +end + +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png b/docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..e6a56506ac9b0257d37b7613b4079cd203a4c16f GIT binary patch literal 70265 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%0A23MAyD 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 WtX_ZHSc9KZ)YoaL#IN0R^nU<+u>;-! literal 0 HcmV?d00001 From c4a0012f1ecacf61b22d3aa831b6de1b31ebf71d Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 14 Apr 2024 21:44:52 +0800 Subject: [PATCH 219/274] Update DG --- docs/DeveloperGuide.md | 11 ++++++----- docs/diagrams/ArchitectureDiagram.puml | 2 -- .../diagrams_png/ArchitectureDiagram.png | Bin 25087 -> 22923 bytes 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index c195a163c2..3219358bc0 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -22,10 +22,9 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a - `Parser`: Parses user input - `User`: Handles user input and stores the `Exercise`, `Drink`, `Meal`, and `Water` created by user - `Date`: Handles user's local machine date -- `Exercise`: Exercises completed and its duration created by user -- `Drink`: Drinks intake and its nutritional values created by user -- `Meal`: Meals intake and its nutritional values created by user -- `Water`: Water intake created by user +- `ExerciseList`: Exercises completed and its duration created by user +- `DrinkList`: Drinks intake (including water) and its nutritional values created by user +- `MealList`: Meals intake and its nutritional values created by user ### Ui Component #### Sequence Diagram @@ -47,8 +46,10 @@ The Ui class will continuously read the user input: 2. A `User` class consists of zero to as many `Exercise` objects in the ArrayList. 3. Each `Exercise` contains exactly one enumeration of `ExerciseIntensity`. ### Drink Component +![Drink Class Diagram](../docs/diagrams/diagrams_png/DrinkListClassDiagram.png) -### Water Component +### Meal Component +![Meal Class Diagram](../docs/diagrams/diagrams_png/MealListClassDiagram.png) ### Storage Component diff --git a/docs/diagrams/ArchitectureDiagram.puml b/docs/diagrams/ArchitectureDiagram.puml index e61946dafe..f873e2ebc4 100644 --- a/docs/diagrams/ArchitectureDiagram.puml +++ b/docs/diagrams/ArchitectureDiagram.puml @@ -17,7 +17,6 @@ Package " "{ Class ExerciseList LIST_COLOR Class DrinkList LIST_COLOR Class MealList LIST_COLOR - Class WaterList LIST_COLOR } Class "<$user>" as Icon PERSON_COLOR @@ -36,7 +35,6 @@ User .> Storage User --> ExerciseList User --> MealList User --> DrinkList -User --> WaterList Parser -> User Storage .> File diff --git a/docs/diagrams/diagrams_png/ArchitectureDiagram.png b/docs/diagrams/diagrams_png/ArchitectureDiagram.png index 16c8fd78344415e0452a049889ed63d43da3e749..2038f95d727520ff4be20f94cdf72aa31ea3a404 100644 GIT binary patch literal 22923 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
7g#~Eq0baLq!KBYPr3z`F8dr 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 TT?YS&;WzCw2B-7XZG-;<{=}Gy From 335d08181eadd9cc149d0847dc692f63940edc64 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sun, 14 Apr 2024 21:50:15 +0800 Subject: [PATCH 220/274] Add sequence diagram for User component in DG --- docs/DeveloperGuide.md | 16 ++++ docs/diagrams/ParserSequenceDiagram.puml | 2 +- docs/diagrams/UserSequenceDiagram.puml | 69 ++++++++++++++++++ .../diagrams_png/UserSequenceDiagram.png | Bin 0 -> 88104 bytes src/main/java/seedu/fitnus/user/User.java | 2 +- 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 docs/diagrams/UserSequenceDiagram.puml create mode 100644 docs/diagrams/diagrams_png/UserSequenceDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e87009437c..1f60ec54df 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -47,6 +47,22 @@ classes when loading and saving data. XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ ![Storage Class Diagram](../docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png) +### User Component +#### Sequence Diagram +_Note: The following sequence diagram captures the interactions only between the User, MealList, DrinkList and +ExerciseList classes._ + +For diagram simplicity, the following choices were made when creating the diagram: +- Only optional blocks for handleViewXYZ() and handleClear() methods were created. + As such, methods within User such as + handleRecommendations() and handleListEverything() were omitted. +- For methods where the user would like to view their nutrional content (handleViewXYZ), XYZ is used as a placeholder + for the specified nutritional content (e.g. calories, carbohydrates, protein etc.) + +![User Class Diagram](../docs/diagrams/diagrams_png/UserSequenceDiagram.png) + +User class initialises MealList, DrinkList and ExerciseList for the user to track their data. + ### Exercise Component ![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseClassDiagram.png) diff --git a/docs/diagrams/ParserSequenceDiagram.puml b/docs/diagrams/ParserSequenceDiagram.puml index b19f6c7255..1aacbafecc 100644 --- a/docs/diagrams/ParserSequenceDiagram.puml +++ b/docs/diagrams/ParserSequenceDiagram.puml @@ -12,7 +12,7 @@ Fitnus -> Ui **: Ui() activate Ui Ui -> Scanner**: Scanner() activate Scanner -Ui -> Parser**: Parser() +Ui -> Parser**: Parser(user) activate Parser Fitnus -> Ui: printWelcomeMessage() diff --git a/docs/diagrams/UserSequenceDiagram.puml b/docs/diagrams/UserSequenceDiagram.puml new file mode 100644 index 0000000000..9321cc024e --- /dev/null +++ b/docs/diagrams/UserSequenceDiagram.puml @@ -0,0 +1,69 @@ +@startuml +'https://plantuml.com/sequence-diagram + +participant ":Parser" as Parser +participant ":User" as User +participant "myMealList:MealList" as MealList +participant "myDrinkList: DrinkList" as DrinkList +participant "myExerciseList: ExerciseList" as ExerciseList +participant "meal:Meal" as Meal +participant "drink: Drink" as Drink +participant "exercise: Exercise" as Exercise + +hide footbox +!pragma teoz true + +User -> MealList **: MealList() +activate MealList + + +User -> DrinkList **: DrinkList() +activate DrinkList + +User -> ExerciseList **: ExerciseList() +activate ExerciseList + +||| +opt user input is viewXYZ +Parser -> User ++: handleViewXYZ() +loop all meals in myMealList +User -> MealList: get XYZ value for meal +MealList -> Meal ++: getXYZ() +Meal --> MealList --: XYZ value +& MealList --> User: increment counter for XYZ +end +||| +opt if user is not viewing fibre +loop all drinks in myDrinkList +User -> DrinkList: get XYZ value for drink +DrinkList -> Drink ++: getXYZ() +Drink --> DrinkList --: XYZ value +& DrinkList --> User: increment counter for XYZ +end +end +||| +opt if user is viewing calories +loop all exercises in myExerciseList +User -> ExerciseList: get caloriesBurnt for exercise +ExerciseList -> Exercise ++: getCaloriesBurnt() +Exercise --> ExerciseList --: caloriesBurnt value +& ExerciseList --> User: decrement counter for caloriesCount +end +end + +User --> Parser --: display to user their XYZ content + +end + +opt user input is clear +Parser -> User ++: handleClear() +User -> MealList: clear mealList +MealList --> User: mealList cleared +User -> DrinkList: clear drinkList +DrinkList --> User: drinkList cleared +User -> ExerciseList: clear exerciseList +ExerciseList --> User: exerciseList cleared + +User --> Parser --: clearing of lists handled + +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/UserSequenceDiagram.png b/docs/diagrams/diagrams_png/UserSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..9aa268fd3d6fe61884febabd54eff8acb5799126 GIT binary patch literal 88104 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⪚dt!PHs-xx!P9o@=SH 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 Date: Sun, 14 Apr 2024 21:50:37 +0800 Subject: [PATCH 221/274] Add descriptions to User Component in DG --- docs/DeveloperGuide.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 1f60ec54df..2b4eae15cf 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -43,11 +43,37 @@ The Ui class will continuously read the user input: ### Storage Component #### Sequence Diagram _Note: The following sequence diagram captures the interactions only between the Ui, Storage and StorageManager -classes when loading and saving data. -XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ +classes when loading and saving data. +XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ + ![Storage Class Diagram](../docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png) ### User Component +#### Description +The User component will create MealList, DrinkList and ExerciseList for the user to track their data. Additionally, +this component is in-charge of handling view, listEverything, recommend and clear commands. + +#### Implementation +User Class: +- Attributes: + - `myMealList:` Represents the user's class that managers the meal lists. + - `myDrinkList:` Represents the user's class that managers the drink lists. + - `myExerciseList:` Represents the user's class that managers the exercise lists. + + +- Methods: + - `handleViewCalories()`: Prints the user's net calorie intake of the day. + - `handleViewCarbohydrates()`: Prints the user's total carbohydrates intake of the day. + - `handleViewProteins()`: Prints the user's total protein intake of the day. + - `handleViewFiber()`: Prints the user's total fiber intake of the day. + - `handleViewFat()`: Prints the user's total fat intake of the day. + - `handleViewSugar()`: Prints the user's total sugar intake of the day. + - `handleListEverything()`: Prints all meals and drinks that the user has inputted today. + - `handleListEverythingAll()`: Prints all meals and drinks that the user has inputted of all-time. + - `handleListEverythingDate()`: Prints all meals and drinks that the user has inputted on a specified date. + - `handleClear()`: Clears all user's entries of the day. + - `handleRecommendations()`: Give recommendations to the user based on their calorie and water intake. + #### Sequence Diagram _Note: The following sequence diagram captures the interactions only between the User, MealList, DrinkList and ExerciseList classes._ From b3d411225a92295286814c4003f5c71d2699417e Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Sun, 14 Apr 2024 21:53:41 +0800 Subject: [PATCH 222/274] Update Parser Diagram png --- docs/DeveloperGuide.md | 2 +- .../diagrams_png/ParserSequenceDiagram.png | Bin 0 -> 30954 bytes .../diagrams_png/ui/ParserSequenceDiagram.png | Bin 31289 -> 0 bytes 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/diagrams/diagrams_png/ParserSequenceDiagram.png delete mode 100644 docs/diagrams/diagrams_png/ui/ParserSequenceDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 2b4eae15cf..d0e438f705 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -31,7 +31,7 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a #### Sequence Diagram _Note: The following sequence diagram captures the interactions only between the Fitnus, Ui and Parser classes_ -![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ui/ParserSequenceDiagram.png) +![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ParserSequenceDiagram.png) When the user first starts the application, the Ui class will be constructed. Within the Ui class, Scanner and Parser similarly will be constructed. diff --git a/docs/diagrams/diagrams_png/ParserSequenceDiagram.png b/docs/diagrams/diagrams_png/ParserSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..055c47b32be98ba86a4f6d48ea00653ba852452f GIT binary patch literal 30954 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 z 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 VmmJpafjgWL271Q2xjNQC{{q9|z=i+- From 90015daf015523682ac9eafd0fdd04416cfb5aa3 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Sun, 14 Apr 2024 22:28:20 +0800 Subject: [PATCH 223/274] Delete johndone.md --- docs/team/johndoe.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 docs/team/johndoe.md 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 From 8000c621e2f9cac83a2fbcf5d929b6a642f3a50c Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Sun, 14 Apr 2024 23:53:05 +0800 Subject: [PATCH 224/274] Add Storage Implementation in DG --- docs/DeveloperGuide.md | 44 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 60668b1b91..b713204179 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -18,7 +18,7 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a - `FitNUS`: FitNUS main code which runs the program until termination - `Ui`: The user interface of the app that reads in user input -- `Storage`: Handles stored all `recipe`, `ingredient` and `shortcut` that the user has input +- `Storage`: Handles storage of all `meal`, `drink` and `exercise` that the user has input - `Parser`: Parses user input - `User`: Handles user input and stores the `Exercise`, `Drink`, `Meal`, and `Water` created by user - `Date`: Handles user's local machine date @@ -40,6 +40,33 @@ The Ui class will continuously read the user input: - Else if the user input corresponds to "exit", Ui will handle the exit. ### Storage Component +#### Description +The Ui component will create a `StorageManager` to manage the reading and writing of the `Storage` (meal, drink, and exercise). +There are two types of data being stored, one to keep track of what the user has inputted to the app, and one to keep track +of the nutritional information of the known meal/drinks/exercise. + +#### Implementation +- File Location: + - The user's meal, drinks, and exercise data is stored into text files in + `./data/MealList.txt`, `./data/DrinkList.txt`, and `./data/ExerciseList.txt`, respectively. + - The nutritional information of all available meals, drinks, and exercises is stored into csv files in + `./db/Meal_db.csv`, `./db/Drink_db.csv`, `./db/Exercise_db.csv`, respectively. +- Format: + - All `Meal` objects in `MealList` will be formatted and stored in a string format of "`MEAL_NAME`,`SERVING_SIZE`,`DATE`" + - All `Drink` objects in `DrinkList` will be formatted and stored in a string format of "`DRINK_NAME`,`SERVING_VOLUME`,`DATE`" + - All `Exercise` objects in `ExerciseList` will be formatted and stored in a string format of "`EXERCISE_NAME`,`DURATION`,`INTENSITY`,`DATE`" + - All meal nutrients are stored in the format of "`MEAL_NAME`,`CALORIES`,`CARBS`,`PROTEIN`,`FAT`,`FIBER`,`SUGAR`" + - All drink nutrients are stored in the format of "`DRINK_NAME`,`CALORIES`,`CARBS`,`SUGAR`,`PROTEIN`,`FAT`" + - All exercise information is stored in the format of "`EXERCISE_NAME`,`HIGH_INTENSITY`,`MEDIUM_INTENSITY`,`LOW_INTENSITY`" +- Loading: When the app starts, the `StorageManager` will load and parse all the nutrient information from the csv files and put it into +a HashMap in the `Meal`, `Drink`, and `Exercise` class. However, if the csv files are not found, it will create a new csv file +and store some pre-defined contents. Then, `StorageManager` will load and parse all the user data from the txt files and append it +into list in the `MealList`, `DrinkList`, and `ExerciseList`. If the txt files are not found, it will create a new txt file. +- Writing: When the user enter the `exit` command, the `StorageManager` will retrieve all the `Meal`, `Drink`, and `Exercise` objects +from the list and format it into string. Then, it will append all the strings and write the files to the corresponding `Storage`. + +#### Class Diagram + #### Sequence Diagram _Note: The following sequence diagram captures the interactions only between the Ui, Storage and StorageManager classes when loading and saving data. @@ -100,8 +127,6 @@ User class initialises MealList, DrinkList and ExerciseList for the user to trac ### Meal Component ![Meal Class Diagram](../docs/diagrams/diagrams_png/MealListClassDiagram.png) -### Storage Component - ## Implementation ### Information on a Particular Meal Feature @@ -119,19 +144,6 @@ The `infoMeal` feature is executed on the `User` class. Let's say we want to fin - Using a hashmap, access the data regarding the amount of calories burnt per hour for the given exercise and calculate the total calories burnt for the given duration. - Store the total calories burnt through exercise in the User class -### CSV Storage -- Create three CSV files for storing meal nutrients, drink nutrients, and exercise calories information. -- For each line in the CSV, parse the string with "," as the delimiter, with the first element being the name and the others being the nutrient/calories information -- Save each description name and nutrient/calories information in the corresponding hashmap (meal, drink, and exercise) to be used by other functions. - -### Saved Meal, Drink, Exercises Storage -- Each meal object in the meal list corresponds to a string with a format of `meal_name,serving_size,date` -- Each drink object in the drink list corresponds to a string with a format of `drink_name,volume,date` -- Each exercise object in the exercise list corresponds to a string with a format of `exercise_name,duration,intensity,date` -- To store, convert all objects (meal, drink, exercise) in the list into its corresponding string, then write the appended strings into a .txt file -- To retrieve, parse each string using "," as its delimiter and convert it into its corresponding objects, then add all the entries to the object list (mealList, drinkList, exerciseList) - - ## Product scope ### Target user profile - Have a need to manage their dietary intake and exercise routines effectively. From c7857148bfb6b1b0f9b56d06c6a57086d7ddaa68 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 15 Apr 2024 00:17:50 +0800 Subject: [PATCH 225/274] Update user stories in DG --- docs/DeveloperGuide.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 60668b1b91..9e25e4ea29 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -146,11 +146,30 @@ By offering a streamlined interface optimized for keyboard input and CLI interac ## User Stories -| Priority | As a ... | I want to ... | So that I can ... | -|----------|----------|------------------------|--------------------------------------------------------| -| *** |new user| see usage instructions | refer to them when I forget how to use the application | -| *** |user| add a meal | track my daily calorie intake | - +| Version | As a ... | I want to ... | So that I can ... | +|---------|------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------| +| v1.0 | new user | view all the commands on how to use the app | navigate through the app easily and be able to use all the features | +| v1.0 | user | add my daily meals and the serving for each meal | keep track of what I have eaten in a day | +| v1.0 | user | add my daily drinks and the volume for each drink | keep track of what I have drunk in a day | +| v1.0 | user | add and view my daily water intake | keep track of my water intake for the day | +| v1.0 | user | list the meals I ate today | view all the foods I have eaten in a day | +| v1.0 | user | list the drinks I drank today | view all the drinks I have drunk in a day | +| v1.0 | user | view the nutritional information about every food and drink | choose to stay away or consume that particular food or drink | +| v1.0 | user | view all my macronutrients (protein, carbs, fat) intake for today | make sure that I am getting enough macronutrient and not exceeding the recommended level per day | +| v1.0 | diabetic user | view the sugar intake from my foods and drinks consumed for today | keep track and not exacerbate my diabetes condition and damage my nerves | +| v1.0 | user | view my calorie intake for today | increase or decrease my food/drink intake accordingly | +| v2.0 | user | add and view the exercises I have done for today | keep my self active and exercise frequently | +| v2.0 | user | view the calories I burned through exercising for today | keep track of my total calorie intake and expenditure for today | +| v2.0 | user | view the recommended water and calories intake for today | easily add or decreasy my needs without having to count manually | +| v2.0 | user | delete a particular drink/meal/exercise I have done for today | delete the stuffs that I actually did not do or consume for today | +| v2.0 | user | edit the serving size of a particular meal I have eaten for today | correct mistakes I made when I added a food | +| v2.0 | user | edit the volume intake of a particular drink I have drunk for today | correct mistakes I made when I added a drink | +| v2.0 | user | edit the water intake for today | correct mistakes I made when I added water | +| v2.0 | user | add a new drink to the available drinks | add drinks that the app did not recognize | +| v2.0 | user | add a new meal to the available drinks | add meals that the app did not recognize | +| v2.0 | user | add a new exercise to the available drinks | add exercises that the app did not recognize | +| v2.0 | user | store and load all the meals and drinks I have consumed and also the exercises I have done throughout the entire lifecycle of the app | view all of the existing data even after I close the app | +| v2.0 | user | view all the meals and drinks I have consumed and also the exercises I have done throughtout the entire lifecycle of the app | keep a record of my exercises, macronutrients and calories I have done and consumed for a week, a month, or even more | ## Non-Functional Requirements 1. Should work on any mainstream OS (Linux, Windows, MacOS) as long as it has Java 11 or above installed. From 9c23a44505675ec3609af03975af5f2b972e17a4 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 15 Apr 2024 00:22:21 +0800 Subject: [PATCH 226/274] Add Storage Class Diagram --- docs/DeveloperGuide.md | 3 +- docs/diagrams/StorageClassDiagram.puml | 37 ++++++++++++++++++ .../diagrams_png/StorageClassDiagram.png | Bin 0 -> 45494 bytes 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 docs/diagrams/StorageClassDiagram.puml create mode 100644 docs/diagrams/diagrams_png/StorageClassDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b713204179..56db2fa75e 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -66,13 +66,14 @@ into list in the `MealList`, `DrinkList`, and `ExerciseList`. If the txt files a from the list and format it into string. Then, it will append all the strings and write the files to the corresponding `Storage`. #### Class Diagram +![Storage Class Diagram](../docs/diagrams/diagrams_png/StorageClassDiagram.png) #### Sequence Diagram _Note: The following sequence diagram captures the interactions only between the Ui, Storage and StorageManager classes when loading and saving data. XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ -![Storage Class Diagram](../docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png) +![Storage Sequence Diagram](../docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png) ### User Component #### Description diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml new file mode 100644 index 0000000000..534e7bb258 --- /dev/null +++ b/docs/diagrams/StorageClassDiagram.puml @@ -0,0 +1,37 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor CLASS_ARROW_COLOR +skinparam classBackgroundColor CLASS_DIAGRAM_COLOR +skinparam classAttributeIconSize 0 + +Class StorageManager { + + StorageManager(mealStorage: Storage, drinkStorage: Storage, exerciseStorage: Storage, + mealNutrientStorage: Storage, drinkNutrientStorage: Storage, exerciseCaloriesStorage: Storage) + + loadMeal(mealStorage: Storage): void + + loadDrink(drinkStorage: Storage): void + + loadExercise(exerciseStorage: Storage): void + + loadMealNutrient(mealNutrientStorage: Storage): void + + loadDrinkNutrient(drinkNutrientStorage: Storage): void + + loadExerciseCalories(exerciseCaloriesStorage: Storage): void + + saveMeal(mealStorage: Storage): void + + saveDrink(drinkStorage: Storage): void + + saveExercise(exerciseStorage:Storage): void + + saveMealNutrients(mealNutrientStorage: Storage): void + + saveDrinkNutrients(drinkNutrientStorage: Storage): void + + saveExerciseCalories(exerciseCaloriesStorage: Storage): void +} + +Class Storage { + + textContent: String + + folderPath: String + + filePath: String + + Storage(folderPath: String, filePath: String) + + appendTextContent(content: String): void + + readFile(): ArrayList + + createFile(): void + + writeFile(textToAdd: String): void +} + +StorageManager ..> Storage +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/StorageClassDiagram.png b/docs/diagrams/diagrams_png/StorageClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7f0e2cf00f5452478f0deb1ce7d6c4b29f0c3c48 GIT binary patch literal 45494 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 literal 0 HcmV?d00001 From c80d48ca49fe715b148a4ba7a9da6f58edfaba55 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 15 Apr 2024 01:11:40 +0800 Subject: [PATCH 227/274] Edit Storage Class Diagram --- docs/diagrams/StorageClassDiagram.puml | 71 +++++++++++++++--- .../diagrams_png/StorageClassDiagram.png | Bin 45494 -> 85740 bytes 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 534e7bb258..02212be10b 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -5,6 +5,56 @@ skinparam arrowColor CLASS_ARROW_COLOR skinparam classBackgroundColor CLASS_DIAGRAM_COLOR skinparam classAttributeIconSize 0 +Class Ui { + - mealStorage: Storage + - drinkStorage: Storage + - exerciseStorage: Storage + - mealNutrientStorage: Storage + - drinkNutrientStorage: Storage + - exerciseCaloriesStorage: Storage + - storageManager: StorageManager + - parser: Parser + + handleExit(): void +} + +Class Parser { + + parseMealStorage(data: String): void + + parseDrinkStorage(data: String): void + + parseExerciseStorage(data: String): void + + parseMealNutrient(data: String): void + + parseDrinkNutrient(data: String): void + + parseExerciseCalories(data: String): void +} + +Class User { + + myMealList: MealList + + myDrinkList: DrinkList + + myExerciseList: ExerciseList +} + +Class Storage { + + textContent: String + + folderPath: String + + filePath: String + + Storage(folderPath: String, filePath: String) + + appendTextContent(content: String): void + + readFile(): ArrayList + + createFile(): void + + writeFile(textToAdd: String): void +} + +Class Meal { + + nutrientDetails: HashMap +} + +Class Drink { + + nutrientDetails: HashMap +} + +Class Exercise { + + exerciseDetails: HashMap +} + Class StorageManager { + StorageManager(mealStorage: Storage, drinkStorage: Storage, exerciseStorage: Storage, mealNutrientStorage: Storage, drinkNutrientStorage: Storage, exerciseCaloriesStorage: Storage) @@ -22,16 +72,15 @@ Class StorageManager { + saveExerciseCalories(exerciseCaloriesStorage: Storage): void } -Class Storage { - + textContent: String - + folderPath: String - + filePath: String - + Storage(folderPath: String, filePath: String) - + appendTextContent(content: String): void - + readFile(): ArrayList - + createFile(): void - + writeFile(textToAdd: String): void -} -StorageManager ..> Storage +StorageManager .left.> Storage +StorageManager .right.> Parser +StorageManager ..> User +StorageManager ..> Meal +StorageManager ..> Drink +StorageManager ..> Exercise +Ui -down-> "6" Storage +Ui -down-> "1" StorageManager +Ui -down-> "1" Parser +note "Some parameters and methods omitted for brevity" as N @enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/StorageClassDiagram.png b/docs/diagrams/diagrams_png/StorageClassDiagram.png index 7f0e2cf00f5452478f0deb1ce7d6c4b29f0c3c48..da82f502d3d2230b11834acc2d4bdef8e8b2b712 100644 GIT binary patch literal 85740 zcmbTeby$>Z+dVuM1|o_A2BCB}BCP@<-5sOAfOL1MsHAkK(lEf#Ie$Eao-5Zn&vmX7UwK(^ybCukKp+r2iN~Uf5Xk9$2;}74xs%|N z7uSp|!T%WS#MJHdEv=l*V1{-OahL_n=BXXb;I^Lg?Pqp&RP6L zRX8P&^+%I@-awJ3L0h$}_k6>GFJGwY77CH1j)^m>DQM($tf_m5gWI|Dnxhd{`=wjO zTGO;*7sjzAQvK_hPY=HbHOKR<2J8rBL;KNfm$u9AC%oV$^DKLmG8?s;F#8crM>*p( zxV>6{7P>0%#6tD`{*wc~!lf~W$ncjnIH3af;@{3gPshCJQXt_si@b3B#+SzBk35^WIB+m761UCST~OP12^E!3G2AMRui$D4*S~sJAyT#OHYq z17AaKK-s;&Sw6B448O^b)OF?WH(VzH}PCsn>cZ zMU|d7{;>9`r^V!S?xkRk-NvNl-uux>M+OfvSWQLAzk9tkBVVSPADLRnOI97x=`=}8 z%OM(O5!yG=GWXPgyK8oB2(909Q0Z`ZQ&^1`{wz9Sp#$RoiSJ5ZVUs_DmWm-cggP&c z(1=`MI*(?0RtZxoz2hWyNmRj?EFhVHMa&vO%V&3V?%LG>#c9eXZF??U0ahykqajrr zO>sywS~aUg<~g&xoi)KYqf+kpwtzKS3&P&p4+m{j&5Fo%G3Me4*1?jyv)fQRldB{6=r=l4Z7*s zpwmqjDP&x9_fb^W^C9!WU}8LLX;geNjXon{9BW z_3aHA8G<>&%D{^Q=}c|2xc1W|-0fqGrX!n7o&t^eorJr1u2!0gvQfxyAHuSA&cD!v z$llCRHo0N`r78D{HI*S}(DjD+PlJ>4-<+nP0Rl#9)r*gcc8A{C8roMuU3oIT&2Wvz zzlrOyvb|{``?=k?{6WUI^tnaj@?Fn2aqrK*o#`ceM@XmC@vh!9`t4#X+ypA$ON(Ih zxsA@YH!p3YadD1Tf4tWDHv53>fe`*_u6Y*iGfz*Q#p!q}j{NlO8k+=haJo@BjI65G z^yESTA)$bo?Au052L>x!cWXInyTg;(55~G9aW(qTm@I`c2L^>8U3iuwwkd$^=G&P_q}pxN#Vk%|`Ox$ zIAL)QLVfjr{h-nUg}gyPw&qkqy9^PbSE;lcdm~4B&+7g@Hy$LPok|z-Ja20ihih|{ zZ97FUE2B1DA7mkrFJcpE7j?k5LHJKV z?i2e)aeyD6fGmMYflph&kIz7UJ%n4$RFi7cJ)w~O;rP=lA1+`&C8Es|X9eSVo&bTo z^QTgsgRN1Q+>;P=`SY%Vhphgr^s6R^{(g11kSDYd$Q;FULKh7;2??a9!tw8&&j0ay zzT2z}$M1uv&Z(paxVJQ$F5Fm?muAq{{r-vh@1IUDe5>F)2zN2;`)H=-h!1PS)h++W z5N{qVM_j>GgB#U-ek2q7-!I@cSvyNe?yA=t`UVt5Mj>uas! z1v;^W$oz&@+Y>ywi52 zYxi~BYapEoQ`KtFH20lS&NFP)jZ85gB~sGn$O=;@PiA`!9SZK1;-Bx?P?x)5T2dew$m$yGqNJ^H(;g7uE6M8Oo_lMxy-sw12X%Aq>acT8 zh<+twk*K?wH0_S=qmvD=Kw2B4&spS+cj&v-2LyOy{3*KHp z0+V9$9DaZg!5w*B`5QaE8;f`Citm}MrQ3|U?+kv;oCC)&`Q@9p#{KWZmW+qDNUaa* zt2k^b64bkIop`~xO-_8LNHf7@y~U-qpYb0{+u}K)v(x;5{V|_|L_pM%5YueLgWN}N zh40yEZteGH>w8?Ww#ZUUG>O&crU|JTd8>M5B7XC|W2pLhCE9mewKler? z8G^#q&|+7)G)u~zzW}+*zr{GY1`i`Q8Cu}zH!*+z`%vd$XmvOFJ(Og1qV!?%9esVW z^;2_norDE!x4DufT1zPyTRb-1!GgyXdYC>DRZgLiX$>#H5A?gc%FcVQ>5R_{WX+sJ zOC{ZiqP@lJ+!PZ<8i#Dty|5(MVnl(e)(o6Fgavg)pivD z_s)=ZOeWy$^hajQU)eOMezUNBz7={VRihTQj7juRbyh3Q1V_l3MGFy7qNzo9d_VFD zEFasMMctw7C*x%d)dfrNIZ9V`hH+mNH;Ipjeo=31)aaF|Jpd&_k)98W9Cfu|pTHAt$js+!rPn1cHs##M`Fl@GP zvqc?V^7mve$IQ8lS z>oo}t;(^qpE&NNy14XsYL7U-V(~-ycJ@j~jw3e^pk=LV3va)$(iMd`baAEhB3)tO5 z9Z%JaYE6;4kea65B^$VU^XIDdcgE-`4ZX`@`Cu2|hiF!M z{Ast^^F0iL-;}cL<~g>~zpXJ&A(1nKgc78mDe6CbY^GnEyG^3ZWMWYmPvm}`)Csb|aAMmE@tNsRF zr?Rf<-ON@#HPfPh+>S-AKHJ{9j#J)#sk8)|C48G;s9%bg`Sm>3@-9xlk4GFm409gY zN{_ERJVe4MHd>rvY)@q*;dz1)1#&XA79!%b2Ju~^%44kA``-&bDs=hA%!-}CyVa8; zLOYbAEAk5&$^39}9*O$4WfkK^bD`fp{}8bsWSaPJr?=uxSHU6&YmR``!wsK;U5;K@ zPG98C@ex>$aWdt4R&3X)03)fk@!}im7+udYQ|j!L9f4WvVpdb@@S(=rd6=~Uot$76Qaes z#hf~1%vz|;+8gWNqij$W@%}U~g_N;hhWP8txK2nTOawREzy)t{vgz)}P>qbv?gu6f z_ttuGIBb3opO;nEn{f`=ZbP8|;AKTrTt<}Jsja1Ao%PJ|o=z6b)H{wqi9xDa_&{#0 z)4-igLK{~7+|s(^AT^@1?v{|f#Xyq+#TYYY!+-c~BDY+AthaLqtr2uHSA`Y;KKsgL z4nR11{rw3Ods4#u-R5(1WhcEN?ixj{+jcuJb}76v_=TNox*$OD?W2L|1dNpH9K^_Z zO-vkkiTpt4)N|i$gsAvRTZ6CY>5fvfQDlFUVud3Nb+IAOF?ca1`KpEcn1g6xdTi7+ zD8?Z12{%5PQ`lu*Gh|J4gRqYm;~sLbBtv73dqn0wealg-&4EFyqpQMf!7C}z{6FEe zLhTrkCnhL(vV&^=6I%URL3DJrQ)+asVgMDsTGHE0WE6&mSeP>ra3rJs*1<>sX~o< z$xL%+Qo5BzaI_k^ERznH9d(O~iFZHSrfKTy6BHB)#;oaiJmxdFF{&yusP$D|n@`}r zQSjyQMK6!1Sndb2O$QSS@q^H4?|30vJX;p76U{HId{Zq@+!s1^*8qBjlNE^qVgKpr zx$nD-NxS=|E(uxqp%P#_0Qv8A)>4ttkXCI-RymR;wC?q1b23jS6^h@u7*~c2sBWH` zQ->?)TdT5|UY`Cs74EbVzob#a)6@4^sUnt&3{Wr8<(uDDrkVF{)$FV%C(N&>FTAe* ziN$27i24KgulUp^Bfn|gVg+O%0tTbkHWv-8Ra{te?DP7||Hfb9HZDSN2_D-mRkqTZSGfuzm-wfhH699YP>ZVJ?J5*gh895BIRLfGwaGCE1o^zdGT4Q_iA^1f>QCK0% zR?q2kx!{ zKr61rFA`gs#H!W0UPAh`{@xQWUtCe3uw^ix2(&zXI&aid`&FBX{X#S2Vy+}M^jZA- zo|LJkG?0_YDW%eFPcrUn4w!d);X?J+@7vVM}js`cVt zbCi$@*!>0s66M;K+PqjA4Q2Z;cxF3>XQmY)&qfcJfQNk{vJjQMfsKL=|K^3(ipt@v zXcE$h-Kixwg=j^&>g6n^ZCQ3%5OlKA%}mqYZ7$sJ)O*CF$=sk~I)HbbO|*1ghj;U% z>+_79@tfDL^kqu)aKM(tE)8h29YZwglc?`C1`fBdNOLi+2sJA^8=?@!8-U|N&=om9 z7J`wLAKa8dfgh=#eT!noIf)o+mf7U zbd-2&q~n3*8vzU~5h0C@Z%aNEQm&nR-mZ_$x4Wt6s+iQuj@Kxwj!83an~X$%th^Q{0=YJdnwm%n(2|0k5RcF8&~PTTF7!KrXtg1xiXe4#GBHHc{tb|=7jMBA&_?e?QD^z4}cam zv>g35$~THA$KC{bFtVxhPAw^V$PQaj^Z6O%9Wv1sJZYDS$X?Q7c3aRcV7pS=45n(yHe3Ms_i=Qt_MfSe~YxQF$&^z%jOc1f3y`ihVsGVzl3~SxEhRQ5| zLI2j%;~!D1%@heRIOF^I%e7RN(;O6gT0O2xJZN{#$pB%C_;CjBUl-ST^M44k-NTP> z(*KiQ@#~?%mvKCnCK(XIA9sP0<|hLP=}n_!cg>1I0m)`_<^_ zH>%`m?@k5@_aBy=K1}h!K6!;uZ6acu(Cd4aEi+j+W0;rMZmOblB3y03l;&SUb#BX_ zFR%7vTa#_utwmoGBb4&3)2ecidC0nPtqUZ6Y{@6Z>%^JtCvq3mctALf7IBF%5;-C1 z-cDn=yG_FT)P9ft3aJ`t+tzAVnfv2t=eP)LiZTbJGdeB05U1^BxjP#V<*s0rK*|;) zIs)@k`bJfiuH`OHkJ{7+xoyHh;`B3iH;`-0f86!;n12*#Cd*b`Ycy=}S6luB=fvSy zoUQHQ(ROETzkl#WR?PYOaY|q;TTo8c^~Lg2v83EiID?L69@JLmEG@15NoWm^l7K0? zG(2qJk8pkkh%iJ{m~4)w5_s#@*7@;`WHI#zN%SNlhxuVny;CXMbEm`wcaG18yU|0j9ZNzAb+6I~I?whj^VRnX#^*rtO2y}(GxIv)tn9^TE~S8o zU2qM2?lV%v{17*MrF7*l0adc!Y-a-iL@arC&PTVyaa_~=z;b{>Hx@)(7O&uKLZ5M1 zj-bMo2KpA&pgkGs(6aX_^)IIb_8k6A4N+i~SS7p+ccHv(HGMcqVW0|EV(pChp%l#h zng#XR%w?DNzYdJCVw$e+UFs0P<5Ud*bt2I%?|xCzzB@LA_qkW5oTV6hHR8cWHXiF; zOY^m0CV#Y^0AQyXLF@pFdK_Z5;Rs%4`?xYW71yw=HAciX8K?1jCG*Td7JhQNk8_Jt zeT}|ukXne~0(F+u!37_}j`0HMjUZ@3{A>$0D`(ySK&%*!7cPzDeWk0eCv^<%>0oQYDEgLr^oz;P zK`56xr-QZDnS%w>bRj4F@8O$Trzn$eavN&`q0~yb*g3BG~UQT_m#j5YJP> zihidK16s~3*vQXf2nfL~IFboYw&$wZlzxt=_x)p#KJcapnFu*xiAq-TbwgX`l2-2c ztMb83V}FPAIH>$3A`hE2{w{)izNNIXwOE2soz@|xVW zt1W=$btxukZf3p&o74&Ln@2f+QikS=G~M6Kpvb~+A1NJ}KpGx6=ZPbrf~yPP=z9_} zfpA8#8dD~yfq1{?{%Kw9gt5i@?F&0Vuf=pt{~#!B5TXn}#4@wk(ES)%6v;zYWxr>D zAg_nee4mTZZ3>_K$yYgoHmY^mAVGV>TAkAd(kCJiet{Ue{Ow3zl9PeZWolW(f|^ROml4_67VUn5>6C!tWK3pL2iNNl#9cEN6w%g=3U(VJ+$voRt3*GMbdC+lJ@Bq0eck*+HxJW=k4v)kwO3GVLpZrFl=WKANKX2?=V-sH&=32%y9BvuI{M{G@j zXm{ET@*XzpNMN8ODUy)8^)(UTqnbh+B2MPZDSXv{TS-2xlUdcT$AyPoAcNh7L4Tk6!) zRpyePJ8KQ>=e{IAe7$a2doaUVOU7B7Q~s$NrqmL}y1iX1eAHgs9npO1tP<2^KE`Ic z#SfmVDX8Pn5zV_WpRqXI{XO5mU?0C4r`=tNhvgcvosA8~^JsOxbBl@|Z=qXjFu6X= zr1!fD>&(b1M=ZCi1Tt}AUQ1ds=+Lh2iTQ+?oE*=l2GJ1-GYd^8t?8N~&`2w4T(TCd z1JhjGEHKXHN*>-ZkrlA9GyVL=BUh`|uwclIo!eAZ(A6U9dOUxvRzQSD`%O__ z;T1Hoga5}UBgg(+EhXFWQU5xBieXSsd1L@cEI`|#KEVke=C(5xCKM#RB53s_*oQ7g z<0#l0=i=O5*N(w)3leClz+J9lI0rou2?-|f@yT1ElS$6$sPef7wTBJ@)b=kP-;@0O z?!iZmMxjdE?N(|jT71&sMoi$ug|W(#qxspkn4(A9OE=z0`@IT|=Qx_l4V%ziPe@L- zJ$!loXm3lN1@DY{Kmc6@SJS?ql<(S@E7VVm&RAT@1sD8Bz?$H~UhQHZ&t~1U%2QN- zzZypayH4sDUewOPt34)v&p;yLu-UK@r!0XeW&}bbn?%b^mq;y>g*U5=Vb?p8mys^B z`q^QlI3v^DIMzqV)QQaNOzQU(0{Y5SS#zMZA1crdz8~W&Cf{6~PpdIb6#IR)upIP= zrD{SJnY=P4Ty=C`vMsfVXWUIAHN4K=HhkBlFPm=s^wp>7k`cnf#;Q!}yA3%$r}Z!g z_}&a`JgC7^Z3d0t%`99RWj>Sxt1%Va57#+4wcDOQf2q2l^G=ta9OM zsB&Wke&j61CfIV!gu;^tS5F?WiQS2YOx*j-}741Mbw-;At z$TVIGjzR> zIX;3iaW%IuMKG#u$v1efi)y&whT++mSwbJB>akyzgO0shajVPFw>Der?3&P9cPk`f zjhHQLKO0+6KMS*dz0h)SK3gq~SE^#EdfzA^o}@jlo!A!L-`o;WZ80W9{jhxf=uDFq zoOlc1C<_a$e!wd#%KMq>I9DgdTJq2M49g6ZQ99PNy4d?w+fgq($EZw)2!JbR<+v?M zW0X)MRmmJ#hqN{IYggr*7=0fiL^IZ_`9tswDm`|mXWv{}E`lv~=jfAb1YC8#t4^Y& z9Z<>HiIXNeqfuyAxa*i|OJ?|VLN|)VlLaRVvBX{b8l@4-I8~$RuMc*sf{7*ydzpzW zv&rJ{x%B-z8KVeI@`7ixxr}s<7VdX=v2HH(xwpkJv!tuQ)%G`W%}|)tSdVs{I^xe? zKMD?)x{KJl{B=4x4JQ(6ti5-qC{=|JF`aiA>4A_1fvJu9mWc;BHU^yMcfcf3KzwfB zXBS$G_&Wuk)xi5>Z}J5y_%6JW@3ge5cw1#Yc}{VzOycVFS}De#X$y zlFD~Woy7C#^EZcOl$AC8NV)aF)uEBT?a+iCqkwC8$;-3Q!tmy)@LdlNIia;z+W|2t zQ)#^eokbrf1}F6R>`in^b8K1g7NnMigS#^obX@m2D4Kmp=w@Nlo==4j;&=PCWW+Ka zM=ao=WvdJ7`?8Y)>x-BUc{R1A6Xp6R(wI=nf{~{-710=_{PKtP(}$;-6O-F4hboIT zOBj|%c+@=k%FOc1uTLBK$|VlJpH~ycRXAHaNOwsGSuEZ$RrDB1_cK&NhM!So zR+L?%4`DIUWm{2ZEX$tcR;LIpYSuaw6qi*`@Q@U3R5@F8;JRT>PGE>Kr2ZNF5;{&W z?B`Y}k@AHYxH-R!-a)cNPtyV9b!3K7L~BvYydq27+u4|-;ri|TIEJOzP~+QBST zk*sCc<7&E!%cl$w-@=w;K2NGOIXkx(FouGfG((tsgRDn}Ww}6VO<;UD{<3noHxW?t zwa5F$M3}1FlTJ*~H~B{+Wd5XXKsM|_GJ|;T`ImE!td?El-|M4@fu>U?&r0vHUo#uW zP0X4Aico2fax>4sry}@Yi$yxxB6bER?@S&Z@N-ThQ7tg9N}vjhDLGK-`Y~MD9C^n*dLuwlcq9|Xv4v~Z_@rojulAu=`uwE{%9A||4sv8o-3wTr@J(XXAB075^_eY@qi5VNHNBG!S)9<%19?8`x9KHAZP57z4 z;VvpE4^nW`lAq^0)Q0pjg+XDmZl7yK@A5Lr_1QN7qy zP|w|K(!1j&k}-|6%;hV*6IDXb{eR8x80QDm6w@T>^$R}zE()QwD|CUD{aVYRG|GwI zult%Wu~;$i+5|klO266C)$IJ)x3$Fy=m_?b(%3?GFM2WPXb2G#q?4qYX1M(BseW5f z&5j}Cl{Bt{LK#b4OT1}qon>X|z`()>mgY7b|D{9%`L2CL`qHI!8RX9-FIn^g-nqBW zx(joC($_Ccs1W{^B3&3e)36B-(~pG5EyPLTSElES&Gi1)LJ?CCD9tAY!XDtiL`lX@ zBd|(A>e%yHxO>cF(*)>VmBlQh$kkTGhOn^Gg|s?M=QgQuNtWkX^b9D9_a*tI3UOJE z=z{aM{Y%2^^|o16>#TBdYO$kbU`HdHTxZPxk|?#xon4x@U;P#+|C#;$JXAw}7K6)J z9Pufm11rplX1z}GP^juEB2r4;dzy%D9#R7`fv-lDMh|kUX(-#nep>p5Yfrv&E4UxT z*4tS$o>6F!>dvMvtFFhPsvjonS6#euhlOtVB*@5XHVV@ppyl0Vt{{I^_7m6tRQAz# zLqIBdhFaBPjR;$kB4+z#2IzFV`LD^K#So#&L;{bc%jkynH8G8+zO{+NwFUX?zYbfN zgAIL12+$c@sw#j&A(5CCMfS5QbtSWR^{MK=Wr0YaaUgT@@&fy>403G|dadU~{^?7848R1HL-fPKr0bLHR}S_* zlswVw044~h{^O6TS0{@=o~^H^h3ROAc?=8ROV#N-oDu9->aWoJQ-jh9;P$Y$d5iOw zBtBkSP(bVKrmE*&IANrHUgWVQ>;LGk`rjl@Ep2Z1$xCPnI5S*_`L}-#rs7-n!CxcH zqtae})h|eJ*p`)w<@ zdKRD^z-c})#JZO3CK4}g>~=5_otOje>W<#C%~Z$KMt~m{sN<40Rt2O1aP(s$*X2Nc z=1senZUf4|#xAEXv)~?M6t~ZX>ugk3->rry8C<4uYBQ2l8rDX(1;=wLyd7cI)ePJw zV$AAk6>7k@2Wmbmx+vh^_+_;kdZ(Me_qwqBqQ5E8fHW{>CDL(J00V;!H~o?67gv^K zzQ4#VeX2s){s*yDM3I7JHzWIbYIeGm|MmpveMpVbW1=BmZOQC<*99u@17y5f^XHR* zd1r$!!k`-%6)5C=ixkQ0djGQ;W_Rrb;I)5N!`cTizS`M}K$v6n0;1-|4StPL9#EQm zA{yRg9P4UNE_C-E10TShOaR`o_H$IXdT}EUTw3$X4GT(v)xlqj5x+0ZV;Wt7Q$0%& zx%TM(*Or4uv8Ei=4BbSjK498XJ(k}=HTmx z1ua^q*uc0&igrQznaQ)NZ!I!^o`}szvp{cUnOJggdrWVl^l4;t%jz*Nvvzg8DtkM{ zn2Zkt4_cfs3sVA7+1O&paX}Wi87z6#)c6U*Qc^gQ;@wqF6A}+xpxB*4(Ki6o&h(jj zBu1G^!{JDy%|{GgUk<7@Cr-U-x?9Z%iW@qfn8F#w1%hT7gLSNb;U2B!owGD&&+g)A zvVYOaUmDPQQ_r38Z{p<)c4#8m9ky3uprVqn_+V?A&a@dtP=IFu+kYSUwWb~>7yuub zqG5b%#j{TViWI}#7Q;D(mL!lQO&sAfTp&GcsR0blFml43)d`kb*P zr5?E(a70ok_ncr<;k3?C+#P(+n549sjEe=DfL?!B`eY=#7(*C{SNRNtfU9H75z`xN ztu$2?yUEARldV`(+LTtY?c)cm2eJz~yuc#|EGP>%LJF~D!Qp`3(5#%z2h; z3`Mo;99}emjhlev#qXBy?d-#ND&EV!ItRSc6TZ)Ga^Y`AKDBNqeTd_CU&wS()_N^1 ziFE$1-G+;c zGOL)?b+sLuJvu~<;Udbe7cnUqU$3^yT_5pfa!8M@zjGy0*9H>5Rc zRSZ%=JvRdXeg_Osl6g4h&}PvAn9Bg-EpmBye2Ts1Om|FX)(=8Tfd8-D>>q@;yDVN^ z2QLE(Nu?0+?Ubk%&aG#OQ%?G)xp^+Wh=OHec4gn{Df{xDoSzl@Jp_3 zNyTy9F^$-R&g)pkBy%tM?TR4wEju0l??yT0Z+{b9sZfB5N67kFH;`%{Or$-JKQ@(NVt zcObx+^we+=ISq0#P>(U_Az0QJsL2Fr$yvtZ<`=$YZAfJyv-uF&m4CUZ zdY@885wJgcg#tx!ky)m!B`ujZctctisHRc82=D@}s^==@a@V?r>^VExF66I$><4*8n^xfqgEkSYWY?HqiN^EW-!YU zTc$ynZOZWV98kSto{6VjhAszZ zbk$e-?if6||Ew-2m%qNX1h_@?4lK{$FnT+w*lI*O|6$3)WmL6m($eS%qk(#rqYFaf z@xk=Kc%1=@#zP&YeoI2%G?4dAi^N4V17mc2OQfycp`)QJuXC;r;)_jQ9!nnKVSjcm z=2GI!9$;Z$sN&`0^@sZorU>m>9DQUV9A!{hTNbvite)?bXJ#4s>B=tevPD!^U~QRC z>EyI4XP?b;z=%BdUK{GJK5`k7MhKU@!!6p8SGC#d>-e_nf1i#8ltZV-QxI-EtOyep zT+TlZqkQ`^i*Z?rgG~J=&!XOa$1htcx19|X2$zba%hRl3mGYn~P>JYcVG@Rw_x9gkxi9K>CEL$^VwV9j|xLUZTJl1 zFK{=j?`pd$;w@*=RjGw}sWR@q?X{Ip{a1(5{qs>_VMRukF5_RW94@=&X@(`cowF7C zyVr@jf2?X-Xm7T|;-l9o6t0ZK!Q9rea51U#oxhSp$#+_176>_6*9@iFmFhQU<7-3J zuG__=yCQ!zN`=$aV%8VeBNj)HW1Mzh=iK)>i@nK1t*;`+Ji{4OT87dvaLcp6sQd}} zmSN~uGIsy`+QGJP1FQO2vVGZ8N}AbqTyHYJ_g4`lz%n)um;?C8+D9@&e|KYDM{Oc% zV%SZauG$E$z0ZA2VP=*bDp?AQCLbAw z$d4@}zTTf_m{}?LNJve&O_*k;Vf=5zDuF*mC8xKh^Eoh}GbO^y9<~F2s8~kfbh!1E z9KXWQU#_1IA6T@J1f0$*wVo9#y}MBe?Ex|m0~hCR0X5|;4OiLWmAaH!fT)@v>7D^> z^u=h&fIa319kqmO^Kt4cSI{q7kdb-nbHnS68uKtThnHV(rY^R6p(7L&6~JUk`>? zHGUWziai9(<7qWl>^2A3rrvf_vU>g1XDAM^ofk^sqf04t303NT?a=d&B<%w1QwP4x zBd3`)L%##-ktsfLHij0(J?}a5VY88yKgu@5n+7pL@Y9`PnUuY5q8AK!Wh+3vShGzz zSBD3z++lHW9|nHX1&?-aBa2--(6+|+ zHp#N5I*5Z(uc-c_u}5BgOIq%AH8Dc#V|;sF(%RfSgx)2te)y&Y|C~lryu)I@xp^a$ zCh37}v5X`}{sy+|C8aw__{QQN%Y_=tkYX0#jOq8FEyiCeW_vCn?x<8x`>$2otV{|+ zH+NKzx#FFl8};m&F?U=U?Q+1>uiuyw)dEnhu`^F>8Wg{LnM3}N>>VIFAhpQ=8T6q( zXd>7sghj-b{O$0gfpPpaU{AaRHrI0jJ|;Wetwf!DaP46~YZc`yzhmb9IRMxrrK>B$ z?((yFPqmKLn!yDxCKaQ=&Ir%X-x01Zp$u%y>!clj5cvuH%?)tKH?_n>VmP*18YvmW ze&!O4t1~OgrK7*`m=VsaX8GC$oh4St&?5OeOkK2@T^Y+YPO@7e=;wC&zD1hkI|pB; zd$@biX4fnwlj3*VUrv1jzvEpC)Rskt$H!_4;jxlcfU2b_P1Bq$GevLzoNPJ|fZDoA z@%=)#Qys^jx^AU|BbVg%XvnQp;m=g-=lgR*c4Wu(Q|Ww@hzBp6G)b%Gv$x1GWTh@+bKnI&PL}G?N zH;DccT1_DVIgmhh#y(ORRV_paNd-DG!# z{$8HjE8tjl2|GGmAo)@~5ImMd+Dpbl|Mwbs+X~YfHPX7Cta|N;ONIe=ftQzeIFO+3 z5y8*?qAY^n9gPC71d}|ws%L{cbUv4^?ksuuc2xR#%OLSbk~%}9+R=Lsk0%60Jm2adGP7jxl_W_NxE7IjH2vnnf^jyAgYdp5F1CRDEnQsNL@hT|Y zQ)DZGD8Xx#L6somV(i^cy@}-?hWk4%pg;5WUi+=y%}+-6o0&4&Dh zYgRVhs33UV#*L2%3r4hV0hdDAF7<2DGdj*=Yyuy@z zSsQJyRA)#Ks{VnwJWi;tldy>my!0bn_;H0ZI&v!?uZh#k_-5T_oTF7swBr)-B-X)r zM>Phai+GS!5C%GBq?+zsy?%xI;k%_jT}*i^tG~)*wLUF<3%y~EAz0t3NU}bVWYwL& z);*WttXJ=OmvwBxhg}gD`+!w$#&U$<_GP-D{wSX`qF?94ZtNkW(TYv;35yg9YJkw~MW{+o`@M6p0`-4aXz(X&(}^&yrPp2me3 z;c&_!DUkD|D!-DeW*lk|ZHn>fV0EKF-HML_vHib_TfQ|V3r#q-EqAU6RpF760@g~l z4W2Qv3Er!nA{p2A7t7SdqdnQ6(E+m<$`Ph?(n+7jP#^)Q<9ya3$zZ&5n0yb z8ms&?;yCle1T8|{IqC1#IJaWM`oo=`&f(8@AF+C6p;J@aK(R=rta)w9UQ2Y?4Ai55 zXOfo{XE6wRchwO%(z+CGAY_HpR@87n@j%6~l#`dwiZG!d1v)rI)|~1Rj_3l(J8dpf}l)xe#>!#=;6j^eBt)! z5>bOO;~wIJ#gWw#Z*#@O8`3@Rw%NE0AAywOfTpfKPfn|tb4;&SSy);8BZyzx_7hqw zs9-wENpNE}))1##Jmxf!1vW?4GDUkiKqrDpt4Io53yXytGuZS~Si`JwL0(KroU1^C zHRMbAK7j&$hsDqKq+Wna)13X;Yai@%;_H#e{&GVo%(q?3o>bU+tHcy)ia(Msz!|M; z&?jJr-UziEPe>?j#f~IrvzHS{Y4nrL5?by1pc4v#v{hHCV7hmYp>lO6>&|5Q)M1{X znqv^CW%tqMf!GrCnSjOdHCX(nQ!(3g9@tMMc%5Zp+zLS}T~+M#>irh9vEpk*Q~V_J z?v3T0Gw?d7)w0@M$Ol6(w83KG!}74`;tH86G7;}aH|MRFTlwv+oL=){s_mbTIr@5; zbydAwa<{;>b|7g{8zw>lmzUfUG)0mB&=Y+?slxB^4bUO+JuQk^SH2&_V)gdG^Xr!l ztdZzum0y*yZeviM(c{60xaT>k7k%rQ8R+c=y_CFBw&zI%v^#vB=N?WmSVLh#o!HyV z8^uh{%hUh}sa?xqwAK^4zX|>*!U-UW-CY2jk7auPguTsMZ0pZv&M!X|_?~}5n)PD? zmDzgMJhp*&V&z@A6Z*92p}Z)zi5EEeL4z~LsvJnxfPeem!e2E1!pulw!E0QW%TOb^ zn-lbJZCcV2Q0rxs2d3C+u!E-5^JGG@ER>rcjabVT2^kOwq0~IW{Xk!Trtvs>qdJOu z-{TtC2vA_TYJKW|;E~`CFRF7p-EoD0Xq0jNd&uN4t2N}l1duD9_&c~eyffW?F!u87 z>MjO%nLTsx2~J%2&QlO7DRlOl?bt2taiL{f_M{|`pFkMVPnBBwY|OlOuzYc#c6XfB z7QE*Xc#qa4a$d4-;e|2TgTu8hS=4ki?Ja3!a&})94`@?rQNIX;l`lwd4$_)M9i;$MyQ287Jt=O=qIftv@{F?d2kBw=CpCZVq`KD&vTK=4(chM~t8&0BIeg zHr>4+0XHRUV4y6K=Q6XHh9~H?W!ASu9K@#_?c}r|YU=2{<;>3wS)1LZfAN&-FwnN(?82nLv*H3{|*Td}B%%!o~&?>{I)@ zv(VW(#Ll)jd#C0narVzvkCFYW;}wnzZfoQ**ENU?|tS6RI4qhTSbQ zxg}s?Hag8X0H#iPd+laDfH(iqeZy9kN!kt}*T7C&90(=&LnLg8a*oT3*Y3TOJIc(_ zr!8rOfEe#)YuUJmu;pR)Om1ZjIrr|5iwt?L0@6;l(4{5Teebs}WlFWnNGMzXn^L4Ln=i_NAJwXu)!J_pIU(}=_4!<4uJW44&1(BZu8E;OPPBGgO1 zCCDC}MBx&80R-uCfItpiz$sDv2C%d_>*(1SixU=HplhoS2Tv0qn9IQ;)SS98Nz>*w znfu|yw-n*g%ElI8Ikh@;G zh$7ci-|gT}M&^=xZja#)(?IUO0K|ALD>jrT=uYE3J&bB5ahltnC794;|faW;DMxn|5$nhGX~s8aH+I_ zan~bW(9w9gvi*t(EfPhM4~{T>50TkO&3>Ha<61~CEBI>9T=%mae2#dFJWr;wdS;6o zAtR3_>P0H-_Z=F(>9?v=!c(AUrwUrozEG z9ZaSqVDlERPLylOA1uZXCjoCUs+#+d5cL$w1ZTegtY7!};OwQNbzIA|6VH#pU8Qrw zrmv+GSs)Yyx8*Aj{s|Xg&tsbHfbLl>27)_rcH7Twb2IQn!hX=rTT#K~^Zpwt7^d@( zTYw7Xn}7q6^{{~3>bpAX+1aVUI{(^F;OfTnxm!%mnD-d5%=cLCEHa-Qv7Zw(tDAc5 zFT7(nAhZUZ;dfkl)_LN2C^-7>zGzpvnOjZmTsm=w+;hER>pFxJSSnwDyP6>AIG^5xI0BSqUJ6q4S>EUd1E07niu@|Z3p}vEZ6tvb=Sx-7H zH$$GtfStcE0mRR6IsL?1D?CemoD1NP>w{)Hez0@Hn?o<~`z_+xjAfG!6@VD#i}(i4 z$LmWZq_@g$v(JC7-oK<%u@|u=4WSbPtA@Y);Ui^2)hoPnO{yT`p zNri0OfFOjPLEOBnXOr>a!~}frZP`iJts8t6pW0MRL&Y8v#nl5sDKR>EKLp^V(>Y+E z-&fF|#EfiX=92hrZET9YPY7HjV3nlWEPL75*rr-Th*?-9^>P&h%xmPn-XHL}(c>Tj z+IQ)l54gWmtw66O2orLH%X}%G_xIS{3*k67=iou`}O6eVzLo|;ujITUjLSBQ@ zO1Cmv?Ygj0G1coSDi_@cSP5izUX+cj(3lM|7aGq85CIB6$vQ_n&y3<61RG?ccgGxs z!2p~LsB}LhlY8tK4;Y;_?9@S}Y=6NXXU?gEA+#!pIX)tAAo38f9Yop{dnzECmwj;x zFj2N3&b#1XrxyYTTO)5lMB4fP5%$($Rc_t-unN+pbfF$niE@SWaJ?DJa@6Ua0*ILh&Gcap)ywsbYI1ujUtoOMlO-|mp-+^YZkllEjhS@UL z>4lDi-Z*Ep5WMJ`jpTUi8D=X{m?OEeA z-@Yf6PKx}^@i3F-Fuy+@x8Q}{JYW_3(?9QDlltR+v!hrFNTFXUM5u>8bv!~1Q{6sz zm)p724JfD-mjDTzp5S~)Z*PZy3Iou1nan*)IPkgG;A!VW!^cWwflg3UWXcEIr|D z0^tIx5Ei%XapCOM-fV65&OLcAaC74Ke~>!kFy5vB1V&dT^{%h05TuK_a+V$!A*ky7*hTAgdSXd5kSV(Lcqa;;#miP9k}fP z(Z1c88lOVD2M02lWC_qBd*e#;!8%8RNN4+@@J_xA+>3a}Z6ij1RiYL6?GFZa7l-A! zcF6OVlg5_EpFy4mfS(z>ctYOb#`ClfwlFX4?hY60{wMlCKYVM%rC_N`CN{R-huFOj zpD4j9$tz)qG!b_`Y$MisD~yT|`87&qDow?}hj2G8EB3VP?ATpnJNNj)lQhdT&ZLis zQFV7Eq5JH}t>Hi>}9 zkX9@5h5V(eG8U4tJ>+WV%wl{GVHfv)DUEdcI~Jr*L#fP5BB|T*0=MUiZtXSvH|9k58{*Ae#hX{7&t;p8X1!5D|xT*)ruW6OqHs=F+Ebuc!Uu@#zs0lCi+$Ms_l8rs;`0|7D_c$bm5}mL%I$_0>Jt8jNES z{H z7h#gj;~C2&nkr9#BU(rMW%s0;=`5;f3X6z!Gss))oE7|v1cTRU3#P|vbzA2k@E6c$a+OJJc>k(SxVe3Yv%U{{K2}>_iyCG6)!^;+roda! zt`BG$@IDEdi{c%m$=8g4!Y}qpHVH#u?a1?8XLPDOE#La?EK`jG;iYBBw}sHx4iY-x zYnf&*kNb}C1BKv3_uNk~_;Wu9nJYrSfqQtb@vhj;UI*+ZxcHuTO)$`}-w*@3Ve$q} zjdcrJ!#(idk|H#LlxdH}M1aPzN%SkoG@ze%8#*CO77daJz)wEh*s1-s9r3bQ*v@+= z&C$A$7Tgqh+WL(Uf!m4FJ-x=YbVZY_`P*%K=x-<|K;!o~^$MM2xuK-UH2D$FTWRKk z!?w4?7b(msBJ}WLVldz^lHOeKcA0{ep>`Av8v08Ndt78%Ha*yTkZ|IDUq`q5a$S$1GtGPsn6~urQ>@n&k+&d$} zBY6C{S?;UJ`dGFzwM-HZJMZqfZ#MKKjP0Q@Xs!*9PK>&XTl{WCw7Y?!P+`>kER$zR zE0_$yi_8z{qKzvtA>rJ7)Uw`gU%cb{`s7g*B&ZucO&*&L8Z0}Tcef`$XGT_T;Dh*8 zT*8^yG~v7j6WSg@pW!KXjPQkd`7^b-G|(*a-a&sf zGTQnbXeL>I`r0tudhYr&Q>i%K0R?oq#$QxhrH)skb^BxLjlQR__|Cb7Krf|=qH7Jv zM{eTSF>~vWczNx2D&{?|f|yE`{`sH{_+V3U+Q7Gi1OHs-J&z`6q|)bH&q7z3vUhhO zeAv?lBWwt6{E;y_4Rn<;r7wy^e#kP8T2#5aIBgP_Tz-G8!Omb`sy5Hb{$|WT;gXIK z^DUWf{%113onp~eQNvEpb76dX@EbQyuBjNVGgwkVQ z(%ZIZzA_Mep)B?|{Bz|$O6qOausuuC*WbK3Eo^7-4lk_;A3{2Qv|gh>yjpEqI7}pd zb-|VUG6DluzgVGF%3*P76jxL>Ku-E*DX<6{Ey^AxX@u$WISMD!dyU{q&wbtN7(Z?7 zjgE}iAHx@%;p46JbcpR$cUIqV!JU47Qerm9cGYtK?zJ})y})7tn-^Yvo#7hj z&6RmlS*r9+-S)!TOe-xr#D)VmI%|hJ-{Xc)163nu*V=Nh7}L^(m~MNZfTp!aIWggy z06rssT9lB8(~b^yqMRg`kj;i=3nEM-%i-qcI+Dj{yZuo+nm@glvB&+yKM7)9em73( za(g=KAf_%RPp)sCWm6A_796ac$31wb+PxXyWsP^``Y2<_;M-fUOBLr!1N&7O%MW!u zZy2EANup5!4bLZ=L0sr(ySN8KSu^vVmAm1`+XW0>O0uHTi4TJp6vvCE7rxn<<6F$R zBr_O8jFb*%8Xg(GmGw+ey_RS_ev#;PHO#Gji4KY0_RTO*y{6q3X%ZaiVRxdm{<2t*?R+I18?`8@@bJWaYIgwd7@!)D>BuUIq z^LCK+X=Y!KJyJ3|d9~K#{R64+9Y2FT8*KgN2?O)zn>qvq^J1A+3|*W@8cA7n4vlY~n-S3k-~B3WKNfBwnyD<>223y}ad z(%d!Ds@p_Ns`~PM-mB%Kfblu(_=jX#4z{*r8}Cz`2t$&n%};g9L*+d4k+H!!g|g=k zSPgv3rN6t#!;jJ*KhDbVIGYu?VBHcwP{9+VW82_CKMukh-i_Tgia2?c z{brO*o@xV}ytj-7&D{(`MVLrY9S%YC#M7!qaN=bTO>xJyacv?T`f@GU8+``N^p=;m zrQ<&}c3PD3oS?Bp@(%Gjj!LoXW>Si8*X^5%t&UWFXWl)c5MOE4oA$#!9+neelI-8) zBHK)C`2nrP#$lE_?X*h9V-2e4CnzMvt`@g9S7#TjU;XQ`MKL~p%iJe|{Xo@w>Gw6B zC&-07BSR#Cw2eVcC)=Y1L<$D4&2z0+QeSHc&B@~IFAd}NG+Ja>-cw;81_-dYxfy%9 zJaY1_H*1g-OW?~KtL$Nh6|^Khcnm-m2QY19H%soW#zUZ`i!Pn6J?M2#S5~serK|Pk z;eGG+FIR7CGm-YR9<`>cSY4vg3C&G{SH<0k$DM@zh^y2%JN1R0VcoOljUN#FXjkTQvOwVR>Z`A2_5`^Jk^o`#;wW*${o{8;ws z{zmXhQ!5ZC9+~H>n=oRv`~nU=37;}XMth0hRuIwqIBZ`(*^d7Ta*qUYU&!W&4PK*> z%x$$MzB^hmlb2*i2LZVDABVT*UpyM9VdxE!kRjza7Tt~Ank3ahk&`w*F)}Tj1o!Cq zbME#Y&7PHR?r@R1l1m&yAF{{m!}O>IsjWe`PJk0BD(rW^%y|cRx#6aRzm2pX9#uN?o&W)H5ARp zm|+LWH2i)i=#3IoP}B=2c#yCpvxh!{9B`T)&m};}LPu^rv|U8!#^DO8SgVQ4=&4Lc zN0)%Jh16noXh+Qb!Jlp1*j^^6!Wcp6VSdr;;0AaJixy}%{ydwfU(IEKeqAW|I;V7R z-{8}2HiKCoV(b$tHu_&**E8QxYuBCfhLKT}X%D2ub&F(rqFw?YG6FHhM@;Jg1md&t zKYR}hJq@a%DDXXQG{4KNhQA<0YKbpOfQO$SC-;o!=EPaE>_0hskZ@^00k|@D5#=!uK;%#_8eG$g1@x~#a-aHZW)6> zg3088xGYHn*lbZ!QhvHc@E5JH6CQXqT%2BkEgv+DxIJi7h2A!U3~esa)Z;XGbP~(y z*BBtFuDjEmv!WvW{V4{qx|FN4y`t%F>GSV%LIMJyrS?R?djwIyGD?hU9%EQkPKc%k(l;{>jh>uoZEm*_C_2c#)y3Y&XCd zTJ2`1gt-mDh2p_yLbzc2BH}A`@m`pZ&3sPwy!`|!FJ1ldVms{@xRYCW(ucmEr)sRm z0RcH@W%y@1>R;8Rka}L5Uw#&$q@?+UZBahu%?t&B- zU>)3MFW(wTIeFN2GE?~K z)e~7M^4!Z>5|X+C8hf|5;O_Xk7}}0OQj-W1v00abiHk z>M|Mn3Rc89R_Fy&eJ=)PB%&!|I|q7|xq>IPW+B z$n><{%@3R$U68{bIDnd9628ra1!mCrh0cGTA{s=%=XShck+XT_dCN@h(O2cq)_Ap> z{4Q43==LsCW7AdrL1H>DpPYQyfyQsmRh>yc{)quF(4f7Kn)1*Jx3D%2?i_v`b zh<*;?J4m%>qhH;%>cxZlfA+A}-{ns6knt-x%CvT>KUC3pyo40|I@ZeavQoBeBB*hM zLG6OxaFDy3vv;UZc4i>=nrEATW}iPGM*4dR+yg+u*_+pmtaj8h>xulz1?pv&hp{TS zrv7;fnMl&AKvM^A;t%!n^INdE)@H_krdw`4Ffb8Pv~|d*oc8yOzLok#oAoz%Lr>3j zPZ+Se62-|>u#$XUUS7Q#fS%_7O+!Gmv9W1@O9#jQ%mDtEt%GK7m?*@-M>J<)fX9UfVjsLdYmu9Be;>ju643%Xuo@$dkwra_fU3N6+g6c#u9OqqoPvola9PHED8)jEyyCjU{_T%okVmI*ne{hF8F7 zdo#b_^lZuFZ$jCAzVr}m8oJ?+CvwTfpifU1q=v3wqkga}A3(!#_F{`KVUVbtTz^hZ z4%ZxS&-i)2=bZc9D^Rbp>TM1mI;9>4xJ2)`O7*-d^JzefXvi<8yCgt@sDCv+<_Nzm zsi^z52NnuMgDh!xyP1!%Ky+gQ@l%33Sq$u7Fj$Hq8SISvDOtJip0c3h0M?Fwt<7;)#`4bBQ4x6Vcg=(wT zy*9(uUt@F`2ZVEbTd0I}$KH0#h(#6Y2cQse8ZAV-ZA&L3Qd7LW5+M2xf2=Sf$ZCA#^(>X)9@ zad>ELSCLqS^%$Fn*@PnTr0ufeevS1^8i$&Q{X$Z{V1x;_Svbl!`^h;l#rO7uhmI8q zHU4EuREq&Jw)4oi{Cc+rLwZrzNOU=83M-UNR#SFqR6;;-0x96onD)!9@>7tM9zb)F zHD3!j4bzf~X`9B(tOBA(FD7>z2bCJd7A3z{S1l*j3vyKw(Q~@FM!fkC=E5{$17J9+ zZ=jh4^4n84m#eb%eX2jqB|F+C5$vo-5RAf@RXPKD{BtljQ#wZJXt>H?VuiDJKH9mp9H8 zIm>){#Mm`YI&o@OgZxESQum>I6CO3At^hzNT!u1ZDC(uGM>%|Pe9~nP0yzsJ?_;}t z5_t(4B=yayt$f+MdsTUVsKJ24geR2NAV#Wy{v&0<{P|+{B6UK0ar48e?Fu;o`mg4X zQThb#HrQZ%p4X}rkq$VRH^rBsNl5q4Jn)_FoP0r+L%f}7;4Sf$vQtHGFsmHfFZJ!K zx>pyqI$Og6hn5E-;N}ih(*f2&SDhs-MaXMOByo5CQw|Vo%q7#i`9_axcLts>+Z8^2 zE88Y~ci+P#O6_H}6^mZbxmp`ZzR@|Lc?nq5EF5aOW6d!sinA1;BoE_*;wnEfV{@i9 z0RmOUMKMbKOzS|)%;od|*_LhOo4Nhe+v{)+mfVdZtoa@Qh(}$#d8-`19R;q)by~MlMlhjT_KqrtOX*C8=|7qp0E5X=MFr z=^Dcokm!z1wqI}a1t6%_j5rKb>Ue|j+ezBsH|c8zv?xmr)7pQ*>0?GEPSRQKme^Ll z%Z_%1pycg^95E4*I5%0&>{MlN#PRh`t$BCo-C^ff2i#r8qvF*9m0bZ#y6V6uA_1g9 zI|y{4?phVZk(W4l?H)S2VJ5WNcYTP8;P2SXxg4|is@g<-x_VBP`a3-cy)WCiDWyt` zs}HPbiEUb?Pcoz`X5Je$g+oad@cw;8)ggXeWFE*tQrp-#sX7sC6a9^dnn7dai0Rq5 ztu0!)`Nn@TijO4DffvwS;C(-rjE}pf(Ph&mg4oKAdZsy_scAM=W0gEp$7g1?oyVcM zE8y~7wM4P_jCLD~F#ro&tD)9q?RLNQONy*^o>DH-S)c=MO)bcD$NFsI&tLEib6>1k z7ZW$lKAy2~LfS>Il!tOh)v6QnjReJUGY{1CFwj4TbK7iXA+Gd{N>n-)A4ec)^{WG{ zeG~IfKhMDPjn?Qf;j)a{HUJBl=>D*`3 zY4X_=iP8Z?MKccdZffnI3<;Yt4MO3SKo>#PqB%Tfv!3=|S7@lnDT{(o;hY68h!fje z)UH9-J{#(WT#Bu(?ESQuD4%f0dUP`Mu=;BA0zQC4dv<1{9&Kiq=Q($Pqx6%;iUP&P z#i}xts*`!!D!(WdXRcevqCadks8-n^{u2&w9VA5;yrV&$yjOL@uQYq)G74YxgQhU| zGp$?$jj{Y5-a?)LQM8Cyvl$J}rCuI)Vb1f_lA;Y8})L#V%@+@41xg5#aL!9O9%!{D7a+i$`iHe60 z3I?chAmHG&zxb_ob1!W_EpKS^dGt9+XIfTE;hC~@cU)ww80Mec@N%m{6RAJ!IPLmo zX~8}|bM;4`?$8q>42dlZ+GFE_d=Dc@IwG$a*T4mlR7sypTH7t4g+ojwyuX_S z6pZH1GXu@(+P-ojD-^;dAtb6IZiF%;(@cyGi^ncN%>g<8f**=r|B)uE%&mlN+;Zge zMJU|Ys(0$YHHrylp`THL8?`#PwGo-dyMY&4gpS1y*O16^Hx}p zm)CK{2Z%gUeN&RUs?-+hx|F#9ZM;u?EC!W`hu6;iOT)u)Rl-%1Q?`{O0qKeq{PaW4 zaf9>A$EsQPPw05;tCJ)xKsL8H`@o3pe3yzggWC)tnMqf2e0#Wmis&DZi5??}x1dn( zQ)=O;*jZEu_c{2hK6?$m1^;Naz)fD#mW5#7oZIb(KE^`ZbeJ3h}k!8Bd1>l zZrh9pa63Pmz_&{~ob7)MCh@F*hv0nKtpceJD2^{_n}H(nD`q+sS`chuaASGpwq>KD zIOy3zsM$SYo|l;yOt3z*o^O(!Fb2X1G-y_r`{%wOkA+uBc?**h!dq$3SL7=+8lLIc zbFPIU*(+MWLSDORBNoJz)K4z<_V7{Dn$4+!W(DJf2s(K$Fj_t^zvu zmFQ>v`EZ3|-a7qKu9b@2Cf|kv-GS}jg+7D7H~NIBX~3- zV57_fayL}+MNUSy@iG=Z#NRrEOuU-ecq48t$vxPacT3#+H&t1G@Oep%&t+dvM#Tw` zLmub5ChR{S?WI%B3qUTSL{QLKPOe>9T59G=a{Ty*;lPR7rE%KydU|wB0G?yW#YjOM{or zqQA)Xw@IS{o*nlSd7u>>;TDF=0B1=f>M+;8vID`u%94}CY(DW9lX)lJV>#UOhConv zOa);KkAiKQy);gAAiCVoczui3VoW1mX3TAb(1rwU7Z-G?t=#E>ou~jiu`>^zZ4Nw} z9-(tq{YwguPJ%WHeA&@F|JaWTXOT@6vHzRYa6{xiNRDHFYRF#+C1z4@aC^ubP4XC| zSi)!gs7_egJA^D*0F?uj&;DkP)%--X7)?z5ip~P!)ev05S%B)c8C$J+)b`G+m)at6 zvsYM*e4S78U8g)n#rj-PBcM3wmS{-IuN9mOyBTZ!jC&>%#?uUGfK&+dOrSBVLl$Tm z;-ae6^Ft=!Ipbeh{p>5l6=z4VjB-BpQKL#9LBjc7foP4*$7ba|h+S1a<+P*#tu*6< z1lj^rf7wi{{Ra79bh!rgS&!p$>>oYqRV!)-^le;gR9A)=~3B+1Ph$w3*8n)B=*l>5HtTGKvWBdK5TNQ(F<_6m{BHo5SCmX6@Yt8ju zapEp-pX{HS4=zerN|H6Tykd+HL+22c$_Dx?`lk_u$X{B%pGsX1;U zm*Rm6p771~VTOc9`YHoC!Us*99MYti2hLPwf^id&jbPyA0O_0@$BxtQ;*KN#PS5Nv zlQMgPB9>1+75J7QwP0&qB$Ovxl_q&EbYx8GG56}%rf5I0_KBPm$HX!D)t9 z&=N;Qc>mjG^}zo2PuvA+XsXTBU<4|FXulharNZN~{&Gs5;7pRDGUA62(O1LL;G(Ur z|Elr>jsPUoGR^@jto}6pM9m0R{L`%NZaa5A>rw;kb&>3|A7aUs?EPO(!Ys_Xcyh&R4s>)YkYnHh&! zYEA8<-BIb4%SajnWlK(fx*9g4a9WDH>+Ij0hQ=S50Zhqtl3T-9A~+M{O-&!B!>AN0 zcicenZKDV<;LlL4J1tZbGeK7(<7(1^RP<(Mc{iL8yca8T&$^0vfs9*!7^gO`^p+m3 zQt+1xBd0B(;mhIwiTM6ETVM@JxB;*7_g)IIm;9wn#GY+Gb3E#BR_iZ&-jg3YL#QzO zGZh%3fz)DrLVoxG4>7AzNB_|##|!V9>-cY@X2jv|)zO#q3zf!7N&_wWHbSbq0%&!x zdx;hmd}RksKyv8Sh%a6X-EK00?ikO&BIOVAbp~#AX-@K`ogoG+QcF>D!7l3_9cPTM ztUyk{v#N@72Cge3gCXcbD9zmdfEUSIY14`qhS!!(oreU>KSgY8eDtw4Vo zx8o0*sBILJj8v%EY0w?baMr0}7&Dz_k9?Wr#y{vGYxfaePe@@fwAuS-7)O0g zp#(b#=r_!VfcRqSSNxkCsGeMShZ~hNSS@!w@x}T)8HDWSINbV3V7n$K%emdH{b++x zWMW=4mo@aDh{Vg(aCcD`Xds6%Cm33GV?lTIY9Q>4|6|HodRpn-g>EYkwG+24;-`}8 zFS9ZAyJTb3hW)8PW@)B=@~{FzBs$lqOn6uoys?M*lJD;2r5UO8^>#$RiN}h>UC0l} z3gRHEgz!UO?lR|m$6K9ZZ+v3Ys=U$O?+liJ;`m?c_IyrPOFnfYYLH3!ye(6<-DG*dmP z2kAYj#1^SM2#sy;6eY5+%K{We-S?8;r<}E5nu@nxNuQ;j>#^lEXKuI8a6Bx=w;kOD zb$XUax@{gIA9gRqo(BNcc*Iz}5egpTZTwPa8y>v{- zd6`&)0$R6EGtNS=1qa;E*X{gVYWcY=otw7ap<;Da0Hk3j`O*?@hF{1*a%lU5t)qSR zQEMM^W!sC$l*33G2yJ&y5$~g~2B3rtCQeGXIY_^`+<(dj+B9}ynlTmE>xmPz52VJv zzksRKnu!l+9qR}uVfU?b$^>#4Mq1hK@v$yVYWx+jYCCUGO|5cIJ2p$LgucOY<%7Ss z=~MevW-k%=y0y+O8EUAzd6UkW?^gn}J4DIIDe0+L;hufuVeo^ID%bL9$p6$X23jRJ z^F7bfsRehigF<%Co?Z7(!t~I4UvH9^~`tu>S*IBJ_M}V zKzlmD6?(Zin^n~$Kjq@T_pxT-a2C*v#lpT!w;=G>!39a#KSg9Gd8U*G($DC8*Z$-} z@^)56Qdh>lD6X z%A>nQ#hdZJsVMIK@lTep@Bej|uLHYNn8MAoRu;D&_-v-B+w8Q8x7#w+ zdJI=6Z1?-0urXwt4Fe(=c}ZM*7FYTrMCm=IcfM?fnxZ9+S0)(raD3}zJyN#1Wme58SEwry2)>|j zfzFsn${=q1IO+d}*-vWVALCIM-&>_XR- zLZ!_lg0`k~2TDvmY%(E$dHxu9WI%0T)x*n8&?Iefpf$u{LSh`GmsNgSFqN^#OST$s z`CNTE2(&=XSr2b{3mLkd1-TSDKSy+{+?#+lWm?i2bG2(4X|nzg``@y;8M{pUfL?CF zp9B)M;~F?pyg=U%+BsI=t@x{9$IGOx_kkJf3MLmVQ1N&I3VmL+qxg|9jSZsVs3GGb zv0xU%;SePvwLXA86)_Ic3Q|V?7$buVRDf#zMJ#xRK^Muq`(5j~Kbt!&`re@F`2g90>zmYQKe)HNpu#s>jY_{F56N2kUTld{nJ z11Bs?8l3lZY#TAe#KgQIowMts`74--wP=MZy-@qOOS!L)Q9B88+WZN*&RM@z(=|oc z6{I@TJ`m{T0K+~O`IqDo$1`V2-8BJ$9n0z)Oa;Wnb*oq)dPEe1{=R-+#_{MJKfl4i z*I$qA`Q?OO4oVXL^Yc4fsscv~EQ9x81-n|mWLhM-@4o13{4$I8hfx0Kztzr^90du( z4~`5$f%>q2_N|@W;)X<++OE z+dLqhA|noO$Q6Jhh3T9RxQ5k$V*mH1$48`alht(HVxTqQo|Wtvf>#b%4MU@h5itG7 zaQ9rs!cw0_n8nh4eL4N%)lZy)N?h$!5sYvSv!R});0fZ?6=U~#oL@gDTQ8hun$;xs ze!yEq1l)X@=#1Xds?gtcajjb@TWKzs% z)oXt>%t5BK>BH$)>yChyzp^O{ADNA%&y0TZ#0@ON-p>5DttIX;mfDOq>*jVb zmb$IRF=V)2h{a)dn2k9H`mn+`#0D!oBVd_KCq z@$d?bi0A&)>pj2SDq2rZz3Ct3l%WDoA=qVx|AR_CF|~qp1na>b_RXaPS-wy~(GEpY zqQ3AG-0(`MCz<1C;O5O8B4)N+QgTM`*9aL2imj{~Inby722xszc`X{yy|U{E-aUX_ z(D*1fqw895#rH^sP!SvI{@aWW6L3I!rgM$K!m8 zct|e#2HLs@|2TBG${1rO4Unp@Xhf;lOVRoM5;C5d=O(AVxHQkS?wg+kuLncKf`gM{ zMdLqR|K)b$os-od?dksj)Q)@|>;q8cgQeq8Gs~DN6yu_TCOlEM1n{OjH#(k1?taf$ z6KW|9(OrO(H>p7B)ga_BD^UMH#V%iZ3vkp{-U|fA8M=dlIh%mEO=v zboBAT3WoarND1mBc*@jjH+MT|tjgtFOr56ts&b{$zqRzfVCbR9u_(R7Y+|)S4dMq( zScbn$#cuxkD4F~D^HBEIviLaxsUaW|nDI~@s2!<50Re35YoO^4y(0q-Qa4S}5U0db z_~}QpVeT3DhvSX*UP?a4pte_E;y9Q6AGVa}R%tp7Axlo_Qn|A^2TlbKv&~;ZWXu{b zQaWa`{UYO5kBvyiFDDgOe6PlZP}&Ws@)3EtROCEoKzJe{@#dtq$f(2k@d6kKd)y(R zW!s(96ZB5E;hVedIK(_ntH(VIK(7$Y5-XTuo(|_B@>=qio!JFhVm4}?`f)!TNJO~M ztRUjdN$bBHfdmw#L3$3VgoMP61`O~T?2?~H`_dCIZ0F0}G()Wx#G;gdl@1*H7(NUl^Qoiad(ZQLb~ zyrHJk;2UZQXXf`*6Ks*!Ba=j>#vr2oKF)sTn2ZvME8lz0X!VqeI5O{l8HS1azQeg%-A!SaG+)xSy=k);_By)bMV(&)OB!R(4$2IEimHui>&2fg z=UVCkYe1nlDpeiOnL{)N?1iKjAb%bAuqW4efSelMqaYKR=nlGc&_e_X!J+AV;qD8N zmSt)!p%X6yTFSZYYAMIs$*RDaC~Z!@C+iTVa7&NO*zMDLI{P`X z@gqcA9{4s?jez(;G5jYU!+!GJND<1cKCiB=`5Oc;%{V#C*KDi8Zbn0vjDP$a&>AkR zgqajGwAtAQj_B2I$A-q7Q#Y!jDqWBzLhn$s`i}Ws4S@C^LI!wv!?CJss*Ct-zqA^b z{9fyCUnmAXjOwFpW*mcX=~#2qq0Oj|l~x$;Bx}WY za{PFpmNF6v+{g^pYPJF`+l$@zgLXhN;4n8YR73VqFh3>gtIiR?bT&UrzsI#yM7!P z(4+%ao!TE0iD+F!ETRg`g4`4FSR->aNk1#~)$3~j#pWS;$l>w9r+D6~ z0??wvJ!246;~wjSm5bsxXZB=rtGW{S>F>v^+TQW#NiDu;i#D{tWGgta8Knkd2MZ|x zH{A2r64I<7lEq~5L+3OPoA7m9$Dy3>pmb+ub46O_avSw8Y9)>Cg7t!h!2V_ zwe2om0J>bv(d_d6C?#1nB=Vx--+cd;2`5S=rsbOltT5289y+vKK53Qg5j9Qk(2RAes+kqe zfekZVMq~cmUFhdyKFB*D>zBEu9r?6~lx^9WOIZkL^fwJY>Z@4JFEE)hTx}?Oh{jC0 zw~bnZ_?p|5IIxPRD#*7|E)Y$wqyYa*4K+&qbL@nS-%UGFC&3e_a8000@bE{Q*mMEu z-5jj%HxMVQs{4MD0hF=R9Yq3w?wj=i#ggj*Xm9ZOb9G9;-Cw7!aK>HuW%l#`l5WY5 zfFipvXExq84ZW%vm7rJNx(N7ci~Kpa?M7kkogtgAU>HNYH>&QP{K@e}~)oEM<; zACi`$}e*v7vR2 zHyUc#w6fZkh+@o=L-T*euA|n|T6~O=-IWN{4HKY#Q{5-0f90QQ=MSJ>Ykh*YR%iNt zz{`)Fj530r%y0~$3$fO35hG?u>`x<$|Bt#(T_HTQJ)~)g8=&o->!7}QG3^|0h?r)9 z;sxTvg%RWkFsJh`>=qx~LXo7nC=0eE&I5S=<*PN5d_;13tDxPLZ4JoUr)e!`EU4Ny z+!3lbUSV*Sh8kxW0^Zmy4|2m&;#CW#B8Zw?g-p8EqorM+MyC2Ur_>3Kk2lAi-vK=D zDT5tk`gL^we=C2g>5D`$2V^a%9}ZxIU6E+7#sG&D0yqy~M1RNtO%h-J$>Rq zt$8rt>b3rDlLE2!ILFHZE3wB03;QU(N08)7zG#A2Q)5bq4t$Hs!Rv-F9^eyWvy$xAU ziq0_+RN7{Hx4o=EpF%&Q>zm*weuXRuAQ3E9fBa?EeTd-jT1Wd;1RaZhN`j|`I{sb? zZH_sdBz&_}IX9rk?>*dy-i{)*$$DTd6in|I=inbzVkLFIaAY8-?4E6jxaG$YGCu89 z9`H)TcPRZ8UhP0S!$>Qd@xN3mF`VrvH+uCbV&a)w8+jaFhaBP+is6ABF+O=%%I~_=$*PcE(MAS zxUPv;Xv}V|!m`6o#6wP41E;CI_tSsA!3zS`libOM+}$HOWMZlEA3YFb?|XLcYS(1| zq5%H&*Up#yx~=o36&Z}yOcrE`Sv6k%)YXCuDjmhR5{7~tCu(|ytS-85G`#fIB8-zd ztVY;>yBmv20-x#D3xSD|rj~SG$h#)tMT&i)W``=WP>RcQf2V=0azQyhm>*I-o_JX3 zQIh;1kYn-K0oOuE^ZHFPwcAR-90=qIhd~iENk?`jb}OkroI)F4DC_A3Ed+FeMck}M z1eIp>z^OB6=wi%Ft1`@=iT^tw9< zpyO{YcS{xiC@#@@_H}QrsEv$Pl55MsXqdQB&-?WQ1LD>s3_yYvoJ|YASmS6l5E4YM zZ~WBkZOa_ROynYBq_|M`MdEST+E~%d&Wni9{rUcjc_JKTpfnL%47kN&hwb^$84 zZpYaHhl$5&msjg+S|GLwoz&2HV1mb2zc7qS#PgwHD5T(fnvBHx{B7`xxaAHqMG1kwwaH9l;movqXqmjTMv+h?te zPz~Vs@`ELlx^F!irc?B(8h;OAc|E85GlRt^?(wIakH1v}HJ&qjhxW8D%4tIY?-cNi zr;LsNdSrp25)@Wqg2|5tsb-y**Fga+v%{7mX@F*G$_SGd)9l&T6LNHfe0^|}da`O& zOTVqMst^n?&;mqQVAz%l)FC*MF~l{csavF*^!TQWa*5QSqQOY5n;0F|0qz{HB=ZDu zau6yLpg?ℑ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

#+*g(kYz20X$sVk7Kv_?$?_m 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

o=&)Hc@4Y!`+P)wCg{!PY5-oo8G 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 literal 0 HcmV?d00001 From f9240d200f004c5a8f6cb184eccca2b95b0ce60f Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 15 Apr 2024 02:46:42 +0800 Subject: [PATCH 229/274] Update UG --- docs/README.md | 9 ++++---- docs/UserGuide.md | 56 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7e9489fa5a..fd6ea6b7e5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,7 +19,7 @@ To use the app please follow the setup procedures below: be inputted immediately: `allMeals` 3. View all pre-defined drinks. These drinks will have their nutritional content defined per 100ml and can be inputted immediately: `allDrinks` -4 Viewing all pre-defined exercises. These exercises will have the number of calories burnt for a +4. Viewing all pre-defined exercises. These exercises will have the number of calories burnt for a high/medium/low intensity workout defined per minute and can be inputted immediately: `allExercises` ### 2 For user to add data @@ -40,7 +40,7 @@ high/medium/low intensity workout defined per minute and can be inputted immedia 7. View daily fat consumed: `fat` 8. View daily sugar consumed: `sugar` 9. View daily fiber consumed: `fiber` -10. View daily water consumption: `viewWater` +10. View daily water consumption: `water` 11. View daily calories consumed: `caloriesBurnt` 12. View daily calories and water intake recommendation, based on current intake: `recommend` @@ -66,7 +66,8 @@ high/medium/low intensity workout defined per minute and can be inputted immedia ### 6 For users to delete existing data 1. Delete a meal entry: `deleteMeal` 2. Delete a drink entry: `deleteDrink` -3. Clear all entries of meals, drinks and exercise: `clear` +3. Delete an exercise entry: `deleteExercise` +4. Clear all entries of meals, drinks and exercise: `clear` *** ## Exit the program -Close the appplication: `exit` +Close the application and save all the changes made: `exit` diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 7fddad71f3..f3d19ad8ff 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,10 +1,13 @@ # User Guide: FitNUS + +--- ## Project Introduction FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even past records. +--- ## Setup To use the app please follow the setup procedures below: 1. Download the JAR file. @@ -15,7 +18,7 @@ To use the app please follow the setup procedures below: Note: 1. All files under 'data' and 'db' folders should not be modified by user 2. Enter "exit" to properly close the program and save the data - +--- ## Table of Contents * [User Guide: FitNUS](#user-guide-fitnus) @@ -46,7 +49,7 @@ Note: * [1.3.7 View daily fat consumed: `fat`](#137-view-daily-fat-consumed-fat) * [1.3.8 View daily sugar consumed: `sugar`](#138-view-daily-sugar-consumed-sugar) * [1.3.9 View daily fiber consumed: `fiber`](#139-view-daily-fiber-consumed-fiber) - * [1.3.10 View daily water consumption: `water`](#1310-view-daily-water-consumption-viewwater) + * [1.3.10 View daily water consumption: `water`](#1310-view-daily-water-consumption-water) * [1.3.11 View daily calories consumed: `caloriesBurnt`](#1311-view-daily-calories-consumed-caloriesburnt) * [1.3.12 View daily calories and water intake recommendation: `recommend`](#1312-view-daily-calories-and-water-intake-recommendation-recommend) * [1.4 For listing arrays](#14-for-listing-arrays) @@ -73,9 +76,13 @@ Note: * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) * [1.8: Exit program](#18-exit-program) * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) + * [FAQ](#faq) +--- ## 1) Features List + + ### 1.1 Information for users ### 1.1.1 Viewing all commands: `help` Shows a list of all possible command inputs. @@ -162,7 +169,7 @@ You may also input a meal that isn't here. ### 1.1.3 Viewing all pre-defined drinks: `allDrinks` Shows a list of all pre-defined drinks. These drinks will have their nutritional content defined per 100ml and can be inputted immediately. -**Format**: allDrinks +**Format**: `allDrinks` **Expected Output**: ~~~ Available drinks: @@ -177,7 +184,7 @@ You may also input a drink that isn't here. ### 1.1.4 Viewing all pre-defined exercises: `allExercises` Shows a list of all pre-defined exercises. These exercises will have the number of calories burnt for a high/medium/low intensity workout defined per minute and can be inputted immediately. -**Format**: allExercises +**Format**: `allExercises` **Expected Output**: ~~~ Available exercises: @@ -251,7 +258,7 @@ Adds a new exercise to available exercises ~~~ Added badminton to available exercises ~~~ - +--- ## 1.3 For data retrieval ### 1.3.1 Find the information about a certain meal: `infoMeal` For the specified meal, display its nutritional content to the user @@ -531,7 +538,7 @@ Pizza has been edited to 2 servings ### 1.5.2 Edit an existing drink after inserted: `editDrink` For a drink that was inputted in the day, edit its serving size **Format**: `editDrink INDEX s/NEW_SERVING_SIZE` -**Sample input**: editDrink 1 s/200 +**Sample input**: `editDrink 1 s/200` **Expected output**: ~~~ Sprite has been edited to 200 ml @@ -548,9 +555,9 @@ Total water has been edited to 200 ml ## 1.6 For deleting data ### 1.6.1 Delete certain meal entry: `deleteMeal` -For a meal that was inputted in the day, delete its input based on its index in the meal list -**Format**: `deleteMeal INDEX` -**Sample Input**: `deleteMeal 1` +For a meal that was inputted in the day, delete its input based on its index in the meal list +**Format**: `deleteMeal INDEX` +**Sample Input**: `deleteMeal 1` **Expected output**: ~~~ Removed Chicken Rice From Meals @@ -576,8 +583,39 @@ All entries have been deleted ## 1.8: Exit program ### 1.8.1 Exit the app: `exit` +Saves all changes made to the app and terminates the program **Format**: `exit` **Expected output**: ~~~ Bye. Hope to see you again soon! ~~~ + +--- +## FAQ +**Q**: How do I save changes made in the app? + +**A**: All changes will be saved once typing `exit` and terminating the program correctly. Any abrupt termination will +cause all changes within the session to be lost. + +**Q**: What is the difference between `listMeals` and `listMealsAll`? + +**A**: `listMeals` will list out all the meals you have eaten today +(with respect to the device current date). Let's say you type `listMeals` on Monday 23:59, +and then type it again on Tuesday 00:01, the list displayed will be different (empty if you have not made any changes). +`listMealsAll` will list out all the meals you have eaten throughout the lifetime of the app, it could be days ago, +weeks ago, months, or even years, as long ss you have inputted and saved it correctly and did not delete the data. +The same applies for others (e.g. `listDrinks` and `listDrinksAll`) + +**Q**: Will `clear` erase all the entries from days ago? + +**A**: No. `clear` will only delete all insertions (including post edit) you have made today. + +**Q**: Am I able to delete or edit the entries I have inserted from days ago? + +**A**: No. All drinks, meals, and exercises, you have inserted from days ago will no longer be able to change. +Only changes made today can be edited/deleted, so make sure that everything is correct before the date changes! + +**Q**: My `listDrinks` have 3 indexes, but my `listDrinksAll` have 10 indexes, why can't I perform `deleteDrink 10`? + +**A**: Referring to the previous question, you can only delete/edit items made today. `listDrinks` and `listDrinksAll` +have different list indexes, please follow `listDrinks` index only. This applies to both meal and exercises. \ No newline at end of file From 313f84b72fa7e554a8a3e248cb2acba86c52c686 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 15 Apr 2024 03:16:19 +0800 Subject: [PATCH 230/274] Update DG --- docs/DeveloperGuide.md | 9 +++++++-- src/main/java/seedu/fitnus/drink/DrinkList.java | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 947b7e91c8..12d1e5517d 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -30,7 +30,8 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a #### Sequence Diagram _Note: The following sequence diagram captures the interactions only between the Fitnus, Ui and Parser classes_ -![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ParserSequenceDiagram.png) +![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ParserSequenceDiagram.png) + When the user first starts the application, the Ui class will be constructed. Within the Ui class, Scanner and Parser similarly will be constructed. @@ -119,15 +120,19 @@ User class initialises MealList, DrinkList and ExerciseList for the user to trac ### Exercise Component ![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseListClassDiagram.png) -1. Upon starting up the application, User will call `loadExercises` to fetch all data from `ExerciseList.txt` and add it into `exerciseListAll`. +1. Upon starting up the application, User will call `loadExercise` to fetch all data from `ExerciseList.txt` and add it into `exerciseListAll`. 2. A `User` class consists of zero to as many `Exercise` objects in the ArrayList. 3. Each `Exercise` contains exactly one enumeration of `ExerciseIntensity`. ### Drink Component ![Drink Class Diagram](../docs/diagrams/diagrams_png/DrinkListClassDiagram.png) +1. Upon starting up the application, User will call `loadDrink` to fetch all data from `DrinkList.txt` and add it into `drinkListAll`. +2. A `User` class consists of zero to as many `Drink` objects in the ArrayList and zero to as many `Water` objects in the ArrayList. ### Meal Component ![Meal Class Diagram](../docs/diagrams/diagrams_png/MealListClassDiagram.png) +1. Upon starting up the application, User will call `loadMeal` to fetch all data from `Mealist.txt` and add it into `mealListAll`. +2. A `User` class consists of zero to as many `Meal` objects in the ArrayList. ## Implementation ### Information on a Particular Meal Feature diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index 95408de531..8d182fb0fc 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -215,7 +215,8 @@ public void handleEditDrinkServingSize(String command) throws InvalidListIndexEx * * @param command string inputted by the user, containing the new total volume of water * @throws NonPositiveValueException if the provided serving size is a negative value - * @throws IncompleteEditException if the user did not comply with the required command format + * @throws IncompleteEditWaterException if the user did not comply with the required command format + * @throws InvalidEditWaterException if the user tried to edit water intake before adding water for the ddy */ public void handleEditWaterIntake(String command) throws NonPositiveValueException, IncompleteEditWaterException, InvalidEditWaterException { From e4b64e169c31af6fa0e4268ad93329b482eb716b Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 03:25:46 +0800 Subject: [PATCH 231/274] Fix PED issue #118 on corrupted saved files --- .../exception/StorageErrorException.java | 5 +++ src/main/java/seedu/fitnus/parser/Parser.java | 21 ++++++++-- .../java/seedu/fitnus/storage/Storage.java | 9 +++++ .../seedu/fitnus/storage/StorageManager.java | 39 ++++++++++++++++--- .../java/seedu/fitnus/parser/ParserTest.java | 7 ++-- 5 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/StorageErrorException.java diff --git a/src/main/java/seedu/fitnus/exception/StorageErrorException.java b/src/main/java/seedu/fitnus/exception/StorageErrorException.java new file mode 100644 index 0000000000..2eaca11800 --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/StorageErrorException.java @@ -0,0 +1,5 @@ +package seedu.fitnus.exception; + +public class StorageErrorException extends Exception { + +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 948ccb5a56..f18b1ce915 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -2,6 +2,7 @@ import seedu.fitnus.date.DateValidation; import seedu.fitnus.drink.Drink; +import seedu.fitnus.exception.StorageErrorException; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; import seedu.fitnus.exercise.ExerciseIntensity; @@ -499,11 +500,17 @@ public static void parseEditWater(String command) throws NonPositiveValueExcepti * * @param data The data string to be parsed. */ - public static void parseMealStorage(String data) { + public static void parseMealStorage(String data) throws StorageErrorException, NonPositiveValueException, + NumberFormatException { String delimiter = ","; String[] arrayOfMealData = data.split(delimiter); + if (arrayOfMealData.length != 3) { + throw new StorageErrorException(); + } mealStorageDescription = arrayOfMealData[0]; mealStorageSize = Integer.parseInt(arrayOfMealData[1]); + IntegerValidation.checkIntegerGreaterThanZero(mealStorageSize); + mealStorageDate = arrayOfMealData[2]; } @@ -512,11 +519,15 @@ public static void parseMealStorage(String data) { * * @param data The data string to be parsed. */ - public static void parseDrinkStorage(String data) { + public static void parseDrinkStorage(String data) throws StorageErrorException, NonPositiveValueException { String delimiter = ","; String[] arrayOfDrinkData = data.split(delimiter); + if (arrayOfDrinkData.length != 3) { + throw new StorageErrorException(); + } drinkStorageDescription = arrayOfDrinkData[0]; drinkStorageSize = Integer.parseInt(arrayOfDrinkData[1]); + IntegerValidation.checkIntegerGreaterThanZero(drinkStorageSize); drinkStorageDate = arrayOfDrinkData[2]; } @@ -525,11 +536,15 @@ public static void parseDrinkStorage(String data) { * * @param data The data string to be parsed. */ - public static void parseExerciseStorage(String data) { + public static void parseExerciseStorage(String data) throws NonPositiveValueException, StorageErrorException { String delimiter = ","; String[] arrayOfExerciseData = data.split(delimiter); + if (arrayOfExerciseData.length != 4) { + throw new StorageErrorException(); + } exerciseStorageDescription = arrayOfExerciseData[0]; exerciseStorageDuration = Integer.parseInt(arrayOfExerciseData[1]); + IntegerValidation.checkIntegerGreaterThanZero(exerciseStorageDuration); exerciseStorageIntensity = ExerciseIntensity.valueOf(arrayOfExerciseData[2]); exerciseStorageDate = arrayOfExerciseData[3]; } diff --git a/src/main/java/seedu/fitnus/storage/Storage.java b/src/main/java/seedu/fitnus/storage/Storage.java index 63e7af637b..44bead9441 100644 --- a/src/main/java/seedu/fitnus/storage/Storage.java +++ b/src/main/java/seedu/fitnus/storage/Storage.java @@ -75,4 +75,13 @@ public void writeFile(String textToAdd) throws IOException { fw.write(textToAdd); fw.close(); } + + public void clearFile() { + try { + assert (filePath != null && !filePath.isEmpty()) : "File path should not be empty"; + new FileWriter(filePath, false).close(); + } catch (IOException e) { + System.out.println("Failed to clear file. Please manually delete it from your device."); + } + } } diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index 6deff2c1a0..0aa0d170d4 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -1,7 +1,10 @@ package seedu.fitnus.storage; import seedu.fitnus.date.Date; +import seedu.fitnus.date.DateValidation; +import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.NegativeValueException; +import seedu.fitnus.exception.StorageErrorException; import seedu.fitnus.meal.Meal; import seedu.fitnus.drink.Drink; import seedu.fitnus.exercise.ExerciseIntensity; @@ -14,6 +17,7 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.text.ParseException; import java.util.ArrayList; import java.util.Map; @@ -48,12 +52,16 @@ public void loadMeal(Storage mealStorage) { Parser.parseMealStorage(s); String mealDescription = Parser.mealStorageDescription; int mealSize = Parser.mealStorageSize; - String currentDate = Parser.mealStorageDate; - User.myMealList.mealListAll.add(new Meal(mealDescription, mealSize, currentDate)); + + String savedDate = Parser.mealStorageDate; + DateValidation.formatDateIfValid(savedDate); + + User.myMealList.mealListAll.add(new Meal(mealDescription, mealSize, savedDate)); } } Date currentDate = new Date(); String todayDate = currentDate.getDate(); + for (Meal m : User.myMealList.mealListAll) { if (m.getDate().equals(todayDate)) { User.myMealList.mealList.add(m); @@ -62,6 +70,12 @@ public void loadMeal(Storage mealStorage) { User.myMealList.mealListAll.removeAll(User.myMealList.mealList); } catch (FileNotFoundException e) { mealStorage.createFile(); + } catch (NonPositiveValueException | StorageErrorException | NumberFormatException | ParseException | + FutureDateException e) { + System.out.println("A saved meal data was corrupted. " + + "Unfortunately, i will need to clear all saved data for your meals. \n" + + "A new file for your mealList will be created for you."); + mealStorage.clearFile(); } } @@ -79,6 +93,8 @@ public void loadDrink(Storage drinkStorage) { Parser.parseDrinkStorage(s); String drinkDescription = Parser.drinkStorageDescription; String drinkDate = Parser.drinkStorageDate; + DateValidation.formatDateIfValid(drinkDate); + int drinkSize = Parser.drinkStorageSize; if (drinkDescription.equals("water")) { User.myDrinkList.waterListAll.add(new Water(drinkSize, drinkDate)); @@ -103,6 +119,12 @@ public void loadDrink(Storage drinkStorage) { User.myDrinkList.waterListAll.removeAll(User.myDrinkList.waterList); } catch (FileNotFoundException e) { drinkStorage.createFile(); + } catch (NonPositiveValueException | StorageErrorException | NumberFormatException | ParseException | + FutureDateException e) { + System.out.println("A saved drink data was corrupted. " + + "Unfortunately, i will need to clear all saved data for your drinks. \n" + + "A new file for your drinkList will be created for you."); + drinkStorage.clearFile(); } } @@ -121,10 +143,11 @@ public void loadExercise(Storage exerciseStorage) { String exerciseDescription = Parser.exerciseStorageDescription; int exerciseDuration = Parser.exerciseStorageDuration; ExerciseIntensity exerciseIntensity = Parser.exerciseStorageIntensity; - String currentDate = Parser.exerciseStorageDate; + String savedDate = Parser.exerciseStorageDate; + DateValidation.formatDateIfValid(savedDate); User.myExerciseList.exerciseListAll.add(new Exercise(exerciseDescription, exerciseDuration, exerciseIntensity, - currentDate)); + savedDate)); } } Date currentDate = new Date(); @@ -138,8 +161,14 @@ public void loadExercise(Storage exerciseStorage) { } catch (FileNotFoundException e) { exerciseStorage.createFile(); } catch (UnregisteredExerciseException e) { - System.out.println("Sorry that meal is not registered in the database. Please check the spelling and " + + System.out.println("Sorry that exercise is not registered in the database. Please check the spelling and " + "try again"); + } catch (NonPositiveValueException | StorageErrorException | NumberFormatException | ParseException | + FutureDateException e) { + System.out.println("A saved data was corrupted. " + + "Unfortunately, i will need to clear all saved data for your exercises. \n" + + "A new file for your exerciseList will be created for you."); + exerciseStorage.clearFile(); } } diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index b7a86ac397..5eae3d7c09 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -10,6 +10,7 @@ import seedu.fitnus.exception.InvalidDateException; import seedu.fitnus.exception.NegativeValueException; import seedu.fitnus.exception.NonPositiveValueException; +import seedu.fitnus.exception.StorageErrorException; import seedu.fitnus.exception.UnregisteredDrinkException; import seedu.fitnus.exception.UnregisteredExerciseException; import seedu.fitnus.exception.UnregisteredMealException; @@ -89,7 +90,7 @@ public void parseEditWater_validInputs_success() throws NonPositiveValueExceptio } @Test - public void parseMealStorage_validInputs_success() { + public void parseMealStorage_validInputs_success() throws NonPositiveValueException, StorageErrorException { String data = "chicken rice,1,12-02-2024"; Parser.parseMealStorage(data); assertEquals("chicken rice", Parser.mealStorageDescription); @@ -98,7 +99,7 @@ public void parseMealStorage_validInputs_success() { } @Test - public void parseDrinkStorage_validInputs_success() { + public void parseDrinkStorage_validInputs_success() throws NonPositiveValueException, StorageErrorException { String data = "milo,200,12-02-2024"; Parser.parseDrinkStorage(data); assertEquals("milo", Parser.drinkStorageDescription); @@ -107,7 +108,7 @@ public void parseDrinkStorage_validInputs_success() { } @Test - public void parseExerciseStorage_validInputs_success() { + public void parseExerciseStorage_validInputs_success() throws NonPositiveValueException, StorageErrorException { String data = "cycling,100,LOW,29-02-2024"; Parser.parseExerciseStorage(data); assertEquals("cycling", Parser.exerciseStorageDescription); From 8dbdb9461971f5b5c3fdb417bdff35818b183c0e Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 03:26:27 +0800 Subject: [PATCH 232/274] Fix checkstyle issue --- src/test/java/seedu/fitnus/parser/ParserTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/fitnus/parser/ParserTest.java b/src/test/java/seedu/fitnus/parser/ParserTest.java index 5eae3d7c09..57830b4579 100644 --- a/src/test/java/seedu/fitnus/parser/ParserTest.java +++ b/src/test/java/seedu/fitnus/parser/ParserTest.java @@ -84,8 +84,8 @@ public void parseEditDrink_unregisteredMeal_exceptionThrown() throws NonPositive @Test public void parseEditWater_validInputs_success() throws NonPositiveValueException, IncompleteEditWaterException { - String command_2 = "editWater s/500"; - Parser.parseEditWater(command_2); + String command2 = "editWater s/500"; + Parser.parseEditWater(command2); assertEquals(500, Parser.editWaterSize); } From f64235b1b77c565509a5f73144cda7886936cd5a Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 03:38:08 +0800 Subject: [PATCH 233/274] Fix bug for waterIntake that exceeds MAX_INT --- src/main/java/seedu/fitnus/drink/DrinkList.java | 3 ++- src/main/java/seedu/fitnus/drink/Water.java | 9 ++++++++- .../seedu/fitnus/exception/ExceedTypeIntException.java | 5 +++++ src/main/java/seedu/fitnus/parser/Parser.java | 5 +++++ src/main/java/seedu/fitnus/unused/CSVReader.java | 2 +- src/main/java/seedu/fitnus/unused/CSVWriter.java | 2 +- src/test/java/seedu/fitnus/drink/DrinkListTest.java | 3 ++- 7 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/main/java/seedu/fitnus/exception/ExceedTypeIntException.java diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index 95408de531..e39509da03 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -1,6 +1,7 @@ package seedu.fitnus.drink; import seedu.fitnus.date.Date; +import seedu.fitnus.exception.ExceedTypeIntException; import seedu.fitnus.exception.FutureDateException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; @@ -59,7 +60,7 @@ public void handleAddNewDrinkNutrient(String command) throws NegativeValueExcept * @throws NonPositiveValueException if the provided serving size is a negative value */ public void handleDrink(String command) throws IncompleteDrinkException, UnregisteredDrinkException, - NonPositiveValueException { + NonPositiveValueException, ExceedTypeIntException { Parser.parseDrink(command); String drinkName = Parser.drinkDescription; int servingSize = Parser.drinkSize; diff --git a/src/main/java/seedu/fitnus/drink/Water.java b/src/main/java/seedu/fitnus/drink/Water.java index 48ca484b92..24e76bfda5 100644 --- a/src/main/java/seedu/fitnus/drink/Water.java +++ b/src/main/java/seedu/fitnus/drink/Water.java @@ -1,5 +1,7 @@ package seedu.fitnus.drink; +import seedu.fitnus.exception.ExceedTypeIntException; + public class Water { private int waterIntake; private String dateAdded; @@ -30,8 +32,12 @@ public int getWater() { * * @param amount volume of water to add to intake. */ - public void addWaterIntake(int amount) { + public void addWaterIntake(int amount) throws ExceedTypeIntException { waterIntake += amount; + if (waterIntake <= 0) { + waterIntake -= amount; + throw new ExceedTypeIntException(); + } } /** @@ -41,6 +47,7 @@ public void addWaterIntake(int amount) { */ public void editWaterIntake(int amount) { waterIntake = amount; + } /** diff --git a/src/main/java/seedu/fitnus/exception/ExceedTypeIntException.java b/src/main/java/seedu/fitnus/exception/ExceedTypeIntException.java new file mode 100644 index 0000000000..a3be1f426e --- /dev/null +++ b/src/main/java/seedu/fitnus/exception/ExceedTypeIntException.java @@ -0,0 +1,5 @@ +package seedu.fitnus.exception; + +public class ExceedTypeIntException extends Exception { + +} diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index f18b1ce915..2a69fde384 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -2,6 +2,7 @@ import seedu.fitnus.date.DateValidation; import seedu.fitnus.drink.Drink; +import seedu.fitnus.exception.ExceedTypeIntException; import seedu.fitnus.exception.StorageErrorException; import seedu.fitnus.meal.Meal; import seedu.fitnus.exercise.Exercise; @@ -246,6 +247,10 @@ public void parseCommand(String command) { } catch (IncompleteEditWaterException e) { System.out.println("Please specify the new volume of water.\n" + "The format should be [editWater s/NEW_VOLUME(ML)]."); + } catch (ExceedTypeIntException e) { + System.out.println("Adding this amount of water will exceed a total of 2147483647ml water today. Are " + + "you sure you can drink so much water in a day? \nI shall remove this amount for now. EditWater " + + "if you deem fit :/"); } } diff --git a/src/main/java/seedu/fitnus/unused/CSVReader.java b/src/main/java/seedu/fitnus/unused/CSVReader.java index dade70a4e4..03f4d4376d 100644 --- a/src/main/java/seedu/fitnus/unused/CSVReader.java +++ b/src/main/java/seedu/fitnus/unused/CSVReader.java @@ -5,7 +5,7 @@ import java.io.IOException; import java.util.HashMap; -//@@author tinaliu27-unused +//@@author tinaliu27 -unused public class CSVReader { public static final String DELIMITER = ","; private static HashMap foodItems = new HashMap<>(); diff --git a/src/main/java/seedu/fitnus/unused/CSVWriter.java b/src/main/java/seedu/fitnus/unused/CSVWriter.java index bb606effb6..c37011f845 100644 --- a/src/main/java/seedu/fitnus/unused/CSVWriter.java +++ b/src/main/java/seedu/fitnus/unused/CSVWriter.java @@ -8,7 +8,7 @@ import java.text.SimpleDateFormat; import java.util.Date; -//@@author tinaliu27-unused +//@@author tinaliu27 -unused public class CSVWriter { public static void main(String[] args) { writeIntoFile("hi", "FOOD"); diff --git a/src/test/java/seedu/fitnus/drink/DrinkListTest.java b/src/test/java/seedu/fitnus/drink/DrinkListTest.java index b2d1290499..330ad88a74 100644 --- a/src/test/java/seedu/fitnus/drink/DrinkListTest.java +++ b/src/test/java/seedu/fitnus/drink/DrinkListTest.java @@ -2,6 +2,7 @@ import seedu.fitnus.date.Date; +import seedu.fitnus.exception.ExceedTypeIntException; import seedu.fitnus.exception.IncompleteDeleteException; import seedu.fitnus.exception.IncompleteDrinkException; import seedu.fitnus.exception.IncompleteEditException; @@ -42,7 +43,7 @@ public void setUp() { @Test public void handleDrink_validInputs_correctlyAddDrink() throws IncompleteDrinkException, - UnregisteredDrinkException, NonPositiveValueException { + UnregisteredDrinkException, NonPositiveValueException, ExceedTypeIntException { String command = "drink d/kopi s/500"; testerDrinkList.handleDrink(command); From f67f566a0c1d2fa1c4bd6b30d8002d3d821d9de5 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 03:44:11 +0800 Subject: [PATCH 234/274] Fix PED issue #122 on excessive water intake --- src/main/java/seedu/fitnus/user/User.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 6098e790db..6e53157e97 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -21,6 +21,7 @@ * Handles all methods related to the user's meals, drinks and exercise. */ public class User { + public static final int MAX_WATER_INTAKE = 10000; public static final int RECOMMEND_WATER_INTAKE = 2600; public static final long RECOMMEND_CALORIE_INTAKE = 2200; @@ -266,12 +267,16 @@ public void handleRecommendations() { for (Water water: myDrinkList.waterList) { waterIntake += water.getWater(); } - int waterDifference = RECOMMEND_WATER_INTAKE -waterIntake; + int waterDifference = RECOMMEND_WATER_INTAKE - waterIntake; if (waterIntake < RECOMMEND_WATER_INTAKE) { System.out.println("We recommend drinking more water. Please drink " + - waterDifference + " ml more water to hit the daily water intake goal :)"); + waterDifference + " ml more water by the end of the day to hit the daily water intake goal :)"); + } else if (waterIntake > MAX_WATER_INTAKE) { + System.out.println("You drank more than 10,000ml of water today! Did you really drink so much?\nPlease " + + "editWater if necessary, else be mindful to drink less water tomorrow :)\n" + + "Scientifically, you should drink less than 800ml an hour !"); } else { - System.out.println("Great! You are on track with the water intake!"); + System.out.println("Great! You are on track with the water intake today!"); } System.out.println(" ~~"); @@ -284,12 +289,13 @@ public void handleRecommendations() { } long caloriesDifference = RECOMMEND_CALORIE_INTAKE - caloriesIntakeCount; if (caloriesIntakeCount < RECOMMEND_CALORIE_INTAKE) { - System.out.println("We recommend eating more food. Please eat " + caloriesDifference + " more calories"); + System.out.println("We recommend eating more food. Please eat " + caloriesDifference + " more calories by" + + " today :)"); } else if (caloriesIntakeCount > RECOMMEND_CALORIE_INTAKE && caloriesIntakeCount < RECOMMEND_CALORIE_INTAKE + 200) { - System.out.println("Great! You are on track with the calorie intake!"); + System.out.println("Great! You are on track with the calorie intake for the day!"); } else { - System.out.println("You are " + -caloriesDifference + System.out.println("You ate " + -caloriesDifference + " calories above the recommended calorie intake amount, consider exercising!"); } } From b0016922c88e195150125cf4a60c1a21d4cc16d1 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 03:50:51 +0800 Subject: [PATCH 235/274] Fix PED issue #114 on units of measurement --- src/main/java/seedu/fitnus/drink/Drink.java | 12 ++++++------ src/main/java/seedu/fitnus/meal/Meal.java | 13 +++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/seedu/fitnus/drink/Drink.java b/src/main/java/seedu/fitnus/drink/Drink.java index c4a7171437..15cb7cb40c 100644 --- a/src/main/java/seedu/fitnus/drink/Drink.java +++ b/src/main/java/seedu/fitnus/drink/Drink.java @@ -81,13 +81,13 @@ private void setNutrientValues(String name) { public static void handleInfoDrink(String command) throws UnregisteredDrinkException, IncompleteInfoException { String name = Parser.parseInfoDrink(command); int[] nutrients = nutrientDetails.get(name); - System.out.println("Drink: " + name + " (100 ml)"); - System.out.println("Calories: " + nutrients[0]); - System.out.println("Carbs: " + nutrients[1]); + System.out.println("Drink: " + name + " (per 100 ml)"); + System.out.println("Calories: " + nutrients[0] + " kcal"); + System.out.println("Carbs: " + nutrients[1] + " g"); // Sugar is part of Carbohydrates - System.out.println("Sugar: " + nutrients[2]); - System.out.println("Protein: " + nutrients[3]); - System.out.println("Fat: " + nutrients[4]); + System.out.println("Sugar: " + nutrients[2] + " g"); + System.out.println("Protein: " + nutrients[3] + " g"); + System.out.println("Fat: " + nutrients[4] + " g"); } /** diff --git a/src/main/java/seedu/fitnus/meal/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java index d1c37fb8cf..5ee3d42972 100644 --- a/src/main/java/seedu/fitnus/meal/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -160,12 +160,13 @@ public static void handleInfoMeal(String command) throws UnregisteredMealExcepti String name = Parser.parseInfoMeal(command); int[] nutrients = nutrientDetails.get(name); System.out.println("Meal: " + name + " (per serving)"); - System.out.println("Calories: " + nutrients[0]); - System.out.println("Carbs: " + nutrients[1]); - System.out.println("Protein: " + nutrients[2]); - System.out.println("Fat: " + nutrients[3]); - System.out.println("Fiber: " + nutrients[4]); - System.out.println("Sugar: " + nutrients[5]); + System.out.println("Drink: " + name + " (per 100 ml)"); + System.out.println("Calories: " + nutrients[0] + " kcal"); + System.out.println("Carbs: " + nutrients[1] + " g"); + System.out.println("Protein: " + nutrients[2] + " g"); + System.out.println("Fat: " + nutrients[3] + " g"); + System.out.println("Fiber: " + nutrients[4] + " g"); + System.out.println("Sugar: " + nutrients[5] + " g"); } /** From 01e4377518743b9e2ae47343dc67927d7742e529 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 04:00:58 +0800 Subject: [PATCH 236/274] Fix PED issue #111 on clear() --- docs/UserGuide.md | 5 +++-- src/main/java/seedu/fitnus/user/User.java | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 7fddad71f3..c8f10a52c3 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -567,11 +567,12 @@ Removed Iced Lemon Tea From Drinks ## 1.7 For clearing data ### 1.7.1 Clear all entries: `clear` -Clear all entries in mealList and drinkList +Clear all entries that you added to mealList, drinkList and exerciseList TODAY. +Note: These are meals/drinks you consumed today or exercises you have done today. **Format**: `clear` **Expected output**: ~~~ -All entries have been deleted +All meals, drinks and exercise entries that you added to your lists today have been deleted. ~~~ ## 1.8: Exit program diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 6e53157e97..28aca2372d 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -254,7 +254,8 @@ public void handleClear() { assert myDrinkList.drinkList.isEmpty(): "clearing of drink list failed"; assert myExerciseList.exerciseList.isEmpty(): "clearing of exercise list failed"; - System.out.println("All entries have been deleted"); + System.out.println("All meals, drinks and exercise entries that you added to your lists today have been " + + "deleted."); } From 8cd4b14e378dcb8658fc3f9b4c750dd7f085d97a Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 05:30:28 +0800 Subject: [PATCH 237/274] Update user guide for 1.1 of feature list --- docs/UserGuide.md | 96 ++++++++----------- src/main/java/seedu/fitnus/drink/Drink.java | 2 +- .../java/seedu/fitnus/exercise/Exercise.java | 2 +- src/main/java/seedu/fitnus/meal/Meal.java | 2 +- 4 files changed, 44 insertions(+), 58 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index c8f10a52c3..3a5129f28f 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,7 +3,7 @@ FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. -Users are able to track the meals, drinks, and exercises they have in a day and even past records. +Users are able to track the meals, drinks, and exercises they have in a day and even view past records. ## Setup To use the app please follow the setup procedures below: @@ -18,61 +18,15 @@ Note: ## Table of Contents -* [User Guide: FitNUS](#user-guide-fitnus) - * [Project Introduction](#project-introduction) - * [Setup](#setup-) - * [Table of Contents](#table-of-contents) - * [1) Features List](#1-features-list) - * [1.1 Information for users](#11-information-for-users) - * [1.1.1 Viewing all commands: `help`](#111-viewing-all-commands-help) - * [1.1.2 Viewing all pre-defined meals: `allMeals`](#112-viewing-all-pre-defined-meals-allmeals) - * [1.1.3 Viewing all pre-defined drinks: `allDrinks`](#113-viewing-all-pre-defined-drinks-alldrinks) - * [1.1.4 Viewing all pre-defined exercises: `allExercises`](#114-viewing-all-pre-defined-exercises-allexercises) - * [1.2 For user to add data](#12-for-user-to-add-data) - * [1.2.1 Add a meal eaten: `eat`](#121-add-a-meal-eaten-eat) - * [1.2.2 Add a drink: `drink`](#122-add-a-drink-drink) - * [1.2.2.1 Add water: `drink d/water`](#1221-add-water-drink-dwater) - * [1.2.3 Add exercise: `exercise`](#123-add-exercise-exercise) - * [1.2.4 Add new meal to available meals: `newMeal`](#124-add-new-meal-to-available-meals-newmeal) - * [1.2.4 Add new meal to available meals: `newDrink`](#124-add-new-meal-to-available-meals-newdrink) - * [1.2.5 Add new exercise to available exercises: `newExercise`](#125-add-new-exercise-to-available-exercises-newexercise) +* [1) Features List](#1-features-list) + * [1.1 Information for users](#11-information-for-users) + * [1.2 For user to add data](#12-for-user-to-add-data) * [1.3 For data retrieval](#13-for-data-retrieval) - * [1.3.1 Find the information about a certain meal: `infoMeal`](#131-find-the-information-about-a-certain-meal-infomeal) - * [1.3.2 Find the information about a certain drink: `infoDrink`](#132-find-the-information-about-a-certain-drink-infodrink) - * [1.3.3 Find the information about a certain exercise: `infoExercise`](#133-find-the-information-about-a-certain-exercise-infoexercise) - * [1.3.4 View daily calories consumed: `calories`](#134-view-daily-calories-consumed-calories) - * [1.3.5 View daily carbohydrates consumed: `carbs`](#135-view-daily-carbohydrates-consumed-carbs) - * [1.3.6 View daily proteins consumed: `protein`](#136-view-daily-proteins-consumed-protein) - * [1.3.7 View daily fat consumed: `fat`](#137-view-daily-fat-consumed-fat) - * [1.3.8 View daily sugar consumed: `sugar`](#138-view-daily-sugar-consumed-sugar) - * [1.3.9 View daily fiber consumed: `fiber`](#139-view-daily-fiber-consumed-fiber) - * [1.3.10 View daily water consumption: `water`](#1310-view-daily-water-consumption-viewwater) - * [1.3.11 View daily calories consumed: `caloriesBurnt`](#1311-view-daily-calories-consumed-caloriesburnt) - * [1.3.12 View daily calories and water intake recommendation: `recommend`](#1312-view-daily-calories-and-water-intake-recommendation-recommend) * [1.4 For listing arrays](#14-for-listing-arrays) - * [1.4.1 List today's meal intake: `listMeals`](#141-list-todays-meal-intake-listmeals) - * [1.4.2 List today's drink intake: `listDrinks`](#142-list-todays-drink-intake-listdrinks) - * [1.4.3 List today's exercises done: `listExercises`](#143-list-todays-exercises-done-listexercises) - * [1.4.4 List everything inputted today: `listEverything`](#144-list-everything-inputted-today-listeverything) - * [1.4.5 List entire app's lifecycle meals intake: `listMealsAll`](#145-list-entire-apps-lifecycle-meals-intake-listmealsall) - * [1.4.6 List entire app's lifecycle drinks intake: `listDrinksAll`](#146-list-entire-apps-lifecycle-drinks-intake-listdrinksall) - * [1.4.7 List entire app's lifecycle exercises done: `listExercisesAll`](#147-list-entire-apps-lifecycle-exercises-done-listexercisesall) - * [1.4.8 List everything inputted for the entire app's lifecycle: `listEverythingAll`](#148-list-everything-inputted-for-the-entire-apps-lifecycle-listeverythingall) - * [1.4.9 List meal intake for a certain date: `listMeals d/[DATE]`](#149-list-meal-intake-for-a-certain-date-listmeals-ddate) - * [1.4.10 List drink intake for a certain date: `listDrinks d/[DATE]`](#1410-list-drink-intake-for-a-certain-date-listdrinks-ddate) - * [1.4.11 List exercise done for a certain date: `listExercises d/[DATE]`](#1411-list-exercise-done-for-a-certain-date-listexercises-ddate) - * [1.4.12 List entire food intake and exercise done for a certain date: `listEverything d/[DATE]`](#1412-list-entire-food-intake-and-exercise-done-for-a-certain-date-listeverything-ddate) * [1.5 For editing existing data](#15-for-editing-existing-data) - * [1.5.1 Edit an existing meal after inserted: `editMeal`](#151-edit-an-existing-meal-after-inserted-editmeal) - * [1.5.2 Edit an existing drink after inserted: `editDrink`](#152-edit-an-existing-drink-after-inserted-editdrink) - * [1.5.3 Edit water intake after inserted: `editWater`](#153-edit-water-intake-after-inserted-editwater) * [1.6 For deleting data](#16-for-deleting-data) - * [1.6.1 Delete certain meal entry: `deleteMeal`](#161-delete-certain-meal-entry-deletemeal) - * [1.6.2 Delete certain drink entry: `deleteDrink`](#162-delete-certain-drink-entry-deletedrink) * [1.7 For clearing data](#17-for-clearing-data) - * [1.7.1 Clear all entries: `clear`](#171-clear-all-entries-clear) * [1.8: Exit program](#18-exit-program) - * [1.8.1 Exit the app: `exit`](#181-exit-the-app-exit) ## 1) Features List @@ -150,13 +104,31 @@ be inputted immediately. **Expected Output**: ~~~ Available meals: +- ban mian +- tau huay +- nasi goreng +- babi kecap +- soup kambeng +- nasi lemak +- pepper lunch +- char siew rice +- pork satay with satay sauce +- roti prata +- mee goreng +- chendol +- wanton mee +- oyster omlette - pizza +- ice kachang - chicken rice - fried rice - kaya toast +- mala - laksa +- hokkien prawn mee +- durian -You may also input a meal that isn't here. +You may also input a meal that isn't here with newMeal. ~~~ ### 1.1.3 Viewing all pre-defined drinks: `allDrinks` @@ -166,12 +138,26 @@ and can be inputted immediately. **Expected Output**: ~~~ Available drinks: +- water - sprite -- milo - iced lemon tea +- milo - kopi - -You may also input a drink that isn't here. +- soursop juice +- kopi c +- kalamansi juice +- coke +- kopi o +- plum juice +- teh c bing +- guava juice +- tiger beer +- teh tarik +- sugarcane juice +- teh +- bandung + +You may also input a drink that isn't here with newDrink. ~~~ ### 1.1.4 Viewing all pre-defined exercises: `allExercises` @@ -185,7 +171,7 @@ Available exercises: - swimming - cycling -You may also input an exercise that isn't here. +You may also input an exercise that isn't here with newExercise. ~~~ ### 1.2 For user to add data diff --git a/src/main/java/seedu/fitnus/drink/Drink.java b/src/main/java/seedu/fitnus/drink/Drink.java index 15cb7cb40c..1056adf4f7 100644 --- a/src/main/java/seedu/fitnus/drink/Drink.java +++ b/src/main/java/seedu/fitnus/drink/Drink.java @@ -119,7 +119,7 @@ public static void listAvailableDrinks() { System.out.println("- " + drink); } System.out.println(); - System.out.println("You may also input a drink that isn't here."); + System.out.println("You may also input a drink that isn't here with newDrink."); } /** diff --git a/src/main/java/seedu/fitnus/exercise/Exercise.java b/src/main/java/seedu/fitnus/exercise/Exercise.java index 41f431f08e..c832bf665f 100644 --- a/src/main/java/seedu/fitnus/exercise/Exercise.java +++ b/src/main/java/seedu/fitnus/exercise/Exercise.java @@ -162,7 +162,7 @@ public static void listAvailableExercises() { System.out.println("- " + exercise); } System.out.println(); - System.out.println("You may also input an exercise that isn't here."); + System.out.println("You may also input an exercise that isn't here with newExercise."); } public static HashMap getExerciseDetails() { diff --git a/src/main/java/seedu/fitnus/meal/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java index 5ee3d42972..ce991879c1 100644 --- a/src/main/java/seedu/fitnus/meal/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -198,7 +198,7 @@ public static void listAvailableMeals() { System.out.println("- " + meal); } System.out.println(); - System.out.println("You may also input a meal that isn't here."); + System.out.println("You may also input a meal that isn't here with newMeal."); } public static HashMap getNutrientDetails() { From 2a1f64def5d7bdcb4800ccccc02ca06f4c8fe42d Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 05:31:19 +0800 Subject: [PATCH 238/274] Update Entire User Guide with a standardised format --- data/ExerciseList.txt | 5 +- db/Meal_db.csv | 21 +- docs/UserGuide.md | 403 +++++++++++------- .../java/seedu/fitnus/drink/DrinkList.java | 8 +- .../java/seedu/fitnus/exercise/Exercise.java | 6 +- .../seedu/fitnus/exercise/ExerciseList.java | 2 +- src/main/java/seedu/fitnus/meal/Meal.java | 1 - src/main/java/seedu/fitnus/parser/Parser.java | 6 +- .../seedu/fitnus/storage/StorageManager.java | 4 +- src/main/java/seedu/fitnus/user/User.java | 6 +- 10 files changed, 281 insertions(+), 181 deletions(-) diff --git a/data/ExerciseList.txt b/data/ExerciseList.txt index 561e56aeb9..a0d34f922b 100644 --- a/data/ExerciseList.txt +++ b/data/ExerciseList.txt @@ -1,2 +1,3 @@ -running,100,LOW,10-04-2024 -running,50,LOW,10-04-2024 +swimming,30,HIGH,15-04-2024 +swimming,100,HIGH,13-04-2024 +swimming,30,HIGH,14-04-2024 diff --git a/db/Meal_db.csv b/db/Meal_db.csv index 11617cca47..ca84124dfb 100644 --- a/db/Meal_db.csv +++ b/db/Meal_db.csv @@ -1,24 +1,27 @@ -ban mian,475,48,22,22,3,10 -tau huay,153,32,14,1,5,1 nasi goreng,346,45,13,12,10,2 babi kecap,607,75,25,23,2,10 +mie,607,75,25,23,2,100 +pepper lunch,500,50,40,11,4,5 +roti prata,209,32,5,7,2,10 +oyster omlette,467,40,19,24,10,1 +pizza,600,80,50,40,30,20 +ice kachang,257,58,6,1,10,2 +kaya toast,459,44,8,27,10,1 +hokkien prawn mee,522,69,18,19,4,10 +ban mian,475,48,22,22,3,10 +tau huay,153,32,14,1,5,1 +cookie,1000,100,100,100,100,100 soup kambeng,203,6,28,7,2,5 nasi lemak,494,80,13,14,6,5 -pepper lunch,500,50,40,11,4,5 char siew rice,605,91,24,16,6,10 pork satay with satay sauce,36,1,5,2,10,0 -roti prata,209,32,5,7,2,10 mee goreng,500,61,18,20,4,5 chendol,386,59,6,15,7,2 wanton mee,555,97,15,14,13,10 -oyster omlette,467,40,19,24,10,1 -pizza,600,80,50,40,30,20 -ice kachang,257,58,6,1,10,2 +1,600,100,1001,100,100,100 chicken rice,400,50,30,20,10,5 fried rice,500,60,25,15,15,5 -kaya toast,459,44,8,27,10,1 mala,583,72,12,30,10,7 laksa,377,71,18,2,4,10 -hokkien prawn mee,522,69,18,19,4,10 durian,147,27,2,5,3,5 diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3a5129f28f..6d03cd8d46 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -5,34 +5,42 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even view past records. -## Setup -To use the app please follow the setup procedures below: -1. Download the JAR file. -2. Place it into an empty folder. -3. Navigate to the folder you just created. -4. Run the JAR file. - -Note: -1. All files under 'data' and 'db' folders should not be modified by user -2. Enter "exit" to properly close the program and save the data ## Table of Contents -* [1) Features List](#1-features-list) - * [1.1 Information for users](#11-information-for-users) - * [1.2 For user to add data](#12-for-user-to-add-data) - * [1.3 For data retrieval](#13-for-data-retrieval) - * [1.4 For listing arrays](#14-for-listing-arrays) - * [1.5 For editing existing data](#15-for-editing-existing-data) - * [1.6 For deleting data](#16-for-deleting-data) - * [1.7 For clearing data](#17-for-clearing-data) - * [1.8: Exit program](#18-exit-program) +* [1) Setup](#1-setup-) +* [2) Features List](#2-features-list) + * [2.1 Information for users](#21-information-for-users) + * [2.2 For user to add data](#22-for-user-to-add-data) + * [2.3 For data retrieval](#23-for-data-retrieval) + * [2.4 For listing arrays](#24-for-listing-arrays) + * [2.5 For editing existing data](#25-for-editing-existing-data) + * [2.6 For deleting data](#26-for-deleting-data) + * [2.7 For clearing data](#27-for-clearing-data) + * [2.8 Exit program](#28-exit-program) -## 1) Features List -### 1.1 Information for users -### 1.1.1 Viewing all commands: `help` -Shows a list of all possible command inputs. +## 1) Setup +To use the app please follow the setup procedures below: +1. Download the JAR file. +2. Place it into an empty folder. +3. Navigate to the folder you just created. +4. Run the JAR file with the following command: +``` +-$ java -jar FitNUS.jar +``` + +**Note**: +1. All files under 'data' and 'db' folders should not be modified by user. +2. Enter `exit` to properly close the program and save the data. + +## 2) Features List +* For ease of reading this guide, _**sample input**_ is only provided if input command is not the command itself, i.e. the + input is not one-word. +## 2.1 Information for users +### 2.1.1 Viewing all commands: `help` +Shows a list of all possible command inputs recognised by the application. + **Format**: `help` **Expected Output**: ~~~ @@ -90,16 +98,20 @@ Delete Commands: Adding a meal/drink/exercises to available list: - Add a new meal to available meals: newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR - Add a new drink to available drinks: newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT -- Add a new exercise to available exercises: newExercise EXERCISE_NAME,CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW +- Add a new exercise to available exercises: newExercise EXERCISE_NAME,CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM, +CALORIES_BURNT_LOW Miscellaneous: - View daily calories and water intake recommendation: recommend - Clear all entries: clear - Exit the app: exit ~~~ -### 1.1.2 Viewing all pre-defined meals: `allMeals` +### 2.1.2 Viewing all pre-defined meals: `allMeals` Shows a list of all pre-defined meals. These meals will have their nutritional content defined per serving size and can be inputted immediately. +Note: If the user has added a self-defined meal previously (using `newMeal`), this self-defined meal will also be +displayed. + **Format**: `allMeals` **Expected Output**: ~~~ @@ -131,10 +143,13 @@ Available meals: You may also input a meal that isn't here with newMeal. ~~~ -### 1.1.3 Viewing all pre-defined drinks: `allDrinks` +### 2.1.3 Viewing all pre-defined drinks: `allDrinks` Shows a list of all pre-defined drinks. These drinks will have their nutritional content defined per 100ml -and can be inputted immediately. -**Format**: allDrinks +and can be inputted immediately. +Note: If the user has added a self-defined drink previously (using `newDrink`), this self-defined drink will also be +displayed. + +**Format**: allDrinks **Expected Output**: ~~~ Available drinks: @@ -160,10 +175,13 @@ Available drinks: You may also input a drink that isn't here with newDrink. ~~~ -### 1.1.4 Viewing all pre-defined exercises: `allExercises` +### 2.1.4 Viewing all pre-defined exercises: `allExercises` Shows a list of all pre-defined exercises. These exercises will have the number of calories burnt for a high/medium/low intensity workout defined per minute and can be inputted immediately. -**Format**: allExercises +Note: If the user has added a self-defined exercise previously (using `newExercise`), this self-defined exercise will +also be displayed. + +**Format**: allExercises **Expected Output**: ~~~ Available exercises: @@ -174,9 +192,13 @@ Available exercises: You may also input an exercise that isn't here with newExercise. ~~~ -### 1.2 For user to add data -### 1.2.1 Add a meal eaten: `eat` -Adds a meal to the list of meals +## 2.2 For user to add data +Importantly, any user-added data will only be saved to our database when you **safely exit** our application with the +command `exit`. Any other mode of termination will result in the loss of the inputs from this use. + +### 2.2.1 Add a meal eaten: `eat` +Adds a meal to the list of meals consumed today. + **Format**: `eat m/MEAL s/SERVING_SIZE` **Sample Input**: `eat m/Chicken Rice s/1` **Expected Output**: @@ -184,8 +206,10 @@ Adds a meal to the list of meals Added 1 serving of chicken rice ~~~ -### 1.2.2 Add a drink: `drink` -Adds a drink to the list of drinks +### 2.2.2 Add a drink: `drink` +Adds a drink to the list of drinks consumed today. +This includes adding a specified volume of water to the amount of water consumed today. + **Format**: `drink d/DRINK s/VOLUME(ML)` **Sample Input**: `drink d/Iced Lemon Tea s/200` **Expected Output**: @@ -193,17 +217,9 @@ Adds a drink to the list of drinks Added 200 ml of iced lemon tea ~~~ -### 1.2.2.1 Add water: `drink d/water` -Adds water to the list of water -**Format**: `drink d/water s/SERVING_SIZE` -**Sample Input**: `drink d/water s/100` -**Expected Output**: -~~~ -Added 100ml of water -~~~ +### 2.2.3 Add exercise: `exercise` +Adds an exercise to the list of exercises completed today. -### 1.2.3 Add exercise: `exercise` -Adds exercise to the list of exercises done **Format**: `exercise e/EXERCISE d/DURATION(MINUTES) i/INTENSITY(HIGH, MEDIUM, LOW)` **Sample Input**: `exercise e/swimming d/30 i/HIGH` **Expected Output**: @@ -211,8 +227,17 @@ Adds exercise to the list of exercises done Tracked 30 minutes of swimming ~~~ -### 1.2.4 Add new meal to available meals: `newMeal` -Adds a new meal to available meals +### 2.2.4 Add new meal to pre-defined meals: `newMeal` +Adds a user-defined new meal to the pre-defined meals. You would need to input the **meal name** and its +corresponding **nutritional content** (namely calories, carbohydrates content, protein, fat, fiber, sugar) per +serving of intake. + +A reminder that this user-defined meal will only be saved to our database when you **safely exit** our application with +the command `exit`. + +Note: We are not responsible for whether the meal name and its nutrional contents are accurate. +Please verify your information before inputting. + **Format**: `newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR` **Sample Input**: `newMeal mie,607,75,25,23,2,10` **Expected Output**: @@ -220,8 +245,17 @@ Adds a new meal to available meals Added mie to available meals ~~~ -### 1.2.4 Add new meal to available meals: `newDrink` -Adds a new drink to available drinks +### 2.2.5 Add new drink to pre-defined drinks: `newDrink` +Adds a user-defined new drink to the pre-defined drinks. You would need to input the **drink name** and its +corresponding **nutritional content** (namely calories, carbohydrates content, sugar, protein, fat) per **100ml** of +intake. + +A reminder that this user-defined drink will only be saved to our database when you **safely exit** our application +with the command `exit`. + +Note: We are not responsible for whether the drink name and its nutrional contents are accurate. +Please verify your information before inputting. + **Format**: `newDrink DRINK_NAME,CALORIES,CARBS,SUGAR,PROTEIN,FAT` **Sample Input**: `newDrink coke,153,32,1,2,1` **Expected Output**: @@ -229,136 +263,162 @@ Adds a new drink to available drinks Added coke to available drinks ~~~ -### 1.2.5 Add new exercise to available exercises: `newExercise` -Adds a new exercise to available exercises -**Format**: `newExercise EXERCISE_NAME,CALORIES_BURNT_HIGH,CALORIES_BURNT_MEDIUM,CALORIES_BURNT_LOW` +### 2.2.6 Add new exercise to pre-defined exercises: `newExercise` +Adds a user-defined new exercise to the pre-defined exercises. You would need to input the **exercise name** and its +corresponding **calories burnt** for a **1 minute** HIGH, MEDIUM and LOW intensity workout. + +A reminder that this user-defined exercise will only be saved to our database when you **safely exit** our application +with the command `exit`. + +Note: We are not responsible for whether the exercise name and its calories burnt are accurate. +Please verify your information before inputting. + +**Format**: `newExercise EXERCISE_NAME, CALORIES_BURNT_HIGH, CALORIES_BURNT_MEDIUM, CALORIES_BURNT_LOW` **Sample Input**: `newExercise badminton,20,10,5` **Expected Output**: ~~~ Added badminton to available exercises ~~~ -## 1.3 For data retrieval -### 1.3.1 Find the information about a certain meal: `infoMeal` -For the specified meal, display its nutritional content to the user +## 2.3 For data retrieval +### 2.3.1 Find the information about a certain meal: `infoMeal` +For the specified meal, display its nutritional content **per serving** to the user. + **Format**: `infoMeal MEAL` **Sample Input**: `infoMeal chicken rice` **Expected Output**: ~~~ -Meal: chicken rice (per serving)` -Calories: 400 -Carbs: 50 -Protein: 30 -Fat: 20 -Fiber: 10 -Sugar: 5 -Sugar: 5 +Meal: chicken rice (per serving) +Calories: 400 kcal +Carbs: 50 g +Protein: 30 g +Fat: 20 g +Fiber: 10 g +Sugar: 5 g ~~~ -### 1.3.2 Find the information about a certain drink: `infoDrink` -For the inputted drink, display its nutritional content to the user +### 2.3.2 Find the information about a certain drink: `infoDrink` +For the specified drink, display its nutritional content **per 100ml** to the user. + **Format**: `infoDrink DRINK` **Sample input**: `infoDrink milo` **Expected output**: ~~~ -Drink: milo (100 ml) -Calories: 124 -Carbs: 20 -Sugar: 3 -Protein: 3 -Fat: 1 +Drink: milo (per 100 ml) +Calories: 124 kcal +Carbs: 20 g +Sugar: 3 g +Protein: 3 g +Fat: 1 g ~~~ -### 1.3.3 Find the information about a certain exercise: `infoExercise` -For the inputted exercise, display its calories burnt per minute for different intensities to the user +### 2.3.3 Find the information about a certain exercise: `infoExercise` +For the specified exercise, display its **calories burnt per minute** for different intensities (HIGH, MEDIUM, LOW) to +the user. + **Format**: `infoExercise EXERCISE` **Sample input**: `infoExercise swimming` **Expected output**: ~~~ Exercise: swimming ~ Calories burnt for a 1 minute workout of ~ -HIGH intensity: 12 -MEDIUM intensity: 8 -LOW intensity: 5 +HIGH intensity: 12 kcal +MEDIUM intensity: 8 kcal +LOW intensity: 5 kcal ~~~ -### 1.3.4 View daily calories consumed: `calories` -Display current total calorie intake for the day +### 2.3.4 View daily net calorie count: `calories` +Display current net calorie count **in kcal** for the day. This takes into account the calories consumed from meals +and drinks, +and the calories burnt from exercise. + **Format**: `calories` **Expected output**: ~~~ -Total Calories: 100 +Total Calories: 230 kcal ~~~ -### 1.3.5 View daily carbohydrates consumed: `carbs` -Display current total carbohydrates intake for the day +### 2.3.5 View daily carbohydrates consumed: `carbs` +Display current total carbohydrates intake **in grams** for the day. + **Format**: `carbs` **Expected output**: ~~~ Total Carbohydrates: 150 grams ~~~ -### 1.3.6 View daily proteins consumed: `protein` -Display current total protein intake for the day +### 2.3.6 View daily proteins consumed: `protein` +Display current total protein intake **in grams** for the day. + **Format**: `protein` **Expected output**: ~~~ Total Proteins: 100 grams ~~~ -### 1.3.7 View daily fat consumed: `fat` -Display current total fat intake for the day +### 2.3.7 View daily fat consumed: `fat` +Display current total fat intake **in grams** for the day. + **Format**: `fat` **Expected output**: ~~~ Total Fat: 50 grams ~~~ -### 1.3.8 View daily sugar consumed: `sugar` -Display current total sugar intake for the day +### 2.3.8 View daily sugar consumed: `sugar` +Display current total sugar intake **in grams** for the day. + **Format**: `sugar` **Expected output**: ~~~ Total Sugar: 20 grams ~~~ -### 1.3.9 View daily fiber consumed: `fiber` -Display current total fiber intake (g) for the day +### 2.3.9 View daily fiber consumed: `fiber` +Display current total fiber intake **in grams** for the day. + **Format**: `fiber` **Expected output**: ~~~ Total Fiber: 20 grams ~~~ -### 1.3.10 View daily water consumption: `water` -Display current total water intake (in ml) for the day +### 2.3.10 View daily water consumption: `water` +Display current total water intake **in ml** for the day. + **Format**: `water` **Expected output**: ~~~ Total water intake today: 0 ml ~~~ -### 1.3.11 View daily calories consumed: `caloriesBurnt` -Display current total calorie burnt for the day +### 2.3.11 View daily calories consumed: `caloriesBurnt` +Display current total calorie burnt **in kcal** for the day. + **Format**: `caloriesBurnt` **Expected output**: ~~~ -Total calories burnt: 70 +Total calories burnt: 360 kcal ~~~ -### 1.3.12 View daily calories and water intake recommendation: `recommend` -Display today's recommended water and calories intake +### 2.3.12 View daily calories and water intake recommendations: `recommend` +Display a recommendation based on the current water and calories intake. +Note: This is a very simplified recommendation system that takes into account that an average human being should drink +approximately 2600ml of water and 2200kcal per day. + **Format**: `recommend` **Expected output**: ~~~ -Great! You are on track with the water intake! - ~~ -Recommend eating more food. Please eat 500 more calories +We recommend drinking more water. Please drink 2600 ml more water by the end of the day to hit the daily water +intake goal :) + ~~ +We recommend eating more food. Please eat 1610 more calories by today :) ~~~ -## 1.4 For listing arrays -### 1.4.1 List today's meal intake: `listMeals` -Display all the meals user input today +## 2.4 For listing arrays +### 2.4.1 List today's meal intake: `listMeals` +Display all the meals the user has inputted today. + **Format**: `listMeals` **Expected output**: ~~~ @@ -366,8 +426,9 @@ here's what you have eaten today 1. chicken rice (serving size: 1) | date: 01-04-2024 ~~~ -### 1.4.2 List today's drink intake: `listDrinks` -Display all the drinks user input today +### 2.4.2 List today's drink intake: `listDrinks` +Display all the drinks user has inputted today. + **Format**: `listDrinks` **Expected output**: ~~~ @@ -377,8 +438,9 @@ here's what you have drank today Total water intake today: 0 ml ~~~ -### 1.4.3 List today's exercises done: `listExercises` -Display all the exercises user tracked today +### 2.4.3 List today's exercises done: `listExercises` +Display all the exercises user tracked today. + **Format**: `listExercises` **Expected output**: ~~~ @@ -386,8 +448,9 @@ here's the exercises you've done today 1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.4 List everything inputted today: `listEverything` -Display all the meals, drinks and exercises user tracked today +### 2.4.4 List everything inputted today: `listEverything` +Display all the meals, drinks and exercises user tracked today. + **Format**: `listEverything` **Expected output**: ~~~ @@ -401,8 +464,12 @@ here's the exercises you've done today 1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.5 List entire app's lifecycle meals intake: `listMealsAll` -Display all the meals user inputted for the entire app lifecycle +### 2.4.5 List all meals intake from the entire app's lifecycle : `listMealsAll` +Display all the meals inputted during the entire app lifecycle. +Note: As mentioned, meals are only saved to our database when you **safely exit** our application with the +command `exit`. Any other mode of termination will result in the loss of the inputs from that use. + + **Format**: `listMealsAll` **Expected output**: ~~~ @@ -411,8 +478,11 @@ here's what you have eaten so far 2. chicken rice (serving size: 1) | date: 01-04-2024 ~~~ -### 1.4.6 List entire app's lifecycle drinks intake: `listDrinksAll` -Display all the drinks user inputted for the entire app lifecycle +### 2.4.6 List all drinks intake from the entire app's lifecycle: `listDrinksAll` +Display all the drinks inputted during the entire app lifecycle. +Note: As mentioned, drinks are only saved to our database when you **safely exit** our application with the +command `exit`. Any other mode of termination will result in the loss of the inputs from that use. + **Format**: `listDrinksAll` **Expected output**: ~~~ @@ -423,8 +493,11 @@ here's what you have drank so far Total water intake today: 100 ml ~~~ -### 1.4.7 List entire app's lifecycle exercises done: `listExercisesAll` -Display all the exercises inputted for the entire app lifecycle +### 2.4.7 List all exercises done from the entire app's lifecycle: `listExercisesAll` +Display all the exercises inputted during the entire app lifecycle. +Note: As mentioned, exercises are only saved to our database when you **safely exit** our application with the +command `exit`. Any other mode of termination will result in the loss of the inputs from that use. + **Format**: `listExercisesAll` **Expected output**: ~~~ @@ -434,8 +507,9 @@ here's the exercises you've done so far 3. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.8 List everything inputted for the entire app's lifecycle: `listEverythingAll` -Display all the drinks, meals, and exercises inputted for the entire app lifecycle +### 2.4.8 List everything inputted for the entire app's lifecycle: `listEverythingAll` +Display all the drinks, meals, and exercises inputted for the entire app lifecycle. + **Format**: `listEverythingAll` **Expected output**: ~~~ @@ -453,9 +527,12 @@ here's the exercises you've done so far 3. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.9 List meal intake for a certain date: `listMeals d/[DATE]` -Display all the meals user inputted for the specified date +### 2.4.9 List meal intake for a certain date: `listMeals d/[DATE]` +Display all the meals user inputted for the specified date, in the format **dd-MM-yyyy**. You may not view a +future date, i.e. dates from tomorrow onwards. + **Format**: `listMeals d/dd-MM-yyyy` +**Sample input**: `listMeals d/01-04-2024` **Expected output**: ~~~ here's what you have eaten on 01-04-2024 @@ -465,9 +542,12 @@ here's what you have eaten on 01-04-2024 4. roti prata (serving size: 2) | date: 01-04-2024 ~~~ -### 1.4.10 List drink intake for a certain date: `listDrinks d/[DATE]` -Display all the drinks user inputted for the specified date (excluding water) +### 2.4.10 List drink intake for a certain date: `listDrinks d/[DATE]` +Display all the drinks user inputted for the specified date (excluding water), in the format **dd-MM-yyyy**. You may not view a +future date, i.e. dates from tomorrow onwards. + **Format**: `listDrinks d/dd-MM-yyyy` +**Sample input**: `listDrinks d/01-04-2024` **Expected output**: ~~~ here's what you have drank on 01-04-2024 @@ -476,18 +556,24 @@ here's what you have drank on 01-04-2024 3. milo (volume: 200ml) | date: 01-04-2024 ~~~ -### 1.4.11 List exercise done for a certain date: `listExercises d/[DATE]` -Display all the exercises user inputted for the specified date +### 2.4.11 List exercise done for a certain date: `listExercises d/[DATE]` +Display all the exercises user inputted for the specified date, in the format **dd-MM-yyyy**. You may not view a +future date, i.e. dates from tomorrow onwards. + **Format**: `listExercises d/dd-MM-yyyy` +**Sample input**: `listExercises d/01-04-2024` **Expected output**: ~~~ here's the exercises you've done on 01-04-2024 1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -### 1.4.12 List entire food intake and exercise done for a certain date: `listEverything d/[DATE]` -Display all the meals, drinks, and exercises user inputted for the specified date +### 2.4.12 List everything inputted for a certain date: `listEverything d/[DATE]` +Display all the meals, drinks, and exercises user inputted for the specified date, in the format **dd-MM-yyyy**. You may not view a +future date, i.e. dates from tomorrow onwards. + **Format**: `listEverything d/dd-MM-yyyy` +**Sample input**: `listEverything d/01-04-2024` **Expected output**: ~~~ here's what you have consumed on 01-04-2024 @@ -504,65 +590,74 @@ here's the exercises you've done on 01-04-2024 1. boxing | duration: 10 | intensity: LOW | date: 01-04-2024 ~~~ -## 1.5 For editing existing data -### 1.5.1 Edit an existing meal after inserted: `editMeal` -For a meal that was inputted in the day, edit its serving size +## 2.5 For editing existing data +### 2.5.1 Edit an existing meal after inserted: `editMeal` +For a meal that was inputted in the day, edit its serving size. You may identify the meal by its index in listMeals. + **Format**: `editMeal INDEX s/NEW_SERVING_SIZE` -**Sample input**: `editMeal 2 s/2` +**Sample input**: `editMeal 2 s/10` **Expected output**: ~~~ -Pizza has been edited to 2 servings +chicken rice has been edited to 10 serving(s) ~~~ -### 1.5.2 Edit an existing drink after inserted: `editDrink` -For a drink that was inputted in the day, edit its serving size -**Format**: `editDrink INDEX s/NEW_SERVING_SIZE` -**Sample input**: editDrink 1 s/200 +### 2.5.2 Edit an existing drink after inserted: `editDrink` +For a drink that was inputted in the day, edit its intake volume. You may identify the drink by its index in +listDrinks. + +**Format**: `editDrink INDEX s/NEW_VOLUME` +**Sample input**: `editDrink 1 s/200` **Expected output**: ~~~ -Sprite has been edited to 200 ml +iced lemon tea has been edited to 200 ml ~~~ -### 1.5.3 Edit water intake after inserted: `editWater` -Edit serving size of total water intake +### 2.5.3 Edit water intake after inserted: `editWater` +Edit the total volume of water intake of the day, in ml. + **Format**: `editWater s/TOTAL_WATER_INTAKE` -**Sample input**: `editWater 200` +**Sample input**: `editWater s/200` **Expected output**: ~~~ -Total water has been edited to 200 ml +Total water intake has been edited to 200 ml ~~~ -## 1.6 For deleting data -### 1.6.1 Delete certain meal entry: `deleteMeal` -For a meal that was inputted in the day, delete its input based on its index in the meal list -**Format**: `deleteMeal INDEX` -**Sample Input**: `deleteMeal 1` -**Expected output**: +## 2.6 For deleting data +### 2.6.1 Delete certain meal entry: `deleteMeal` +Delete a meal that was inputted today. You may identify the meal by its index in listMeals. + +**Format**: `deleteMeal INDEX` +**Sample Input**: `deleteMeal 1` +**Expected output**: ~~~ -Removed Chicken Rice From Meals +Removed chicken rice from meals ~~~ -### 1.6.2 Delete certain drink entry: `deleteDrink` -For a drink that was inputted in the day, delete its input based on its index in the drink list +### 2.6.2 Delete certain drink entry: `deleteDrink` +Delete a drink that was inputted today. You may identify the drink by its index in listDrinks. + **Format**: `deleteDrink INDEX` **Sample input**: `deleteDrink 1` **Expected output:** ~~~ -Removed Iced Lemon Tea From Drinks +Removed iced lemon tea from drinks ~~~ -## 1.7 For clearing data -### 1.7.1 Clear all entries: `clear` -Clear all entries that you added to mealList, drinkList and exerciseList TODAY. +## 2.7 For clearing data +### 2.7.1 Clear all entries: `clear` +Clear all entries that was added to mealList, drinkList and exerciseList **today**. Note: These are meals/drinks you consumed today or exercises you have done today. + **Format**: `clear` **Expected output**: ~~~ -All meals, drinks and exercise entries that you added to your lists today have been deleted. +All meals, drinks and exercise entries that you added to your lists today have been deleted ~~~ -## 1.8: Exit program -### 1.8.1 Exit the app: `exit` +## 2.8 Exit program +### 2.8.1 Exit the app: `exit` +Safely close the application. Don't worry, all your inputs will be saved while you're gone :) + **Format**: `exit` **Expected output**: ~~~ diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index e39509da03..14f7329b46 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -48,7 +48,7 @@ public void handleAddNewDrinkNutrient(String command) throws NegativeValueExcept int fat = Parser.drinkNutrientFat; Drink.nutrientDetails.put(description, new int[]{calories, carbs, sugar, protein, fat}); - System.out.println("Added " + description + " to available drinks."); + System.out.println("Added " + description + " to available drinks"); } /** @@ -207,7 +207,7 @@ public void handleEditDrinkServingSize(String command) throws InvalidListIndexEx Drink updatedDrink = new Drink(drinkName, Parser.editDrinkSize, drinkDate); drinkList.set(Parser.editDrinkIndex, updatedDrink); - System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml."); + System.out.println(drinkName + " has been edited to " + Parser.editDrinkSize + " ml"); } @@ -230,7 +230,7 @@ public void handleEditWaterIntake(String command) throws NonPositiveValueExcepti if (waterList.isEmpty()) { throw new InvalidEditWaterException(); } - System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml."); + System.out.println("Total water intake has been edited to " + Parser.editWaterSize + " ml"); } /** @@ -253,7 +253,7 @@ public void handleDeleteDrink(String command) throws InvalidListIndexException, String drinkName = drinkList.get(drinkIndex).getName(); drinkList.remove(drinkIndex); - System.out.println("Removed " + drinkName + " from drinks."); + System.out.println("Removed " + drinkName + " from drinks"); } diff --git a/src/main/java/seedu/fitnus/exercise/Exercise.java b/src/main/java/seedu/fitnus/exercise/Exercise.java index c832bf665f..4a313f079b 100644 --- a/src/main/java/seedu/fitnus/exercise/Exercise.java +++ b/src/main/java/seedu/fitnus/exercise/Exercise.java @@ -128,9 +128,9 @@ public static void handleInfoExercise(String command) throws UnregisteredExercis } System.out.println("Exercise: " + name); System.out.println("~ Calories burnt for a 1 minute workout of ~"); - System.out.println("HIGH intensity: " + details[0]); - System.out.println("MEDIUM intensity: " + details[1]); - System.out.println("LOW intensity: " + details[2]); + System.out.println("HIGH intensity: " + details[0] + " kcal"); + System.out.println("MEDIUM intensity: " + details[1] + " kcal"); + System.out.println("LOW intensity: " + details[2] + " kcal"); } /** diff --git a/src/main/java/seedu/fitnus/exercise/ExerciseList.java b/src/main/java/seedu/fitnus/exercise/ExerciseList.java index 9c2f8519b7..4d00f6c3ed 100644 --- a/src/main/java/seedu/fitnus/exercise/ExerciseList.java +++ b/src/main/java/seedu/fitnus/exercise/ExerciseList.java @@ -171,6 +171,6 @@ public void handleCaloriesBurnt() throws ExceedTypeLongException { caloriesBurnt += exercise.getCaloriesBurnt(); } IntegerValidation.checkNoOverflowForSum(caloriesBurnt); - System.out.println("Total calories burnt: " + caloriesBurnt); + System.out.println("Total calories burnt: " + caloriesBurnt + " kcal"); } } diff --git a/src/main/java/seedu/fitnus/meal/Meal.java b/src/main/java/seedu/fitnus/meal/Meal.java index ce991879c1..a416ace560 100644 --- a/src/main/java/seedu/fitnus/meal/Meal.java +++ b/src/main/java/seedu/fitnus/meal/Meal.java @@ -160,7 +160,6 @@ public static void handleInfoMeal(String command) throws UnregisteredMealExcepti String name = Parser.parseInfoMeal(command); int[] nutrients = nutrientDetails.get(name); System.out.println("Meal: " + name + " (per serving)"); - System.out.println("Drink: " + name + " (per 100 ml)"); System.out.println("Calories: " + nutrients[0] + " kcal"); System.out.println("Carbs: " + nutrients[1] + " g"); System.out.println("Protein: " + nutrients[2] + " g"); diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 2a69fde384..0350c0c025 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -524,7 +524,8 @@ public static void parseMealStorage(String data) throws StorageErrorException, N * * @param data The data string to be parsed. */ - public static void parseDrinkStorage(String data) throws StorageErrorException, NonPositiveValueException { + public static void parseDrinkStorage(String data) throws StorageErrorException, NonPositiveValueException, + NumberFormatException { String delimiter = ","; String[] arrayOfDrinkData = data.split(delimiter); if (arrayOfDrinkData.length != 3) { @@ -541,7 +542,8 @@ public static void parseDrinkStorage(String data) throws StorageErrorException, * * @param data The data string to be parsed. */ - public static void parseExerciseStorage(String data) throws NonPositiveValueException, StorageErrorException { + public static void parseExerciseStorage(String data) throws NonPositiveValueException, StorageErrorException, + NumberFormatException { String delimiter = ","; String[] arrayOfExerciseData = data.split(delimiter); if (arrayOfExerciseData.length != 4) { diff --git a/src/main/java/seedu/fitnus/storage/StorageManager.java b/src/main/java/seedu/fitnus/storage/StorageManager.java index 0aa0d170d4..29f5e5b60e 100644 --- a/src/main/java/seedu/fitnus/storage/StorageManager.java +++ b/src/main/java/seedu/fitnus/storage/StorageManager.java @@ -92,11 +92,11 @@ public void loadDrink(Storage drinkStorage) { for (String s : drinkStorageList) { Parser.parseDrinkStorage(s); String drinkDescription = Parser.drinkStorageDescription; + int drinkSize = Parser.drinkStorageSize; String drinkDate = Parser.drinkStorageDate; DateValidation.formatDateIfValid(drinkDate); - int drinkSize = Parser.drinkStorageSize; - if (drinkDescription.equals("water")) { + if (drinkDescription.trim().equals("water")) { User.myDrinkList.waterListAll.add(new Water(drinkSize, drinkDate)); } else { User.myDrinkList.drinkListAll.add(new Drink(drinkDescription, drinkSize, drinkDate)); diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index 28aca2372d..49324420e7 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -59,7 +59,7 @@ public void handleViewCalories() throws ExceedTypeLongException { assert caloriesBurntCount >= 0: "total calories burnt has to be a non-negative value"; long caloriesCount = caloriesIntakeCount - caloriesBurntCount; - System.out.println("Total Calories: " + caloriesCount); + System.out.println("Total Calories: " + caloriesCount + " kcal"); } catch (ExceedTypeLongException e) { System.out.println("the amount of calories you burnt has exceeded our data limits. please do a quick " + "check to make sure your exerciseList is accurate!"); @@ -255,7 +255,7 @@ public void handleClear() { assert myExerciseList.exerciseList.isEmpty(): "clearing of exercise list failed"; System.out.println("All meals, drinks and exercise entries that you added to your lists today have been " + - "deleted."); + "deleted"); } @@ -270,7 +270,7 @@ public void handleRecommendations() { } int waterDifference = RECOMMEND_WATER_INTAKE - waterIntake; if (waterIntake < RECOMMEND_WATER_INTAKE) { - System.out.println("We recommend drinking more water. Please drink " + + System.out.println("We recommend drinking more water.\n Please drink " + waterDifference + " ml more water by the end of the day to hit the daily water intake goal :)"); } else if (waterIntake > MAX_WATER_INTAKE) { System.out.println("You drank more than 10,000ml of water today! Did you really drink so much?\nPlease " + From e38490ac564546aaec24fba7b0706f247ffc554a Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 05:45:18 +0800 Subject: [PATCH 239/274] Update tests to changes --- src/test/java/seedu/fitnus/exercise/ExerciseListTest.java | 2 +- src/test/java/seedu/fitnus/user/UserTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java index 6275455cc9..9bd1f1b057 100644 --- a/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java +++ b/src/test/java/seedu/fitnus/exercise/ExerciseListTest.java @@ -54,7 +54,7 @@ public void handleExercise_validInputs_correctlyAddExercise() throws IncompleteE public void handleViewCaloriesBurnt_correctCalorieBurntCalculation_viewCaloriesBurntAccurate() throws ExceedTypeLongException { testerExerciseList.handleCaloriesBurnt(); - String expectedOutput = "Total calories burnt: 240"; + String expectedOutput = "Total calories burnt: 240 kcal"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); diff --git a/src/test/java/seedu/fitnus/user/UserTest.java b/src/test/java/seedu/fitnus/user/UserTest.java index 57ae77ae65..c0bb9c5cf7 100644 --- a/src/test/java/seedu/fitnus/user/UserTest.java +++ b/src/test/java/seedu/fitnus/user/UserTest.java @@ -48,7 +48,7 @@ public void setUp() throws UnregisteredExerciseException { @Test public void handleViewCalories_correctCalorieCalculation_viewCaloriesAccurate() throws ExceedTypeLongException { testUser.handleViewCalories(); - String expectedOutput = "Total Calories: 5507"; + String expectedOutput = "Total Calories: 5507 kcal"; String actualOutput = outputStream.toString().trim(); assertEquals(actualOutput, expectedOutput); From d9ce54e64d2c8f9d7910889fe977fa011e10af1f Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 05:55:49 +0800 Subject: [PATCH 240/274] Test reposense --- src/main/java/seedu/fitnus/drink/DrinkList.java | 1 + src/main/java/seedu/fitnus/meal/MealList.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/seedu/fitnus/drink/DrinkList.java b/src/main/java/seedu/fitnus/drink/DrinkList.java index 0d2779a885..61b01239e3 100644 --- a/src/main/java/seedu/fitnus/drink/DrinkList.java +++ b/src/main/java/seedu/fitnus/drink/DrinkList.java @@ -219,6 +219,7 @@ public void handleEditDrinkServingSize(String command) throws InvalidListIndexEx * @throws IncompleteEditWaterException if the user did not comply with the required command format * @throws InvalidEditWaterException if the user tried to edit water intake before adding water for the ddy */ + //@@author Bryvo public void handleEditWaterIntake(String command) throws NonPositiveValueException, IncompleteEditWaterException, InvalidEditWaterException { Parser.parseEditWater(command); diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index d4e1b3d5cc..16da70d6b0 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -151,6 +151,7 @@ public static void handleListMealsDate(String command) throws InvalidDateExcepti * @throws NonPositiveValueException if the provided serving size is a negative value * @throws IncompleteEditException if the user did not comply with the required command format */ + //@@author claribelho public static void handleEditMealServingSize(String command) throws InvalidListIndexException, NonPositiveValueException, IncompleteEditException { Parser.parseEditMeal(command); //Parser handles the index, so index can be = 0 From 5251236eb82ebb060dbc4a008027f47b4f6e1e47 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 06:08:23 +0800 Subject: [PATCH 241/274] Update README --- README.md | 49 +++++++++++++++++++++++++++-------------------- docs/README.md | 22 +++++++++++++-------- docs/UserGuide.md | 16 +++++++++++++--- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index fef4168009..746ddb54e0 100644 --- a/README.md +++ b/README.md @@ -3,29 +3,33 @@ FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. -Users are able to track the meals, drinks, and exercises they have in a day and even past records. -*** -## Setup +Users are able to track the meals, drinks, and exercises they have in a day and even past records. +--- +## Setup To use the app please follow the setup procedures below: -1. Download the JAR file. -2. Place it into an empty folder. +1. Download the JAR file. +2. Place it into an empty folder. 3. Navigate to the folder you just created. -4. Run the JAR file. -*** +4. Run the JAR file with the following command: +``` +-$ java -jar FitNUS.jar +``` + +--- ## Features List ### 1 Information for users 1. View all possible commands: `help` 2. View all pre-defined meals. These meals will have their nutritional content defined per serving size and can -be inputted immediately: `allMeals` + be inputted immediately: `allMeals` 3. View all pre-defined drinks. These drinks will have their nutritional content defined per 100ml -and can be inputted immediately: `allDrinks` -4 Viewing all pre-defined exercises. These exercises will have the number of calories burnt for a -high/medium/low intensity workout defined per minute and can be inputted immediately: `allExercises` + and can be inputted immediately: `allDrinks` +4. Viewing all pre-defined exercises. These exercises will have the number of calories burnt for a + high/medium/low intensity workout defined per minute and can be inputted immediately: `allExercises` ### 2 For user to add data -1. Adds a meal to the list of meals eaten today: `eat` -2. Add a drink list of drinks drank today: `drink` -3. Add exercise to the list of exercises done : `exercise` +1. Adds a meal to the list of meals consumed today: `eat` +2. Add a drink to the list of drinks consumed today: `drink` +3. Add an exercise to the list of exercises done: `exercise` 4. Add a custom new meal on top of pre-defined meals: `newMeal` 5. Add a custom new drink on top of pre-defined drink: `newDrink` 6. Add a custom new exercise on top of pre-defined exercises: `newExercise` @@ -34,16 +38,16 @@ high/medium/low intensity workout defined per minute and can be inputted immedia 1. Find nutritional content about a certain meal: `infoMeal` 2. Find nutritional content about a certain drink: `infoDrink` 3. Find the calories burnt per minute from a certain exercise: `infoExercise` -4. View daily calories consumed: `calories` +4. View daily net calorie count: `calories` 5. View daily carbohydrates consumed: `carbs` 6. View daily proteins consumed: `protein` 7. View daily fat consumed: `fat` 8. View daily sugar consumed: `sugar` 9. View daily fiber consumed: `fiber` 10. View daily water consumption: `water` -11. View daily calories consumed: `caloriesBurnt` +11. View daily calories burnt: `caloriesBurnt` 12. View daily calories and water intake recommendation, based on current intake: `recommend` - + ### 4 For users to view their lists and data 1. List today's meal intakes: `listMeals` 2. List today's drink intake: `listDrinks` @@ -60,13 +64,16 @@ high/medium/low intensity workout defined per minute and can be inputted immedia ### 5 For users to edit existing data 1. Edit the serving size of a meal that was inputted in the day: `editMeal` -2. Edit the serving size of a drink that was inputted in the day: `editDrink` +2. Edit the volume of a drink that was inputted in the day: `editDrink` 3. Edit total water intake of the day: `editWater` ### 6 For users to delete existing data 1. Delete a meal entry: `deleteMeal` 2. Delete a drink entry: `deleteDrink` -3. Clear all entries of meals, drinks and exercise: `clear` -*** +3. Delete an exercise entry: `deleteExercise` + +### 7 For users to clear all data +1. Clear all entries of meals, drinks and exercise: `clear` +--- ## Exit the program -Close the appplication: `exit` +Close the application and save all the changes made: `exit` diff --git a/docs/README.md b/docs/README.md index fd6ea6b7e5..941d42821a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,7 +10,11 @@ To use the app please follow the setup procedures below: 1. Download the JAR file. 2. Place it into an empty folder. 3. Navigate to the folder you just created. -4. Run the JAR file. +4. Run the JAR file with the following command: +``` +-$ java -jar FitNUS.jar +``` + *** ## Features List ### 1 Information for users @@ -23,9 +27,9 @@ and can be inputted immediately: `allDrinks` high/medium/low intensity workout defined per minute and can be inputted immediately: `allExercises` ### 2 For user to add data -1. Adds a meal to the list of meals eaten today: `eat` -2. Add a drink list of drinks drank today: `drink` -3. Add exercise to the list of exercises done : `exercise` +1. Adds a meal to the list of meals consumed today: `eat` +2. Add a drink to the list of drinks consumed today: `drink` +3. Add an exercise to the list of exercises done: `exercise` 4. Add a custom new meal on top of pre-defined meals: `newMeal` 5. Add a custom new drink on top of pre-defined drink: `newDrink` 6. Add a custom new exercise on top of pre-defined exercises: `newExercise` @@ -34,14 +38,14 @@ high/medium/low intensity workout defined per minute and can be inputted immedia 1. Find nutritional content about a certain meal: `infoMeal` 2. Find nutritional content about a certain drink: `infoDrink` 3. Find the calories burnt per minute from a certain exercise: `infoExercise` -4. View daily calories consumed: `calories` +4. View daily net calorie count: `calories` 5. View daily carbohydrates consumed: `carbs` 6. View daily proteins consumed: `protein` 7. View daily fat consumed: `fat` 8. View daily sugar consumed: `sugar` 9. View daily fiber consumed: `fiber` 10. View daily water consumption: `water` -11. View daily calories consumed: `caloriesBurnt` +11. View daily calories burnt: `caloriesBurnt` 12. View daily calories and water intake recommendation, based on current intake: `recommend` ### 4 For users to view their lists and data @@ -60,14 +64,16 @@ high/medium/low intensity workout defined per minute and can be inputted immedia ### 5 For users to edit existing data 1. Edit the serving size of a meal that was inputted in the day: `editMeal` -2. Edit the serving size of a drink that was inputted in the day: `editDrink` +2. Edit the volume of a drink that was inputted in the day: `editDrink` 3. Edit total water intake of the day: `editWater` ### 6 For users to delete existing data 1. Delete a meal entry: `deleteMeal` 2. Delete a drink entry: `deleteDrink` 3. Delete an exercise entry: `deleteExercise` -4. Clear all entries of meals, drinks and exercise: `clear` + +### 7 For users to clear all data +1. Clear all entries of meals, drinks and exercise: `clear` *** ## Exit the program Close the application and save all the changes made: `exit` diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 85af9cb90d..64325542a1 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -397,7 +397,7 @@ Display current total water intake **in ml** for the day. Total water intake today: 0 ml ~~~ -### 2.3.11 View daily calories consumed: `caloriesBurnt` +### 2.3.11 View daily calories burnt: `caloriesBurnt` Display current total calorie burnt **in kcal** for the day. **Format**: `caloriesBurnt` @@ -628,7 +628,7 @@ Total water intake has been edited to 200 ml ~~~ ## 2.6 For deleting data -### 2.6.1 Delete certain meal entry: `deleteMeal` +### 2.6.1 Delete a certain meal entry: `deleteMeal` Delete a meal that was inputted today. You may identify the meal by its index in listMeals. **Format**: `deleteMeal INDEX` @@ -638,7 +638,7 @@ Delete a meal that was inputted today. You may identify the meal by its index in Removed chicken rice from meals ~~~ -### 2.6.2 Delete certain drink entry: `deleteDrink` +### 2.6.2 Delete a certain drink entry: `deleteDrink` Delete a drink that was inputted today. You may identify the drink by its index in listDrinks. **Format**: `deleteDrink INDEX` @@ -648,6 +648,16 @@ Delete a drink that was inputted today. You may identify the drink by its index Removed iced lemon tea from drinks ~~~ +### 2.6.3 Delete a certain exercise entry: `deleteExercise` +Delete an exercise that was inputted today. You may identify the exercise by its index in listExercises. + +**Format**: `deleteExercise INDEX` +**Sample input**: `deleteExercise 1` +**Expected output:** +~~~ +Removed swimming from exercises done +~~~ + ## 2.7 For clearing data ### 2.7.1 Clear all entries: `clear` Clear all entries that was added to mealList, drinkList and exerciseList **today**. From d8b2d798ac448d81c9d4a1154116d58ca77b3451 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 06:14:08 +0800 Subject: [PATCH 242/274] Update UG and README based on deployment bugs --- README.md | 1 + docs/README.md | 11 ++++++++--- docs/UserGuide.md | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 746ddb54e0..94af4c47fe 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ FitNUS is a CLI application that aims to help combat diabetes and the overconsum carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even past records. + --- ## Setup To use the app please follow the setup procedures below: diff --git a/docs/README.md b/docs/README.md index 941d42821a..cd796bc448 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,9 @@ FitNUS is a CLI application that aims to help combat diabetes and the overconsum carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even past records. -*** + +--- + ## Setup To use the app please follow the setup procedures below: 1. Download the JAR file. @@ -15,7 +17,8 @@ To use the app please follow the setup procedures below: -$ java -jar FitNUS.jar ``` -*** +--- + ## Features List ### 1 Information for users 1. View all possible commands: `help` @@ -74,6 +77,8 @@ high/medium/low intensity workout defined per minute and can be inputted immedia ### 7 For users to clear all data 1. Clear all entries of meals, drinks and exercise: `clear` -*** + +--- + ## Exit the program Close the application and save all the changes made: `exit` diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 64325542a1..ab9d2a5b95 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -11,7 +11,7 @@ Users are able to track the meals, drinks, and exercises they have in a day and ## Table of Contents -* [1) Setup](#1-setup-) +* [1) Setup](#1-setup) * [2) Features List](#2-features-list) * [2.1 Information for users](#21-information-for-users) * [2.2 For user to add data](#22-for-user-to-add-data) @@ -679,6 +679,7 @@ Safely close the application. Don't worry, all your inputs will be saved while y Bye. Hope to see you again soon! ~~~ --- + ## 3) FAQ **Q**: How do I save changes made in the app? From 67731912bf6ef345c310ed5bd973c2ba835e986d Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 15 Apr 2024 16:43:35 +0800 Subject: [PATCH 243/274] Update DG --- docs/DeveloperGuide.md | 124 +++++++++++++++++- docs/diagrams/InfoMealSequenceDiagram.puml | 34 +++-- .../diagrams_png/InfoMealSequenceDiagram.png | Bin 22036 -> 22281 bytes 3 files changed, 138 insertions(+), 20 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 12d1e5517d..5913114c49 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,12 +1,41 @@ + + # Developer Guide +--- + +## Table of Contents + +* [Acknowledgements](#acknowledgements) +* [Design](#design) + * [Architecture](#architecture) + * [Ui Component](#ui-component) + * [Storage Component](#storage-component) + * [User Component](#user-component) + * [Exercise Component](#exercise-component) + * [Drink Component](#drink-component) + * [Meal Component](#meal-component) +* [Implementation](#implementation) + * [Information on a Particular Meal Command](#information-on-a-particular-meal-command) + * [Eat Command](#eat-command) + * [Edit Meal Command](#edit-meal-command) + * [New Meal Command](#new-meal-command) +* [Product Scope](#product-scope) +* [User Stories](#user-stories) +* [Non-Functional Requirements](#non-functional-requirements) +* [Instructions for Manual Testing](#instructions-for-manual-testing) + + +--- + ## Acknowledgements Below are the references used on the project: 1. [Developer Guide](https://se-education.org/addressbook-level3/DeveloperGuide.html) 2. [User Guide](https://se-education.org/addressbook-level3/UserGuide.html) -## Design & implementation +--- +## Design ### Architecture @@ -133,14 +162,22 @@ User class initialises MealList, DrinkList and ExerciseList for the user to trac 1. Upon starting up the application, User will call `loadMeal` to fetch all data from `Mealist.txt` and add it into `mealListAll`. 2. A `User` class consists of zero to as many `Meal` objects in the ArrayList. + +--- ## Implementation -### Information on a Particular Meal Feature -The `infoMeal` feature is executed on the `User` class. Let's say we want to find out about the nutrient values of chicken rice. -**Sample Input**: `infoMeal chicken rice` +### Information on a Particular Meal Command +The `infoMeal` command allows user to obtain the nutritional values (protein, calories, carbs, etc.) of a particular +meal. The following sequence diagram shows the execution of the `infoMeal` command ![InfoMeal Sequence Diagram](../docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png) +1. The user inputs an `infoMeal` command of the format `infoMeal m/MEAL` in this example we use `infoMeal m/ chicken rice` which is inputted to the `ui` object +2. The `ui` object calls the `parseCommand()` method of the `parser` object +3. The parser parses the command and calls the appropriate method, which in this case is `handleInfoMeal()` of `Meal` class +4. The `Meal` class then calls the `parseInfoMeal` method to retrieve the meal name from the command +5. After obtaining the name of the meal from `parser` object, the `Meal` class will print out the nutrient details of that particular meal. + ### Eat Command The `eat` command is responsible for handling the tracking of meal and adding it to the Meal List. The following sequence diagram shows the execution of the `eat` command. @@ -190,6 +227,7 @@ The following sequence diagram shows the execution of the `newMeal` command. Note: The implementation for `newDrink` and `newExercise` command have similar sequence diagrams +--- ## Product scope ### Target user profile - Have a need to manage their dietary intake and exercise routines effectively. @@ -202,6 +240,7 @@ Note: The implementation for `newDrink` and `newExercise` command have similar s The fitness app aims to help users manage their dietary habits and exercise routines more efficiently compared to traditional GUI-driven apps. By offering a streamlined interface optimized for keyboard input and CLI interactions, users can track their meals, drinks, and exercises swiftly, allowing them to focus more on their fitness and nutritional goals and less on navigating through complex user interfaces. +--- ## User Stories | Version | As a ... | I want to ... | So that I can ... | @@ -228,11 +267,13 @@ By offering a streamlined interface optimized for keyboard input and CLI interac | v2.0 | user | add a new exercise to the available drinks | add exercises that the app did not recognize | | v2.0 | user | store and load all the meals and drinks I have consumed and also the exercises I have done throughout the entire lifecycle of the app | view all of the existing data even after I close the app | | v2.0 | user | view all the meals and drinks I have consumed and also the exercises I have done throughtout the entire lifecycle of the app | keep a record of my exercises, macronutrients and calories I have done and consumed for a week, a month, or even more | + ## Non-Functional Requirements 1. Should work on any mainstream OS (Linux, Windows, MacOS) as long as it has Java 11 or above installed. 2. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. +--- ## Glossary * *meal* - Any food consumed. @@ -246,8 +287,8 @@ By offering a streamlined interface optimized for keyboard input and CLI interac * *fiber* - Indigestible plant material aiding digestion. * *water* - Essential liquid for hydration and bodily functions. - -## Instructions for manual testing +--- +## Instructions for Manual Testing Given below are instructions to test the app on your own device. ### Launch and Shutdown 1. Initial Launch @@ -260,3 +301,74 @@ Given below are instructions to test the app on your own device. 4. Save and Shutdown 1. Type `exit` to shut down the FitNUS app. 2. Upon exiting, all entries inputted will be updated to the database locally. + +### Basic Features +Given below are the basic features of our FitNUS, do note that it's not the complete list of commands. +Please refer to our User Guide for the full list of our features. + +#### Add a meal eaten: `eat` +Adds a meal to the list of meals consumed today. + +**Format**: `eat m/MEAL s/SERVING_SIZE` +**Sample Input**: `eat m/Chicken Rice s/1` +**Expected Output**: +~~~ +Added 1 serving of chicken rice +~~~ + +#### Find the information about a certain meal: `infoMeal` +For the specified meal, display its nutritional content **per serving** to the user. + +**Format**: `infoMeal MEAL` +**Sample Input**: `infoMeal chicken rice` +**Expected Output**: +~~~ +Meal: chicken rice (per serving) +Calories: 400 kcal +Carbs: 50 g +Protein: 30 g +Fat: 20 g +Fiber: 10 g +Sugar: 5 g +~~~ + +#### View daily net calorie count: `calories` +Display current net calorie count **in kcal** for the day. This takes into account the calories consumed from meals +and drinks, +and the calories burnt from exercise. + +**Format**: `calories` +**Expected output**: +~~~ +Total Calories: 230 kcal +~~~ + +#### List today's meal intake: `listMeals` +Display all the meals the user has inputted today. + +**Format**: `listMeals` +**Expected output**: +~~~ +here's what you have eaten today +1. chicken rice (serving size: 1) | date: 01-04-2024 +~~~ + +#### Delete a certain meal entry: `deleteMeal` +Delete a meal that was inputted today. You may identify the meal by its index in listMeals. + +**Format**: `deleteMeal INDEX` +**Sample Input**: `deleteMeal 1` +**Expected output**: +~~~ +Removed chicken rice from meals +~~~ + +#### Edit an existing meal after inserted: `editMeal` +For a meal that was inputted in the day, edit its serving size. You may identify the meal by its index in listMeals. + +**Format**: `editMeal INDEX s/NEW_SERVING_SIZE` +**Sample input**: `editMeal 2 s/10` +**Expected output**: +~~~ +chicken rice has been edited to 10 serving(s) +~~~ \ No newline at end of file diff --git a/docs/diagrams/InfoMealSequenceDiagram.puml b/docs/diagrams/InfoMealSequenceDiagram.puml index 9efe726cb3..81e77157dc 100644 --- a/docs/diagrams/InfoMealSequenceDiagram.puml +++ b/docs/diagrams/InfoMealSequenceDiagram.puml @@ -2,28 +2,34 @@ !include Style.puml skinparam ArrowFontStyle plain +skinparam participant { + BackgroundColor #F5F0FF + BorderColor black + FontColor black +} + actor User -participant ":Ui" as Ui MAIN_COLOR -participant ":Parser" as Parser PARSER_COLOR -participant "<>\nMeal" as Meal INTERFACE_COLOR +participant ":ui" as ui +participant ":parser" as parser +participant "<>\nMeal" as Meal -User-> Ui : input: infoMeal chicken rice -activate Ui +User-> ui : input: infoMeal chicken rice +activate ui -Ui -> Parser : handleCommand("infoMeal chicken rice") -activate Parser +ui -> parser : parseCommand("infoMeal chicken rice") +activate parser -Parser -> Meal : handleInfoMeal("infoMeal chicken rice") +parser -> Meal : handleInfoMeal("infoMeal chicken rice") activate Meal -Meal --> Parser : parseInfoMeal("infoMeal chicken rice") -Parser -> Meal : return name -deactivate Parser +Meal --> parser : parseInfoMeal("infoMeal chicken rice") +parser -> Meal : return name +deactivate parser -Meal -> Meal : printNutrientDetails(name) -Meal --> Ui +Meal -> Meal : print the nutrient details of the meal based on its name +Meal --> ui deactivate Meal -Ui --> User +ui --> User @enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png b/docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png index 3b34fd8f59b39483fdda0eff74cb85f5ac54afdf..35108dcaf186766197c26191d3fd9ce07c61d28a 100644 GIT binary patch literal 22281 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 literal 22036 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 oy$GKIzXu=xt|cK!# Date: Mon, 15 Apr 2024 16:51:59 +0800 Subject: [PATCH 244/274] Add PPP and delete meal command to DG --- docs/DeveloperGuide.md | 15 ++++++++--- docs/team/jasonlienardi.md | 25 +++++++++++++++---- src/main/java/seedu/fitnus/meal/MealList.java | 2 +- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 12d1e5517d..8f760dd15e 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -149,7 +149,7 @@ The following sequence diagram shows the execution of the `eat` command. 1. The user inputs an `eat` command of the format `eat m/MEAL s/SERVING_SIZE` into the `ui` object 2. The `ui` object calls the `parseCommand()` method of the `parser` object -3. The parser parses the command and calls the appropriate method, which in this case is `handleMeal()` of `MealList` +3. The parser parses the command and calls the appropriate method, which in this case is `handleMeal()` method of `MealList` 4. The `MealList` object then calls the `parseMeal` method to retrieve the information from the command such as the meal name and serving size 5. With the meal details retrieved from the parser, a new `Meal` object with the given parameters (meal name, serving size) is created and returned to `MealList` 6. When creating a new `Meal` object, it will call its own method `setNutrientDetails()` to set the nutrients for that specific meal using the meal name @@ -166,7 +166,7 @@ The following sequence diagram shows the execution of the `editMeal` command. 1. The user inputs an `editMeal` command of the format `editMeal INDEX s/NEW_SERVING_SIZE` into the `ui` object 2. The `ui` object calls the `parseCommand()` method of the `parser` object -3. The parser parses the command and calls the appropriate method, which in this case is `handleEditMealServingSize()` of `MealList` +3. The parser parses the command and calls the appropriate method, which in this case is `handleEditMealServingSize()` method of `MealList` 4. The `MealList` object then calls the `parseEditMeal` method to retrieve the information from the command such as the intended meal index and current serving size 5. With the meal name and current serving size retrieved, the `Meallist` objects retrieves the name and nutrient details of the meal by calling the `getName()` and `getData()` methods of the `Meal` object 6. A new `Meal` object with the updated serving size is created and returned to `MealList` @@ -183,13 +183,22 @@ The following sequence diagram shows the execution of the `newMeal` command. 1. The user inputs an `newMeal` command of the format `newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR` into the `ui` object 2. The `ui` object calls the `parseCommand()` method of the `parser` object -3. The parser parses the command and calls the appropriate method, which in this case is `handleAddNewMealNutrient()` of `MealList` +3. The parser parses the command and calls the appropriate method, which in this case is `handleAddNewMealNutrient()` method of `MealList` 4. The `MealList` object then calls the `parseNewMeal` method to retrieve the information from the command such as the mean name, calories, carbs, protein, fat, fiber and sugar 5. The Nutrient of the details are then stored in the `nutrientDetails` hashmap attribute of the `Meals` class using the `put()` method of the hashmap 6. Upon successful tracking of a meal a confirmation message is printed Note: The implementation for `newDrink` and `newExercise` command have similar sequence diagrams +### Delete Meal Command +The `deleteMeal` command allows users to delete a meal from the list of meals they have consumed today by specifying the meals index in accordance with the `listMeals` command. +1. The user inputs an `deleteMeal` command of the format `deleteMeal INDEX` into the `ui` object +2. The `ui` object calls the `parseCommand()` method of the `parser` object +3. The parser parses the command and calls the appropriate method, which in this case is `handleDeleteMeal()` method of `MealList` +4. The `MealList` object then calls the `parseDeleteMeal` method to retrieve the information from the command, which is the index of the meal to be deleted. +5. The meal is then removed by calling the `remove()` method of `MealList` and passing the index of the specified meal as a parameter +6. Upon successful deletion of a meal a confirmation message is printed + ## Product scope ### Target user profile - Have a need to manage their dietary intake and exercise routines effectively. diff --git a/docs/team/jasonlienardi.md b/docs/team/jasonlienardi.md index 63a0683abe..c2eb9c85cd 100644 --- a/docs/team/jasonlienardi.md +++ b/docs/team/jasonlienardi.md @@ -3,8 +3,23 @@ FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. -Given below are my contributioins to the project. -* New Feature: added a newMeal command which allows users to store the nutrient details of their favorite meals in the app. -* New Feature: added a newDrink command which allows users to store the nutrient details of their favorite drinks in the app. -* New Feature: added a newExercise command which allows users to store the details regarding the calories burnt for a certian exercise. -* Code contributed: https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23 +Given below are my contributions to the project. +* **New Feature**: created FitNUS which is the entry point of the app +* **New Feature**: created Meal class and MealList class +* **New Feature**: created Exercise class, ExerciseIntensity enumeration and ExerciseList class +* **New Feature**: added a newMeal command which allows users to store the nutrient details of their favorite meals in the app. The new meal will be added to the available meals csv to allow users to track the meal in the future +* **New Feature**: added a newDrink command which allows users to store the nutrient details of their favorite drinks in the app. The new drink will be added to the available drinks csv to allow users to track the drink in the future +* **New Feature**: added a newExercise command which allows users to store the details regarding the calories burnt for a certian exercise. The new exercise will be added to the available exercises csv to allow users to track the exercise in the future +* **Project Management**: + * Assigned issues to teammates + * Wrapped up milestones `v1.0` and `v2.0` +* **Enhancements to existing features**: + * Updated exception handling to give more specific edge cases (ie. negative value exception for meal/drink nutrient and exercise calories and non-positive value exception for meal/drink serving size and exercise duration) [#139](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/139) +* **Code contributed**: [RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23) +* **Documentation**: + * User Guide: + * Added documentation for features `eat`, `drink`, `water`, `exercise`, `infoMeal`, `infoDrink`, `infoExercise`, `calories`, `carbs`, `protein`, `fat`, `sugar`, `fiber`, `viewWater`, `caloriesBurnt`, `listMeals`, `listDrinks`, `listExercises`, `listEverything`, `listMealsAll`, `listDrinksAll`, `listExercisesAll`, `listEverythingAll` [#63](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/63/files#diff-1a95edf069a4136e9cb71bee758b0dc86996f6051f0d438ec2c424557de7160b) + * Developer Guide: + * Added implementation details for `eat`, `editMeal`, `newMeal`, and `deleteMeal` feature. As well sequence diagrams for `eat`, `editMeal` and `newMeal` commands. [#151](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/151/files) +* **Community**: + * PR Reviews: [#44](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/44), [#61](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/61), [#84](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/84), [#155](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/155) \ No newline at end of file diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index 16da70d6b0..baa9ab13d1 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -185,7 +185,7 @@ public static void handleDeleteMeal(String command) throws InvalidListIndexExcep } String mealName = mealList.get(mealIndex).getName(); - mealList.remove(mealIndex); + deleteMeal INDEX; System.out.println("Removed " + mealName + " from meals"); } From 484da5f34f0a35bab9e150e0be660cf41f18b856 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 15 Apr 2024 17:31:28 +0800 Subject: [PATCH 245/274] Update PPP and ReadMe --- docs/AboutUs.md | 4 +- docs/README.md | 4 ++ docs/team/jasonlienardi.md | 55 ++++++++++++------- src/main/java/seedu/fitnus/meal/MealList.java | 2 +- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0c721bbd34..a41ed85120 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -3,6 +3,6 @@ Display | Name | Github Profile | Portfolio --------|:---------------------:|:-------------------------------------------:|:---------: ![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](docs/team/edwardhumi.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](docs/team/johndoe.md) --- | Claribel Ho | [Github] (https://github.com/claribelho) | [Portfolio] (docs/team/claribelho.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](docs/team/jasonlienardi.md) +-- | Claribel Ho | [Github](https://github.com/claribelho) | [Portfolio](docs/team/claribelho.md) ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Castorius Halim | [Github](https://github.com/BryanCastorius) | [Portfolio](docs/team/bryancastorius.md) \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index cd796bc448..790f520cfe 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,6 +5,10 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even past records. +Useful links: +* [User Guide](UserGuide.md) +* [Developer Guide](DeveloperGuide.md) +* [About Us](AboutUs.md) --- ## Setup diff --git a/docs/team/jasonlienardi.md b/docs/team/jasonlienardi.md index c2eb9c85cd..a0798302bd 100644 --- a/docs/team/jasonlienardi.md +++ b/docs/team/jasonlienardi.md @@ -1,25 +1,40 @@ # Jason Lienardi's Project Portfolio Page +## Project: FitNUS + +### Overview FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. -Given below are my contributions to the project. -* **New Feature**: created FitNUS which is the entry point of the app -* **New Feature**: created Meal class and MealList class -* **New Feature**: created Exercise class, ExerciseIntensity enumeration and ExerciseList class -* **New Feature**: added a newMeal command which allows users to store the nutrient details of their favorite meals in the app. The new meal will be added to the available meals csv to allow users to track the meal in the future -* **New Feature**: added a newDrink command which allows users to store the nutrient details of their favorite drinks in the app. The new drink will be added to the available drinks csv to allow users to track the drink in the future -* **New Feature**: added a newExercise command which allows users to store the details regarding the calories burnt for a certian exercise. The new exercise will be added to the available exercises csv to allow users to track the exercise in the future -* **Project Management**: - * Assigned issues to teammates - * Wrapped up milestones `v1.0` and `v2.0` -* **Enhancements to existing features**: - * Updated exception handling to give more specific edge cases (ie. negative value exception for meal/drink nutrient and exercise calories and non-positive value exception for meal/drink serving size and exercise duration) [#139](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/139) -* **Code contributed**: [RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23) -* **Documentation**: - * User Guide: - * Added documentation for features `eat`, `drink`, `water`, `exercise`, `infoMeal`, `infoDrink`, `infoExercise`, `calories`, `carbs`, `protein`, `fat`, `sugar`, `fiber`, `viewWater`, `caloriesBurnt`, `listMeals`, `listDrinks`, `listExercises`, `listEverything`, `listMealsAll`, `listDrinksAll`, `listExercisesAll`, `listEverythingAll` [#63](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/63/files#diff-1a95edf069a4136e9cb71bee758b0dc86996f6051f0d438ec2c424557de7160b) - * Developer Guide: - * Added implementation details for `eat`, `editMeal`, `newMeal`, and `deleteMeal` feature. As well sequence diagrams for `eat`, `editMeal` and `newMeal` commands. [#151](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/151/files) -* **Community**: - * PR Reviews: [#44](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/44), [#61](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/61), [#84](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/84), [#155](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/155) \ No newline at end of file +### Summary of Contributions + +#### Code contributed: [RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23) + +#### Features implemented +- Created FitNUS which is the entry point of the app +- Created Meal class and MealList class +- Created Exercise class, ExerciseIntensity enumeration and ExerciseList class +- Added a newMeal command which allows users to store the nutrient details of their favorite meals in the app. The new meal will be added to the available meals csv to allow users to track the meal in the future +- Added a newDrink command which allows users to store the nutrient details of their favorite drinks in the app. The new drink will be added to the available drinks csv to allow users to track the drink in the future +- Added a newExercise command which allows users to store the details regarding the calories burnt for a certian exercise. The new exercise will be added to the available exercises csv to allow users to track the exercise in the future + +#### Enhancements implemented +- Updated exception handling to give more specific edge cases (ie. negative value exception for meal/drink nutrient and exercise calories and non-positive value exception for meal/drink serving size and exercise duration) [#139](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/139) + +#### Project Management +- Wrapped up milestones `v1.0`, `v2.0` and `v2.1` + +#### Contributions to User Guide +- Added documentation for features `eat`, `drink`, `water`, `exercise`, `infoMeal`, `infoDrink`, `infoExercise`, `calories`, `carbs`, `protein`, `fat`, `sugar`, `fiber`, `viewWater`, `caloriesBurnt`, `listMeals`, `listDrinks`, `listExercises`, `listEverything`, `listMealsAll`, `listDrinksAll`, `listExercisesAll`, `listEverythingAll`. Complete with command description, format, sample input and expected output. [#63](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/63/files#diff-1a95edf069a4136e9cb71bee758b0dc86996f6051f0d438ec2c424557de7160b) + +#### Contributions to Developer Guide +- Added implementation details for `eat`, `editMeal`, `newMeal`, and `deleteMeal` feature. As well sequence diagrams for `eat`, `editMeal` and `newMeal` commands. [#151](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/151/files) + +#### Contributions to team-based tasks +- Managed GitHub issues +- Assigned issues to team members +- Linked PR and Issues to Milestones +- Clean-up formatting of DG and UG + +#### Review or Mentoring Contributions +- PR Reviews: [#44](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/44), [#61](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/61), [#84](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/84), [#155](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/155) \ No newline at end of file diff --git a/src/main/java/seedu/fitnus/meal/MealList.java b/src/main/java/seedu/fitnus/meal/MealList.java index baa9ab13d1..16da70d6b0 100644 --- a/src/main/java/seedu/fitnus/meal/MealList.java +++ b/src/main/java/seedu/fitnus/meal/MealList.java @@ -185,7 +185,7 @@ public static void handleDeleteMeal(String command) throws InvalidListIndexExcep } String mealName = mealList.get(mealIndex).getName(); - deleteMeal INDEX; + mealList.remove(mealIndex); System.out.println("Removed " + mealName + " from meals"); } From 18a66202505e5333c8418b7022c063bbcdb6f080 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 15 Apr 2024 17:41:37 +0800 Subject: [PATCH 246/274] Fix aboutus --- docs/AboutUs.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index a41ed85120..271b988f03 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -2,7 +2,7 @@ Display | Name | Github Profile | Portfolio --------|:---------------------:|:-------------------------------------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](docs/team/edwardhumi.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](docs/team/jasonlienardi.md) --- | Claribel Ho | [Github](https://github.com/claribelho) | [Portfolio](docs/team/claribelho.md) -![](https://via.placeholder.com/100.png?text=Photo) | Bryan Castorius Halim | [Github](https://github.com/BryanCastorius) | [Portfolio](docs/team/bryancastorius.md) \ No newline at end of file +![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](team/edwardhumi.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](team/jasonlienardi.md) +-- | Claribel Ho | [Github](https://github.com/claribelho) | [Portfolio](team/claribelho.md) +![](https://via.placeholder.com/100.png?text=Photo) | Bryan Castorius Halim | [Github](https://github.com/BryanCastorius) | [Portfolio](team/bryancastorius.md) \ No newline at end of file From a09c842b9875a00543f2acc4538daeb8cb3b0a05 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 15 Apr 2024 18:30:08 +0800 Subject: [PATCH 247/274] Update PPP --- docs/team/bryancastorius.md | 50 ++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/docs/team/bryancastorius.md b/docs/team/bryancastorius.md index 30ad788668..69bc422ca6 100644 --- a/docs/team/bryancastorius.md +++ b/docs/team/bryancastorius.md @@ -3,14 +3,46 @@ FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. +--- Given below are my contributions to the project. -* Code contributed: [Individual Reposense](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=w14&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23) -* Feature: Drink and Water Class - * Methods to handle inserting water and drink volume and viewing the intakes. -* Feature: Recommendations + +### Code Contributed: +Click on the following link: [Individual Reposense](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=w14&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23) +### Features Implemented: +#### Drink and Water Class + * Methods to handle inserting water and drink volume + * Methods to edit the water volume intake + * Methods to obtain the nutritional value for each drink object + * Reorganize Drink and Water Class into part of DrinkList class +#### Recommendations * Method to provide the recommended amount of water and calories intake. -* Add Developer Guide - * Architecture diagrams - * Class diagrams - * Object diagrams - * Sequence diagrams \ No newline at end of file + +### Enhancements Implemented + +#### Drink and Water Class + * Create various exceptions for handling invalid insertion to the drink command (e.g. UnregisteredDrinkException, InvalidEditWaterException) + * Making sure that only one object of water can be created per day will only add volume to the existing water object if it is still the same day + * Added javadoc documentation inside the Drink and Water class and also other class methods that relates to Drink and Water class + +#### Parser Class + * Update the help command output message + * Catch exceptions relating to Water and Drink Class + * Methods to parse the load and store Exercise command made from current session into ExerciseList.txt + +### Contributions to Developer Guide + * Added User Stories + * Added Table of Content + * Added Instructions for Manual Testing including basic features + * Added class diagrams for Meal, Drink, Exercise components and their explanation + * Added architecture diagram and its explanation + * Added InfoMeal sequence diagram and its explanation + +### Contributions to User Guide + * Added FAQs + * Update Table of Content + * Added explanations, sample inputs and outputs for features relating to adding data and data retrieval + +### Project Management + * Added issues for milestone `v1.0`, `v2.0`, and `v2.1` + * Solve and debug issues relating to Drink and Water feature from PE dry run + * Merge and resolve conflicts from other peers' pull requests \ No newline at end of file From 8f77ac84adb777dd8939465396f2c4c0ab6a6fa2 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 15 Apr 2024 18:51:37 +0800 Subject: [PATCH 248/274] update Readme --- README.md | 5 +++++ docs/README.md | 1 + 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 94af4c47fe..faa886b27b 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. Users are able to track the meals, drinks, and exercises they have in a day and even past records. +Useful links: +* [User Guide](docs/UserGuide.md) +* [Developer Guide](docs/DeveloperGuide.md) +* [About Us](docs/AboutUs.md) + --- ## Setup To use the app please follow the setup procedures below: diff --git a/docs/README.md b/docs/README.md index 790f520cfe..e25acefa0b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,6 +9,7 @@ Useful links: * [User Guide](UserGuide.md) * [Developer Guide](DeveloperGuide.md) * [About Us](AboutUs.md) + --- ## Setup From 5b353636b404c85aab3bf2c25a4d15e7824294ed Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 15 Apr 2024 19:03:44 +0800 Subject: [PATCH 249/274] update reposense link --- docs/team/jasonlienardi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/team/jasonlienardi.md b/docs/team/jasonlienardi.md index a0798302bd..36488ec9d8 100644 --- a/docs/team/jasonlienardi.md +++ b/docs/team/jasonlienardi.md @@ -8,7 +8,7 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. ### Summary of Contributions -#### Code contributed: [RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23) +#### Code contributed: [RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=jasonlienardi&tabRepo=AY2324S2-CS2113-W14-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false) #### Features implemented - Created FitNUS which is the entry point of the app From 3b934073fec695b76f6b1101fab3de6665a6bb43 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 19:04:07 +0800 Subject: [PATCH 250/274] Update PPP --- docs/team/claribelho.md | 59 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/docs/team/claribelho.md b/docs/team/claribelho.md index 2f78cfd3ff..b31eae6579 100644 --- a/docs/team/claribelho.md +++ b/docs/team/claribelho.md @@ -1,11 +1,56 @@ # Claribel Ho Jia Huan's Project Portfolio Page - +## FitNUS FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. -Given below are my contributions to the project: -* Code Contribution: [Individual Reposense](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=w14&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=claribelho&tabRepo=AY2324S2-CS2113-W14-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false) -* Feature: User Class - * Methods to handle View, List and Add commands -* Feature: Date Class - * Gets System Date and Time for use when storing data +## Summary of Contributions +Given below are my contributions to the project +### Code Contribution +* [Individual Reposense](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=w14&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=claribelho&tabRepo=AY2324S2-CS2113-W14-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false) + +### Features implemented +1. **User** Class: [#10](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/10) + 1. Create methods to handle view and clear inputs. + 2. Additionally, due to reorganisation of methods in v2.1, the following methods originally created in the User Class were moved: + * _MealList Class_ - adding, editing and deleting a meal and viewing of the meal list. + * _DrinkList Class_ - editing and deleting a drink. + * _Meal, Drink and Exercise Class_ - view all pre-defined meals, drinks and exercises. + + +2. **Date** Class: [#48](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/48/files#diff-e9bbd74038a5477b04128de17dc3a668137bf26b605b96c981c1bc8d24963e3a) + 1. Uses java.sql.Date to obtain the user's local machine date and time. + 2. This is used + for storage organisation of user's past and present inputs. + + +3. **DateValidation** and **IntegerValidation** Classes: [#137](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/137) + [#51](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/51) + 1. These classes are responsible for verifying the + validity of dates and integers, else the methods will throw an exception to the user. + +### Enhancements implemented +* Extensive Code Defense through testing to find bugs. Made use of exceptions and assertions to catch errors. +[#51](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/51) +[#80](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/80) +[#153](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/153) +* Improve checks when Parsing user input to detect for user misuse. +* Improve checks when loading saved data in Storage to detect for user manipulation. + +### Contributions to User Guide +- Created User Guide in v1.0, including the description, format, sample input and expected output for each command. +[#35](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/35) +- Add documentation for `allmeals`, `allDrinks` and `allExercises`. [#76](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/76) +- Finalisation of descriptions and formatting in final v2.1 submission. [#153](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/153) + +### Contributions to Developer Guide +- Added Sequence Diagrams for Ui, Storage and User components. +- Provide descriptions for User component + +### Contributions to team-based tasks +- Constantly improving the defensiveness of the code by finding bugs +- Create User Guide and ensure it is formatted and up-to-date +- Documentation of Methods +- Update of README to provide a summary of UG + +### Contributions beyond the project team +- Bugs Review for other teams: [CS2113-T15-1](https://github.com/nus-cs2113-AY2324S2/tp/pull/44) From 9ec1cfadb51d578bb04643463e2f777711bb7a27 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 15 Apr 2024 19:08:39 +0800 Subject: [PATCH 251/274] Add photo --- docs/AboutUs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 271b988f03..a53c48cafe 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -3,6 +3,6 @@ Display | Name | Github Profile | Portfolio --------|:---------------------:|:-------------------------------------------:|:---------: ![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](team/edwardhumi.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](team/jasonlienardi.md) +![](https://media.licdn.com/dms/image/D5603AQEY7Y8ciM41dA/profile-displayphoto-shrink_200_200/0/1695090380983?e=2147483647&v=beta&t=DtL_wRVaskMUARWJcocKkV1B4UmAXVyAI-DJ_4e9Ge4o) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](team/jasonlienardi.md) -- | Claribel Ho | [Github](https://github.com/claribelho) | [Portfolio](team/claribelho.md) ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Castorius Halim | [Github](https://github.com/BryanCastorius) | [Portfolio](team/bryancastorius.md) \ No newline at end of file From 5bbb0e08459590221e4166817dfd9a9c259954b1 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 15 Apr 2024 19:12:27 +0800 Subject: [PATCH 252/274] Update about us --- docs/AboutUs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index a53c48cafe..57ecefbf83 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -3,6 +3,6 @@ Display | Name | Github Profile | Portfolio --------|:---------------------:|:-------------------------------------------:|:---------: ![](https://via.placeholder.com/100.png?text=Photo) | Edward Humianto | [Github](https://github.com/edwardhumi) | [Portfolio](team/edwardhumi.md) -![](https://media.licdn.com/dms/image/D5603AQEY7Y8ciM41dA/profile-displayphoto-shrink_200_200/0/1695090380983?e=2147483647&v=beta&t=DtL_wRVaskMUARWJcocKkV1B4UmAXVyAI-DJ_4e9Ge4o) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](team/jasonlienardi.md) --- | Claribel Ho | [Github](https://github.com/claribelho) | [Portfolio](team/claribelho.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jason Lienardi | [Github](https://github.com/jasonlienardi) | [Portfolio](team/jasonlienardi.md) +![](https://via.placeholder.com/100.png?text=Photo) | Claribel Ho | [Github](https://github.com/claribelho) | [Portfolio](team/claribelho.md) ![](https://via.placeholder.com/100.png?text=Photo) | Bryan Castorius Halim | [Github](https://github.com/BryanCastorius) | [Portfolio](team/bryancastorius.md) \ No newline at end of file From 76cad7ca754667b723023b12ba143e3978fa2075 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 15 Apr 2024 19:56:16 +0800 Subject: [PATCH 253/274] Update Edward's PPP --- docs/team/edwardhumi.md | 50 ++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/docs/team/edwardhumi.md b/docs/team/edwardhumi.md index eace2dbe40..680f4735fa 100644 --- a/docs/team/edwardhumi.md +++ b/docs/team/edwardhumi.md @@ -1,15 +1,45 @@ # Edward Humianto's Project Portfolio Page +## Project: FitNUS + +### Overview FitNUS is a CLI application that aims to help combat diabetes and the overconsumption of calories, sugar, and carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. -Given below are my contributions to the project. -* Feature: Storage Class - * storage system to save user's meal, drinks, and exercises list in .txt format - * csv storage to keep track the nutrients and calories details of known meals, drinks, and exercises -* Feature: User Class - * added `listMealsAll`, `listDrinksAll`, `listExercisesAll`, `listEverythingAll` command which allows user to view the list for all dates - * added `listMeals d/dd-MM-yyyy`, `listDrinks d/dd-MM-yyyy`, `listExercises d/dd-MM-yyyy`, `listEverything d/dd-MM-yyyy` command which allows user to view the list for certain date -* Feature: Parser Class - * created parser for parsing commands and storage files -* Code contributed: https://nus-cs2113-ay2324s2.github.io/tp-dashboard/#/widget/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&chartGroupIndex=31&chartIndex=2 +### Summary of Contributions + +#### Code contributed: [RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2024-02-23&tabOpen=true&tabType=authorship&tabAuthor=edwardhumi&tabRepo=AY2324S2-CS2113-W14-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false) + +#### Features implemented +- Storage Class + - Data storage system to save and load user's meal, drinks, and exercises list in `txt` format + - Storage to keep track the nutrients and calories details of known meals, drinks, and exercises in `csv` format +- User Class + - Added `listMealsAll`, `listDrinksAll`, `listExercisesAll`, `listEverythingAll` command which allows user to view the + meal/drink/exercise list for all dates + - Added `listMeals d/dd-MM-yyyy`, `listDrinks d/dd-MM-yyyy`, `listExercises d/dd-MM-yyyy`, `listEverything d/dd-MM-yyyy` + command which allows user to view the list for certain date +- Parser Class + - Created parser for parsing commands and storage files + +#### Enhancements implemented +- Updated exception handling to give more specific edge cases (ie. negative value exception for meal/drink nutrient and exercise calories and non-positive value exception for meal/drink serving size and exercise duration) [#139](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/139) + +#### Project Management +- Added issues for `v1.0`, `v2.0` and `v2.1` + +#### Contributions to User Guide +- Added documentation for features `listMeals d/[DATE]`, `listDrinks d/[DATE]`, `listExercises d/[DATE]`, `listEverything d/[DATE]`. +Complete with command description, format, sample input and expected output. [#69](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/69/files#diff-b50feaf9240709b6b02fb9584696b012c2a69feeba89e409952cc2f401f373fb) + +#### Contributions to Developer Guide +- Added description, implementation, and class diagram for `Storage`. +[#147](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/147/files) [#150](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/150/files) + +#### Contributions to team-based tasks +- Created GitHub issues +- Assigned issues to team members +- Linked PR and Issues to Milestones + +#### Review or Mentoring Contributions +- [PR Reviews](https://github.com/AY2324S2-CS2113-W14-1/tp/pulls?q=is%3Apr+commenter%3Aedwardhumi) \ No newline at end of file From 19890ffdf052508d9b6db3ccc12c2b276d9c2a2b Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 15 Apr 2024 20:05:47 +0800 Subject: [PATCH 254/274] Update Edward's PPP --- docs/team/edwardhumi.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/team/edwardhumi.md b/docs/team/edwardhumi.md index 680f4735fa..839182b90f 100644 --- a/docs/team/edwardhumi.md +++ b/docs/team/edwardhumi.md @@ -22,9 +22,6 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. - Parser Class - Created parser for parsing commands and storage files -#### Enhancements implemented -- Updated exception handling to give more specific edge cases (ie. negative value exception for meal/drink nutrient and exercise calories and non-positive value exception for meal/drink serving size and exercise duration) [#139](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/139) - #### Project Management - Added issues for `v1.0`, `v2.0` and `v2.1` From 21d16d1912650bc9280dc90d6f5f87f997c628ad Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 15 Apr 2024 20:23:40 +0800 Subject: [PATCH 255/274] Add Enhancements for PPP --- docs/team/edwardhumi.md | 4 ++++ src/main/java/seedu/fitnus/parser/Parser.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/team/edwardhumi.md b/docs/team/edwardhumi.md index 839182b90f..c6076995d4 100644 --- a/docs/team/edwardhumi.md +++ b/docs/team/edwardhumi.md @@ -22,6 +22,10 @@ carbohydrates. Our vision is to promote healthy lifestyle amongst NUS students. - Parser Class - Created parser for parsing commands and storage files +#### Enhancements implemented +- Add exception and its handler to check whether a date is valid before displaying the list of meals/drinks/exercises for certain date +[#61](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/61/files) + #### Project Management - Added issues for `v1.0`, `v2.0` and `v2.1` diff --git a/src/main/java/seedu/fitnus/parser/Parser.java b/src/main/java/seedu/fitnus/parser/Parser.java index 0350c0c025..c37f3279e9 100644 --- a/src/main/java/seedu/fitnus/parser/Parser.java +++ b/src/main/java/seedu/fitnus/parser/Parser.java @@ -711,7 +711,7 @@ public static void parseExerciseCalories(String data) throws IllegalArgumentExce * * @param command The command entered by the user. * @return The parsed date string. - * @throws InvalidDateException If the date format is invalid. + * @throws FutureDateException If the date format is invalid. */ public static String parseListDate(String command) throws FutureDateException, ParseException { int indexOfDate = command.indexOf("d/") + 2; From 8e56d13ff793af646d7bd7c85fc7ef9e00de3957 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 20:45:27 +0800 Subject: [PATCH 256/274] Simplify storage and user sequennce diagram --- ...StorageManagerLoadingSequenceDiagram.puml} | 39 +++-------------- .../StorageManagerSavingSequenceDiagram.puml | 41 ++++++++++++++++++ ...m.puml => UserViewXYZSequenceDiagram.puml} | 13 ------ .../StorageManagerLoadingSequenceDiagram.png | Bin 0 -> 43300 bytes .../StorageManagerSavingSequenceDiagram.png | Bin 0 -> 32182 bytes .../UserViewXYZSequenceDiagram.png | Bin 0 -> 66051 bytes 6 files changed, 46 insertions(+), 47 deletions(-) rename docs/diagrams/{StorageManagerSequenceDiagram.puml => StorageManagerLoadingSequenceDiagram.puml} (56%) create mode 100644 docs/diagrams/StorageManagerSavingSequenceDiagram.puml rename docs/diagrams/{UserSequenceDiagram.puml => UserViewXYZSequenceDiagram.puml} (79%) create mode 100644 docs/diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png create mode 100644 docs/diagrams/diagrams_png/StorageManagerSavingSequenceDiagram.png create mode 100644 docs/diagrams/diagrams_png/UserViewXYZSequenceDiagram.png diff --git a/docs/diagrams/StorageManagerSequenceDiagram.puml b/docs/diagrams/StorageManagerLoadingSequenceDiagram.puml similarity index 56% rename from docs/diagrams/StorageManagerSequenceDiagram.puml rename to docs/diagrams/StorageManagerLoadingSequenceDiagram.puml index c5f40f789c..1d0e9dcfd5 100644 --- a/docs/diagrams/StorageManagerSequenceDiagram.puml +++ b/docs/diagrams/StorageManagerLoadingSequenceDiagram.puml @@ -9,14 +9,7 @@ participant "xyzStorage:Storage" as xyzStorage hide footbox !pragma teoz true -' -'Ui -> mealStorage**: Storage(...) -'Ui -> drinkStorage**: Storage(...) -'Ui -> exerciseStorage**: Storage(...) -'Ui -> mealNutrientStorage**: Storage(...) -'Ui -> drinkNutrientStorage**: Storage(...) -'Ui -> exerciseCaloriesStorage**: Storage(...) -activate Ui + Ui -> StorageManager**: StorageManager(...) activate StorageManager @@ -50,33 +43,11 @@ deactivate StorageManager else FileNotFoundException caught StorageManager -> xyzStorage ++: createFile() xyzStorage --> StorageManager --: created file to store user's data -end - -||| - -alt input is not exit command -else user input is exit -Ui -> Ui ++: handleExit() -Ui -> StorageManager: saveXYZ() -StorageManager -> xyzStorage++: get saved data in textContent of Storage -xyzStorage -> xyzStorage ++: writeFile(...) - -xyzStorage --> xyzStorage --: data saved into file -xyzStorage --> StorageManager --: saved user's xyz data -& StorageManager --> Ui: saved user's xyz data -||| - -Ui -> StorageManager: saveXYZNutrients() -StorageManager -> xyzNutrientStorage++: get saved data in textContent of Storage -xyzNutrientStorage -> xyzNutrientStorage ++: writeFile(...) - -xyzNutrientStorage --> xyzNutrientStorage --: data saved into file -xyzNutrientStorage --> StorageManager --: saved user's xyzNutrient data -& StorageManager --> Ui: saved user's xyzNutrient data -deactivate StorageManager -deactivate Ui -Ui --> Ui --: exit handled +else Exceptions related to saved file manipulations caught +StorageManager -> xyzStorage ++: clearFile() +xyzStorage --> StorageManager --: cleared previously saved file end + @enduml \ No newline at end of file diff --git a/docs/diagrams/StorageManagerSavingSequenceDiagram.puml b/docs/diagrams/StorageManagerSavingSequenceDiagram.puml new file mode 100644 index 0000000000..5dd9711f3e --- /dev/null +++ b/docs/diagrams/StorageManagerSavingSequenceDiagram.puml @@ -0,0 +1,41 @@ +@startuml +'https://plantuml.com/sequence-diagram + +participant ":Ui" as Ui +participant ":StorageManager" as StorageManager + +participant "xyzNutrientStorage:Storage" as xyzNutrientStorage +participant "xyzStorage:Storage" as xyzStorage + +hide footbox +!pragma teoz true + +Ui -> StorageManager**: StorageManager(...) +activate StorageManager + + +alt input is not exit command +else user input is exit +Ui -> Ui ++: handleExit() +Ui -> StorageManager: saveXYZ() +StorageManager -> xyzStorage++: get saved data in textContent of Storage +xyzStorage -> xyzStorage ++: writeFile(...) + +xyzStorage --> xyzStorage --: data saved into file +xyzStorage --> StorageManager --: saved user's xyz data +& StorageManager --> Ui: saved user's xyz data + +||| + +Ui -> StorageManager: saveXYZNutrients() +StorageManager -> xyzNutrientStorage++: get saved data in textContent of Storage +xyzNutrientStorage -> xyzNutrientStorage ++: writeFile(...) + +xyzNutrientStorage --> xyzNutrientStorage --: data saved into file +xyzNutrientStorage --> StorageManager --: saved user's xyzNutrient data +& StorageManager --> Ui: saved user's xyzNutrient data +deactivate StorageManager +Ui --> Ui --: exit handled +end + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UserSequenceDiagram.puml b/docs/diagrams/UserViewXYZSequenceDiagram.puml similarity index 79% rename from docs/diagrams/UserSequenceDiagram.puml rename to docs/diagrams/UserViewXYZSequenceDiagram.puml index 9321cc024e..d581536ba8 100644 --- a/docs/diagrams/UserSequenceDiagram.puml +++ b/docs/diagrams/UserViewXYZSequenceDiagram.puml @@ -24,7 +24,6 @@ User -> ExerciseList **: ExerciseList() activate ExerciseList ||| -opt user input is viewXYZ Parser -> User ++: handleViewXYZ() loop all meals in myMealList User -> MealList: get XYZ value for meal @@ -53,17 +52,5 @@ end User --> Parser --: display to user their XYZ content -end - -opt user input is clear -Parser -> User ++: handleClear() -User -> MealList: clear mealList -MealList --> User: mealList cleared -User -> DrinkList: clear drinkList -DrinkList --> User: drinkList cleared -User -> ExerciseList: clear exerciseList -ExerciseList --> User: exerciseList cleared - -User --> Parser --: clearing of lists handled @enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png b/docs/diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..541bbb92d778bc2105b1ce16288d0d29c03a08a7 GIT binary patch literal 43300 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Π{93U)2>hT0iiHHUf})VMOaf(1or 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 literal 0 HcmV?d00001 diff --git a/docs/diagrams/diagrams_png/UserViewXYZSequenceDiagram.png b/docs/diagrams/diagrams_png/UserViewXYZSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..954b9cf0ffee8aee8990fc278eaf7e53dabafd54 GIT binary patch literal 66051 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 literal 0 HcmV?d00001 From 0d13b0f9107e23bb09147c285bb2faa922efeb6a Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 20:45:47 +0800 Subject: [PATCH 257/274] Update UG with note for user --- docs/UserGuide.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index ab9d2a5b95..59b45d2675 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -240,6 +240,9 @@ serving of intake. A reminder that this user-defined meal will only be saved to our database when you **safely exit** our application with the command `exit`. +Additionally, you may use `newMeal` to override existing nutritional content data, by using the MEAL_NAME in the +command. In short, `newMeal` will **override any past data** with the specified meal name. + Note: We are not responsible for whether the meal name and its nutrional contents are accurate. Please verify your information before inputting. @@ -258,6 +261,9 @@ intake. A reminder that this user-defined drink will only be saved to our database when you **safely exit** our application with the command `exit`. +Additionally, you may use `newDrink` to override existing nutritional content data, by using the DRINK_NAME in the +command. In short, `newDrink` will **override any past data** with the specified drink name. + Note: We are not responsible for whether the drink name and its nutrional contents are accurate. Please verify your information before inputting. @@ -275,7 +281,10 @@ corresponding **calories burnt** for a **1 minute** HIGH, MEDIUM and LOW intensi A reminder that this user-defined exercise will only be saved to our database when you **safely exit** our application with the command `exit`. -Note: We are not responsible for whether the exercise name and its calories burnt are accurate. +Additionally, you may use `newExercise` to override existing calories burnt data, by using the EXERCISE_NAME in the +command. In short, `newExercise` will **override any past data** with the specified exercise name. + +**Note**: We are not responsible for whether the exercise name and its calories burnt are accurate. Please verify your information before inputting. **Format**: `newExercise EXERCISE_NAME, CALORIES_BURNT_HIGH, CALORIES_BURNT_MEDIUM, CALORIES_BURNT_LOW` From 6e6602d9c6bb4c4d8477461881023c43cc8db383 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 20:47:40 +0800 Subject: [PATCH 258/274] Update UG on lack of editExercise --- docs/UserGuide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 59b45d2675..37d261cd7d 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -605,6 +605,8 @@ here's the exercises you've done on 01-04-2024 ~~~ ## 2.5 For editing existing data +Note: There is no method to edit an inputted exercise of the day. If you would like to change a value in your +exerciseList, please use `deleteExercise` and add it again as a new exercise (`exercise`). ### 2.5.1 Edit an existing meal after inserted: `editMeal` For a meal that was inputted in the day, edit its serving size. You may identify the meal by its index in listMeals. From e126d223f06de99e41274810724583d66f2f18ed Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 21:42:05 +0800 Subject: [PATCH 259/274] Update User component in DG --- docs/DeveloperGuide.md | 62 +++++++++++------- docs/diagrams/UserClassDiagram.puml | 50 ++++++++++++++ .../diagrams_png/UserClassDiagram.png | Bin 0 -> 56706 bytes src/main/java/seedu/fitnus/user/User.java | 6 +- 4 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 docs/diagrams/UserClassDiagram.puml create mode 100644 docs/diagrams/diagrams_png/UserClassDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 8f760dd15e..abc1f3068d 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -3,8 +3,7 @@ ## Acknowledgements Below are the references used on the project: -1. [Developer Guide](https://se-education.org/addressbook-level3/DeveloperGuide.html) -2. [User Guide](https://se-education.org/addressbook-level3/UserGuide.html) +1. The general idea for the project stemmed from the ip project: [ip](https://nus-cs2113-ay2324s2.github.io/website/admin/ip-overview.html) ## Design & implementation @@ -28,7 +27,7 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a ### Ui Component #### Sequence Diagram -_Note: The following sequence diagram captures the interactions only between the Fitnus, Ui and Parser classes_ +_Note: The following sequence diagrams captures the interactions only between the Fitnus, Ui and Parser classes_ ![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ParserSequenceDiagram.png) @@ -74,21 +73,33 @@ _Note: The following sequence diagram captures the interactions only between the classes when loading and saving data. XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ -![Storage Sequence Diagram](../docs/diagrams/diagrams_png/StorageManagerSequenceDiagram.png) +**_Sequence Diagram_**: When **loading** saved data upon starting the application: +![Storage Loading Sequence Diagram](../docs/diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png) +Storage Manager has to load both the stored nutritional content/calories burnt and any user saved data. +Exceptions are caught if the file to load is not found and if the file to load has been manipulated. + +**_Sequence Diagram_**: When **saving** data upon exiting the application: + ![Storage Saving Sequence Diagram](../docs/diagrams/diagrams_png/StorageManagerSavingSequenceDiagram.png) +Storage Manager has to save both the updated nutritional content/calories burnt and any user inputted data. ### User Component #### Description -The User component will create MealList, DrinkList and ExerciseList for the user to track their data. Additionally, -this component is in-charge of handling view, listEverything, recommend and clear commands. +The User component will create MealList, DrinkList and ExerciseList for the user to track their data. +Otherwise, this component is only in-charge of handling view, listEverything, recommend and clear commands. #### Implementation -User Class: -- Attributes: - - `myMealList:` Represents the user's class that managers the meal lists. - - `myDrinkList:` Represents the user's class that managers the drink lists. - - `myExerciseList:` Represents the user's class that managers the exercise lists. - +![User Class Diagram](../docs/diagrams/diagrams_png/UserClassDiagram.png) +**_User Class:_** +- Attributes: + - `myMealList:` Represents the user's class that managers the meal lists. Multiplicity = 1. + - `myDrinkList:` Represents the user's class that managers the drink lists. Multiplicity = 1. + - `myExerciseList:` Represents the user's class that managers the exercise lists. Multiplicity = 1. + +- Constructor: + - `User()`: A MealList, DrinkList and ExerciseList is initialised for the user to + track their data. However, methods to handle these lists will be handled in the respective MealList, DrinkList and + ExerciseList classes. - Methods: - `handleViewCalories()`: Prints the user's net calorie intake of the day. - `handleViewCarbohydrates()`: Prints the user's total carbohydrates intake of the day. @@ -103,19 +114,18 @@ User Class: - `handleRecommendations()`: Give recommendations to the user based on their calorie and water intake. #### Sequence Diagram -_Note: The following sequence diagram captures the interactions only between the User, MealList, DrinkList and -ExerciseList classes._ - -For diagram simplicity, the following choices were made when creating the diagram: -- Only optional blocks for handleViewXYZ() and handleClear() methods were created. - As such, methods within User such as - handleRecommendations() and handleListEverything() were omitted. -- For methods where the user would like to view their nutrional content (handleViewXYZ), XYZ is used as a placeholder - for the specified nutritional content (e.g. calories, carbohydrates, protein etc.) +For diagram simplicity, the following choice was made when creating the diagram: +- For the method where the user would like to view their nutrional content (handleViewXYZ), XYZ is used as a + placeholder for the specified nutritional content (e.g. calories, carbohydrates, protein etc.) -![User Class Diagram](../docs/diagrams/diagrams_png/UserSequenceDiagram.png) +![User Sequence Diagram](../docs/diagrams/diagrams_png/UserViewXYZSequenceDiagram.png) +The Sequence Diagram above shows the interaction between the relevant classes when handleViewXYZ() is called by +Parser. -User class initialises MealList, DrinkList and ExerciseList for the user to track their data. +_**How it works:**_ +The method in User will iterate through the user's MealList, DrinkList and ExerciseList each time it is called to +obtain the required XYZ value of each meal and/or drink and/or exercise. +This idea is similarly used when implementing the `handleListEverything` methods. ### Exercise Component ![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseListClassDiagram.png) @@ -269,3 +279,9 @@ Given below are instructions to test the app on your own device. 4. Save and Shutdown 1. Type `exit` to shut down the FitNUS app. 2. Upon exiting, all entries inputted will be updated to the database locally. + +### Missing/Corrupted Data Files +Upon launch, if there has been errors with data files, FitNUS will automatically clear past data and create a new +file. +**For manual clearing of files (only applicable to lists):** +1. Delete the XYZList.txt file from ./data folder diff --git a/docs/diagrams/UserClassDiagram.puml b/docs/diagrams/UserClassDiagram.puml new file mode 100644 index 0000000000..372423bdeb --- /dev/null +++ b/docs/diagrams/UserClassDiagram.puml @@ -0,0 +1,50 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor CLASS_ARROW_COLOR +skinparam classBackgroundColor CLASS_DIAGRAM_COLOR +skinparam classAttributeIconSize 0 + +Class User { + - MAX_WATER_INTAKE : int = 10000 + - RECOMMEND_WATER_INTAKE : int = 2600 + - RECOMMEND_CALORIE_INTAKE : long = 2200 + + User() + + handleViewCalories(): void + + handleViewCarbohydrates(): void + + handleViewProteins(): void + + handleViewFiber(): void + + handleViewFat(): void + + handleViewSugar(): void + + handleListEverything(): void + + handleListEverythingAll(): void + + handleViewFat(): void + + handleViewSugar(): void + + handleListEverything(): void + + handleListEverythingAll(): void + + handleListEverythingDate(String command) : void + + handleClear(): void + + handleRecommendations(): void +} + +Class MealList { + + mealList: ArrayList + + mealListAll: ArrayList +} + +Class DrinkList { + + drinkList: ArrayList + + drinkListAll: ArrayList + + waterList: ArrayList + + waterListAll: ArrayList +} + +Class ExerciseList { + + exerciseList: ArrayList + + exerciseListAll: ArrayList +} + +User -down--> "myMealList 1" MealList +User -down--> "myDrinkList 1" DrinkList +User -down--> "myExerciseList 1" ExerciseList +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/UserClassDiagram.png b/docs/diagrams/diagrams_png/UserClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..2b48a7d35102081bc0250865be5d61555b79fc47 GIT binary patch literal 56706 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 jNN_OCl|lcP4{t=j3nDed Date: Mon, 15 Apr 2024 21:46:55 +0800 Subject: [PATCH 260/274] Finalise PPP --- docs/team/claribelho.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/team/claribelho.md b/docs/team/claribelho.md index b31eae6579..dbff546097 100644 --- a/docs/team/claribelho.md +++ b/docs/team/claribelho.md @@ -40,11 +40,16 @@ Given below are my contributions to the project - Created User Guide in v1.0, including the description, format, sample input and expected output for each command. [#35](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/35) - Add documentation for `allmeals`, `allDrinks` and `allExercises`. [#76](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/76) -- Finalisation of descriptions and formatting in final v2.1 submission. [#153](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/153) +- Finalisation of descriptions and formatting in final v2.1 submission, with heavy emphasis on including notes for + the user to take note on. +[#153](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/153) ### Contributions to Developer Guide -- Added Sequence Diagrams for Ui, Storage and User components. -- Provide descriptions for User component +- User Component: Add Class Diagram, Descriptions and Sequence Diagram. +- Ui Component: Add descriptions and Sequence Diagrams. +- Storage Component: Add Sequence Diagram. +- Appendix: Manual Testing with corrupted files. + ### Contributions to team-based tasks - Constantly improving the defensiveness of the code by finding bugs From d2e916caf469a1316eb675e5223a1d54488140cf Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 21:56:08 +0800 Subject: [PATCH 261/274] Fix checkstyle error --- src/main/java/seedu/fitnus/user/User.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/fitnus/user/User.java b/src/main/java/seedu/fitnus/user/User.java index f02d94fa1d..6df32d41a3 100644 --- a/src/main/java/seedu/fitnus/user/User.java +++ b/src/main/java/seedu/fitnus/user/User.java @@ -21,14 +21,13 @@ * Handles all methods related to the user's meals, drinks and exercise. */ public class User { + public static MealList myMealList; + public static DrinkList myDrinkList; + public static ExerciseList myExerciseList; private static final int MAX_WATER_INTAKE = 10000; private static final int RECOMMEND_WATER_INTAKE = 2600; private static final long RECOMMEND_CALORIE_INTAKE = 2200; - public static MealList myMealList; - public static ExerciseList myExerciseList; - public static DrinkList myDrinkList; - public User() { myMealList = new MealList(); myDrinkList = new DrinkList(); From a3de315d967afdefef8166762856052cf1c6eabc Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Mon, 15 Apr 2024 22:07:58 +0800 Subject: [PATCH 262/274] Update UserGuide.md based on page deployment formatting errors --- docs/UserGuide.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 37d261cd7d..4678d77c99 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -38,10 +38,11 @@ To use the app please follow the setup procedures below: **Note**: 1. All files under 'data' and 'db' folders should not be modified by user. 2. Enter `exit` to properly close the program and save the data. + --- + ## 2) Features List -* For ease of reading this guide, _**sample input**_ is only provided if input command is not the command itself, i.e. the - input is not one-word. +* For ease of reading this guide, _**sample input**_ is only provided if input command is not the command itself, i.e. the input is not one-word. ## 2.1 Information for users ### 2.1.1 Viewing all commands: `help` Shows a list of all possible command inputs recognised by the application. @@ -113,7 +114,8 @@ Miscellaneous: ~~~ ### 2.1.2 Viewing all pre-defined meals: `allMeals` Shows a list of all pre-defined meals. These meals will have their nutritional content defined per serving size and can -be inputted immediately. +be inputted immediately. + Note: If the user has added a self-defined meal previously (using `newMeal`), this self-defined meal will also be displayed. @@ -150,7 +152,8 @@ You may also input a meal that isn't here with newMeal. ### 2.1.3 Viewing all pre-defined drinks: `allDrinks` Shows a list of all pre-defined drinks. These drinks will have their nutritional content defined per 100ml -and can be inputted immediately. +and can be inputted immediately. + Note: If the user has added a self-defined drink previously (using `newDrink`), this self-defined drink will also be displayed. @@ -183,6 +186,7 @@ You may also input a drink that isn't here with newDrink. ### 2.1.4 Viewing all pre-defined exercises: `allExercises` Shows a list of all pre-defined exercises. These exercises will have the number of calories burnt for a high/medium/low intensity workout defined per minute and can be inputted immediately. + Note: If the user has added a self-defined exercise previously (using `newExercise`), this self-defined exercise will also be displayed. @@ -718,4 +722,4 @@ Only changes made today can be edited/deleted, so make sure that everything is c **Q**: My `listDrinks` have 3 indexes, but my `listDrinksAll` have 10 indexes, why can't I perform `deleteDrink 10`? **A**: Referring to the previous question, you can only delete/edit items made today. `listDrinks` and `listDrinksAll` -have different list indexes, please follow `listDrinks` index only. This applies to both meal and exercises. \ No newline at end of file +have different list indexes, please follow `listDrinks` index only. This applies to both meal and exercises. From 4efe78128028b223944871f21227ad9878e54661 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Mon, 15 Apr 2024 22:12:56 +0800 Subject: [PATCH 263/274] Update UserGuide.md --- docs/UserGuide.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 4678d77c99..32fbdbe25b 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -37,14 +37,16 @@ To use the app please follow the setup procedures below: **Note**: 1. All files under 'data' and 'db' folders should not be modified by user. -2. Enter `exit` to properly close the program and save the data. +2. Enter `exit` to properly close the program and save the data. --- -## 2) Features List +## 2) Features List * For ease of reading this guide, _**sample input**_ is only provided if input command is not the command itself, i.e. the input is not one-word. -## 2.1 Information for users -### 2.1.1 Viewing all commands: `help` + + +## 2.1 Information for users +### 2.1.1 Viewing all commands: `help` Shows a list of all possible command inputs recognised by the application. **Format**: `help` From 11f9ad63613475e69e786e6e62d619c355bd4e80 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Mon, 15 Apr 2024 22:15:11 +0800 Subject: [PATCH 264/274] Update _config.yml --- docs/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_config.yml b/docs/_config.yml index 2f7efbeab5..8b13789179 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-minimal \ No newline at end of file + From 02bd36b06bdb3f8ef0b6af7c618b21f15a0e18a3 Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 22:26:25 +0800 Subject: [PATCH 265/274] Update PPP links --- docs/team/claribelho.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/team/claribelho.md b/docs/team/claribelho.md index dbff546097..088d938dd7 100644 --- a/docs/team/claribelho.md +++ b/docs/team/claribelho.md @@ -37,6 +37,7 @@ Given below are my contributions to the project * Improve checks when loading saved data in Storage to detect for user manipulation. ### Contributions to User Guide +- [View our User Guide](https://ay2324s2-cs2113-w14-1.github.io/tp/UserGuide.html) - Created User Guide in v1.0, including the description, format, sample input and expected output for each command. [#35](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/35) - Add documentation for `allmeals`, `allDrinks` and `allExercises`. [#76](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/76) @@ -45,17 +46,23 @@ Given below are my contributions to the project [#153](https://github.com/AY2324S2-CS2113-W14-1/tp/pull/153) ### Contributions to Developer Guide -- User Component: Add Class Diagram, Descriptions and Sequence Diagram. -- Ui Component: Add descriptions and Sequence Diagrams. -- Storage Component: Add Sequence Diagram. -- Appendix: Manual Testing with corrupted files. +- [View our Developer Guide](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html) +- [User Component](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html#ui-component): Add Class Diagram, + Descriptions and Sequence Diagram. +- [Ui Component](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html#ui-component): Add descriptions and + Sequence Diagrams. +- [Storage Component](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html#sequence-diagram-1): Add + Sequence Diagram. +- [Appendix](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html#missingcorrupted-data-files): Manual + Testing with corrupted files. ### Contributions to team-based tasks -- Constantly improving the defensiveness of the code by finding bugs -- Create User Guide and ensure it is formatted and up-to-date -- Documentation of Methods -- Update of README to provide a summary of UG +- Constantly improving the defensiveness of the code by finding bugs. +- Create User Guide and ensure it is formatted and up-to-date. +- Documentation of Methods. +- Update of README to provide a summary of UG. +- Ensure that the website deployments of README, User Guide and Developer Guide is accurately displayed. ### Contributions beyond the project team - Bugs Review for other teams: [CS2113-T15-1](https://github.com/nus-cs2113-AY2324S2/tp/pull/44) From a813c9480250a0b5cb88f32df9b462eaee28e1de Mon Sep 17 00:00:00 2001 From: Claribel Ho Date: Mon, 15 Apr 2024 22:28:28 +0800 Subject: [PATCH 266/274] Update digrams image references in DG --- docs/DeveloperGuide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 9eba3913e2..f473e1fcb8 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -40,7 +40,7 @@ Below are the references used on the project: The architecture diagram belows shows the overall design of our FitNUS CLI app and how each component interact with each other. -![Architecture Diagram](../docs/diagrams/diagrams_png/ArchitectureDiagram.png) +![Architecture Diagram](diagrams/diagrams_png/ArchitectureDiagram.png) **Main Components of The Architecture** @@ -58,7 +58,7 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a #### Sequence Diagram _Note: The following sequence diagrams captures the interactions only between the Fitnus, Ui and Parser classes_ -![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ParserSequenceDiagram.png) +![ParserSequenceDiagram.png](../docs/diagrams/diagrams_png/ParserSequenceDiagram.png) When the user first starts the application, the Ui class will be constructed. Within the Ui class, Scanner and Parser similarly will be constructed. From 5c739fa5b908972c982cee7f2e19b6bf5aa9b708 Mon Sep 17 00:00:00 2001 From: Bryvo Date: Mon, 15 Apr 2024 22:33:02 +0800 Subject: [PATCH 267/274] Update DG ...amend the images file route. --- docs/DeveloperGuide.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 9eba3913e2..49c29a0a67 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -24,6 +24,7 @@ * [User Stories](#user-stories) * [Non-Functional Requirements](#non-functional-requirements) * [Instructions for Manual Testing](#instructions-for-manual-testing) +* [Missing/Corrupted Data Files](#missingcorrupted-data-files) --- @@ -40,7 +41,7 @@ Below are the references used on the project: The architecture diagram belows shows the overall design of our FitNUS CLI app and how each component interact with each other. -![Architecture Diagram](../docs/diagrams/diagrams_png/ArchitectureDiagram.png) +![Architecture Diagram](diagrams/diagrams_png/ArchitectureDiagram.png) **Main Components of The Architecture** @@ -58,7 +59,7 @@ The architecture diagram belows shows the overall design of our FitNUS CLI app a #### Sequence Diagram _Note: The following sequence diagrams captures the interactions only between the Fitnus, Ui and Parser classes_ -![Ui Sequence Diagram](../docs/diagrams/diagrams_png/ParserSequenceDiagram.png) +![Ui Sequence Diagram](diagrams/diagrams_png/ParserSequenceDiagram.png) When the user first starts the application, the Ui class will be constructed. Within the Ui class, Scanner and Parser similarly will be constructed. @@ -95,7 +96,7 @@ into list in the `MealList`, `DrinkList`, and `ExerciseList`. If the txt files a from the list and format it into string. Then, it will append all the strings and write the files to the corresponding `Storage`. #### Class Diagram -![Storage Class Diagram](../docs/diagrams/diagrams_png/StorageClassDiagram.png) +![Storage Class Diagram](diagrams/diagrams_png/StorageClassDiagram.png) #### Sequence Diagram _Note: The following sequence diagram captures the interactions only between the Ui, Storage and StorageManager @@ -103,12 +104,12 @@ classes when loading and saving data. XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ **_Sequence Diagram_**: When **loading** saved data upon starting the application: -![Storage Loading Sequence Diagram](../docs/diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png) +![Storage Loading Sequence Diagram](diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png) Storage Manager has to load both the stored nutritional content/calories burnt and any user saved data. Exceptions are caught if the file to load is not found and if the file to load has been manipulated. **_Sequence Diagram_**: When **saving** data upon exiting the application: - ![Storage Saving Sequence Diagram](../docs/diagrams/diagrams_png/StorageManagerSavingSequenceDiagram.png) + ![Storage Saving Sequence Diagram](diagrams/diagrams_png/StorageManagerSavingSequenceDiagram.png) Storage Manager has to save both the updated nutritional content/calories burnt and any user inputted data. ### User Component @@ -117,7 +118,7 @@ The User component will create MealList, DrinkList and ExerciseList for the user Otherwise, this component is only in-charge of handling view, listEverything, recommend and clear commands. #### Implementation -![User Class Diagram](../docs/diagrams/diagrams_png/UserClassDiagram.png) +![User Class Diagram](diagrams/diagrams_png/UserClassDiagram.png) **_User Class:_** - Attributes: @@ -147,7 +148,7 @@ For diagram simplicity, the following choice was made when creating the diagram: - For the method where the user would like to view their nutrional content (handleViewXYZ), XYZ is used as a placeholder for the specified nutritional content (e.g. calories, carbohydrates, protein etc.) -![User Sequence Diagram](../docs/diagrams/diagrams_png/UserViewXYZSequenceDiagram.png) +![User Sequence Diagram](diagrams/diagrams_png/UserViewXYZSequenceDiagram.png) The Sequence Diagram above shows the interaction between the relevant classes when handleViewXYZ() is called by Parser. @@ -157,18 +158,18 @@ obtain the required XYZ value of each meal and/or drink and/or exercise. This idea is similarly used when implementing the `handleListEverything` methods. ### Exercise Component -![Exercise Class Diagram](../docs/diagrams/diagrams_png/ExerciseListClassDiagram.png) +![Exercise Class Diagram](diagrams/diagrams_png/ExerciseListClassDiagram.png) 1. Upon starting up the application, User will call `loadExercise` to fetch all data from `ExerciseList.txt` and add it into `exerciseListAll`. 2. A `User` class consists of zero to as many `Exercise` objects in the ArrayList. 3. Each `Exercise` contains exactly one enumeration of `ExerciseIntensity`. ### Drink Component -![Drink Class Diagram](../docs/diagrams/diagrams_png/DrinkListClassDiagram.png) +![Drink Class Diagram](diagrams/diagrams_png/DrinkListClassDiagram.png) 1. Upon starting up the application, User will call `loadDrink` to fetch all data from `DrinkList.txt` and add it into `drinkListAll`. 2. A `User` class consists of zero to as many `Drink` objects in the ArrayList and zero to as many `Water` objects in the ArrayList. ### Meal Component -![Meal Class Diagram](../docs/diagrams/diagrams_png/MealListClassDiagram.png) +![Meal Class Diagram](diagrams/diagrams_png/MealListClassDiagram.png) 1. Upon starting up the application, User will call `loadMeal` to fetch all data from `Mealist.txt` and add it into `mealListAll`. 2. A `User` class consists of zero to as many `Meal` objects in the ArrayList. @@ -180,7 +181,7 @@ This idea is similarly used when implementing the `handleListEverything` methods The `infoMeal` command allows user to obtain the nutritional values (protein, calories, carbs, etc.) of a particular meal. The following sequence diagram shows the execution of the `infoMeal` command -![InfoMeal Sequence Diagram](../docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png) +![InfoMeal Sequence Diagram](diagrams/diagrams_png/InfoMealSequenceDiagram.png) 1. The user inputs an `infoMeal` command of the format `infoMeal m/MEAL` in this example we use `infoMeal m/ chicken rice` which is inputted to the `ui` object 2. The `ui` object calls the `parseCommand()` method of the `parser` object @@ -192,7 +193,7 @@ meal. The following sequence diagram shows the execution of the `infoMeal` comma The `eat` command is responsible for handling the tracking of meal and adding it to the Meal List. The following sequence diagram shows the execution of the `eat` command. -![Eat Command Sequence Diagram](../docs/diagrams/diagrams_png/EatCommandSequenceDiagram.png) +![Eat Command Sequence Diagram](diagrams/diagrams_png/EatCommandSequenceDiagram.png) 1. The user inputs an `eat` command of the format `eat m/MEAL s/SERVING_SIZE` into the `ui` object 2. The `ui` object calls the `parseCommand()` method of the `parser` object @@ -209,7 +210,7 @@ Note: The implementation for `drink` and `exercise` command have similar sequenc The `editMeal` command allows users to edit the serving sizes of their meals that have already been added to the Meal List. The following sequence diagram shows the execution of the `editMeal` command. -![Edit Meal Command Sequence Diagram](../docs/diagrams/diagrams_png/EditMealCommandSequenceDiagram.png) +![Edit Meal Command Sequence Diagram](diagrams/diagrams_png/EditMealCommandSequenceDiagram.png) 1. The user inputs an `editMeal` command of the format `editMeal INDEX s/NEW_SERVING_SIZE` into the `ui` object 2. The `ui` object calls the `parseCommand()` method of the `parser` object @@ -226,7 +227,7 @@ Note: The implementation for `editDrink` and `editWater` command have similar se The `newMeal` command allows users to add new meal to the list of available meals by specifying the meal name and its nutrients. The following sequence diagram shows the execution of the `newMeal` command. -![New Meal Command Sequence Diagram](../docs/diagrams/diagrams_png/NewMealCommandSequenceDiagram.png) +![New Meal Command Sequence Diagram](diagrams/diagrams_png/NewMealCommandSequenceDiagram.png) 1. The user inputs an `newMeal` command of the format `newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR` into the `ui` object 2. The `ui` object calls the `parseCommand()` method of the `parser` object @@ -320,6 +321,7 @@ Given below are instructions to test the app on your own device. 4. Save and Shutdown 1. Type `exit` to shut down the FitNUS app. 2. Upon exiting, all entries inputted will be updated to the database locally. + --- ### Basic Features Given below are the basic features of our FitNUS, do note that it's not the complete list of commands. From 028a2684e01568670cad664e5943000520e0d055 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Mon, 15 Apr 2024 22:37:01 +0800 Subject: [PATCH 268/274] Fix PPP link error --- docs/team/claribelho.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/team/claribelho.md b/docs/team/claribelho.md index 088d938dd7..093c8b49c8 100644 --- a/docs/team/claribelho.md +++ b/docs/team/claribelho.md @@ -47,7 +47,7 @@ Given below are my contributions to the project ### Contributions to Developer Guide - [View our Developer Guide](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html) -- [User Component](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html#ui-component): Add Class Diagram, +- [User Component](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html#user-component): Add Class Diagram, Descriptions and Sequence Diagram. - [Ui Component](https://ay2324s2-cs2113-w14-1.github.io/tp/DeveloperGuide.html#ui-component): Add descriptions and Sequence Diagrams. From ee64b4be057035657efdb93ad93f4f054a55c744 Mon Sep 17 00:00:00 2001 From: edwardhumi Date: Mon, 15 Apr 2024 22:55:00 +0800 Subject: [PATCH 269/274] Edit Storage Class Diagram --- docs/diagrams/StorageClassDiagram.puml | 9 +-------- .../diagrams_png/StorageClassDiagram.png | Bin 85740 -> 75588 bytes 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 02212be10b..12c41fe3e7 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -6,14 +6,7 @@ skinparam classBackgroundColor CLASS_DIAGRAM_COLOR skinparam classAttributeIconSize 0 Class Ui { - - mealStorage: Storage - - drinkStorage: Storage - - exerciseStorage: Storage - - mealNutrientStorage: Storage - - drinkNutrientStorage: Storage - - exerciseCaloriesStorage: Storage - - storageManager: StorageManager - - parser: Parser + + isExit: boolean + handleExit(): void } diff --git a/docs/diagrams/diagrams_png/StorageClassDiagram.png b/docs/diagrams/diagrams_png/StorageClassDiagram.png index da82f502d3d2230b11834acc2d4bdef8e8b2b712..ed64ab5556c3db14d97e2ae98959d794dba07a0e 100644 GIT binary patch literal 75588 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ℑ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

#+*g(kYz20X$sVk7Kv_?$?_m z3h>+K!xzE2I`gXe)v#%a&?MFxdtX6e87U%997pIBRKcxQhFdb}zpVaED%>2)^mSj2 zG7WE?K!X`YX=L-zFyZ2_6t_Tc;b75LO=&NvBO(Xb zUpk5=IC#C+X2Yf*9W+!^#JW&(y4lO9Bfc%@`U7E%-;kF!fYB7hvLj^fXgM z+Wv}TT>h?=9jPMo{SO-N{K8yGi8}=Ff84ZR&Bjg|P`mVdk zGQYno0rdf~8di;t+_#{sNo@k{YI;6>_(t+8)yUx4e7e|$hrW#mc3^8ZV9e+jR?| zB<2AZNlfqcKN2wCKN7H7hUO)c+XM`RlCH_?SR)|V4MV_{IGX)Ti+m3)pI_`mj|5;m zow}WG0D`HERvc_8+oc4EIc{R|(D;RDntm8Dh*rn$dSPAAGVsFgt=ZPixxcS^AcaS} z^fsOLEY`H zC8Fiaew8-_)bkEU=89iC?ha_40bJ!K1n-UB-dsT49vv1dNMXrrT+!xm4>ogmsfyv!JFWa`VKy-5;k@d~ zl2m}nWW%PHkLomh#^2cQC8qSCnICoeZO2rsh;C%LN2_fuj1Y^!Brq`WgvOYdyGQHC zO6}EpE&268Wx@Oot|L^Otj{v1ReiPi_AZRMi`5&}(MM~=JomTiFR!-TP(bJ9S(JGJ zB^jBu^nt}jA8sTb;XV9}mdwwJ-#X_1O5`RpltsHJ2;Zp>(LR-=K^N&*w5-l~Zk?aR z$d~?~IUCcp0;V6OGac?@phWJ=%Dl3u`%-@(QpRde8@|GsaQ#q%qof9i+(DVZoyX?cT#kD@O0v}S}Hs^!e=LA z4Q?WFvdNq(;P?dpB~~uo`%|o3965@SAdsl6Sbd*Ur&iLaRCI{Kbp?xs7IPVyW3cOL z3-OQ7Oc=*C1;Xm(XWK0!StSo9mpo@TFHex~KymI_x2^kotLDfLpukVN_@^AWiG|>O zzVN>}#UeSP@5MeF7yFof&*KGVL+xXzqC*O{ab+lxkC%?JXJI^0d z<|vE=abT!c=_)L%nurn&uc|ztc}CPYr{MKG;Ipssx42;+DSlniiBfF}KO6Y4E{e2? z1A7#$`)CSU^bGhm?m3FOu=Z+315Kis-rEnlOH_gb139UjI7&5hn#W)oufdl}O=Cs? z+BUFd01Y1UX1TP^34GCif(Y`gQhv+WYH|Z?$%yLJL%>+tX1%i78Ducbo<-1M^Y>Om zS84-dVW!}e0~Or-BG9%=*195Q=eB}%+5DyYB)pWm#V<9>H!M5D;({dNhr=SY@kKr6 zR^NgGn=ENikL$nwyHDFEke}MQ64cn)bnxJ|rwVujrfd>jrn}q~d=a(#Ui+YAr&?@7 zx=|HLQn9#O;Dab|D$JJbu&TDAo?h&ylFM=B*7-wp=QkTy z*8%AOP@q8nwmt-i2V_)BU^J1x6f`(WYR_6OjirGZAjOu=Q1yVnGeXc;OLJgYsXe*{oX4uK?HpzoN<=m@$|G z*LOyM@rCJT*0n!4THPUU;e1^jB}Yp}lXpBBKmF_Lf~G8%AAqwdU!VB;Xsc?g!#S6L zE-oLJMN*WcIyM};V}8BvJRDwb!R%YOd_VJjLG>|&$TD|T7@aFB^L%H6S~5hyiSK}} zU352w{6q=H*H0^aD+Pe8Wa+T%NMtoq3w) zHgqH8oD00h_ zs13kX7Fhw^u34rERG|xwaoK+mYL6CQGAyy}jLLzI5-X3c zzNebTBWlr4nq95iU*#PV^M*Vr(5#3qMWhDLku<@7F`A&Fp z^-%=c^&3a*()>3^d}u<~GBSOVs`&aMR{;;O4%{rbk1T;o&u#7H(~knaXMlP6=x09kwdSE6!Gs*`i{aQwt@KuxLYhIyYA+dcjhap zt%F~=F7iOvrX9?v0jX0_euOf(s_q#yw=t(?aDPnc6(&6ETmA~yEYHKj`|8du;Waxv zDsvOY8yZz?Niz#3X9TKUWb}bj!tHtiJ1w$iOVJ^eA>8~)9-pdpnx|oZt!`7%kS}NE z;5aQ*s>!LUnj-htLOk_61wxHC+6;I$?$Ju0f3ylm{Qzw&9B_F5796lqs47}pczgMK zV?fZk#^*KzFlr*?LT<=@Wy0Up>}5j(!e1%R@E2TF;C3P_>=fG9{A=7Y%K@+Jq=4f{ zhBE>AC{~dd->exRow3<;{lk?KKrKs~l~w449w30s3VcBiPlutcL06L}PsF8bYupg@ z)m0rd7Vk3Q7l*jw_`~N5d6&wlDTNKO`)?nXRO=y!o=qIpft`bT^MWyOw06Hk6SB|U zP*tweCQS=3N>s5{|!F~^L*^*F~jgtm!A+M&TPLqD=Dnjv5ZpnYO zgl5o-aRgBHd>|YQLIM>SZJzH^?WAvX)uDYc^M}8anxpqSDx8+$TOx49jwOpb5TzG@ zh_)zp-NxdSW8Yie8M}W*RC#s3kH3=Ud|int+yoBssD42?TF_25AeP^9Aqhub;=4T% z+bnHbs(8+L9RTh$+S($>fxq-q6eT2qgydo8Osxw)7{qkcI=mFy@+J>%5K2N#_z8#0jA)JSwYf zj+fGv=IfbnNnEN@Q$IIYvzBhnVyjjXMzb6C>SDn^{qffD=!3D&<|)!5iKY_Vn?RTM zw?KDfTrvaH3W08e1@2yq7p&fSLO~t#U-MZ$S@c7b56AP~>gTt*(x^WepL=v>b8@^M zII!o5U_cUY@~9Ij7z7b|o~gQksvielms+&AfMiY)MmkGrTFlDP4O4f zkwyB--NWjD#*B*{`Xz?de>G8n2P(C^8xO!DYsA#JoKY@j{nRYqi3yq1YtYUS0;v0U z=BNB6x4StlP!{N_;h|M{n%`T15y)e?7vIE6Nc)%*MV z3x9GwhK?+{$w}@r+!e?CG~=%@nF{K=Rcl8;33}JBbj#&pw^hH@=J`sK$jWbRfiB|m_tG92ZMVzDDaNw z%JfO?^?7Z)v&HL|ez;&Xn0T--$aD_#|Ph6Jd*&!dSn+B|>vr z1zv$MGxzn`38f!c7QKvae=V%7Dv8-NEpmG=Z{L7B!V8aa;CZ*np5^i}1q}Q-1Qqk) zCcC-K_mGfe|AtSWzPt)W1(ZhGj$gkSo{F>NKgvb^i>Pv+L9F=u8I&%$PeO9%r`Yf; z8aRjtcdSXl-9VrH_ve{u)_(!Ri-;_K)U#RTf?8$P?9yk%Dli)-E6*kUxsHR>9HL!^ zHwjefm{}ukW%Kb?=!jqC%E?Vq;ZU96u=YJD(u6r2%wo{_Rd*tHC~buiEskl?m;l|4 zIh1myyW)X(n4K-O3b^0$~2hx!VU5gFJSMSnwPc z?k`M`e~n`HGFE{y@S+M$;Ch)|r?cLqb>pD*8N4!GhTnr=pLY$7R}nG!(wss^(|Csg zYB->F28M{5VvsxhDQ*N`X-%nm0XqFMF`??o3qdfv9TmgotNd}5jMu7(MfOVF zkm0jj1YaP8cJ`JdNjp)F;q;PDVbZ^ms)`lJT8R&Fzwi%OfkA;*>?DAEndqtO83E%t zM)sR!iD2WeLX1(XQjuxY9tC1F%mWRP=K`&RpD1!?E0H8Z_^@U<% zdj4Jm5G*>&PZon|VhHnqJ_{YdlP&`~gs|C3pm+l06M_(QxLdl}JYYhpYX6?n;=f>Y zh&coLCTwU17~~#a6;YbB;86#}qR9Aoz6mEktXiJZ&mii8d=p#^>|R2AvN-{W6$c~- zW1yzR0j3y5%~ZJ#dA}in3iHqqaAY1wkv}?usGR(vw5w8s4t6Mms_p6xx@hQL>U)AF z(2<*qkIyI(?^FN#?|;Pq!$TxZR}pakqg`-Xb_mH|CFOC|1PO{2mi80RTvrm8ax<1Y zbMHp&cVyGd04q@c`7_a7g85}25CKXA;W?kvP7sfq4sr1dCWZyC6J;9Pg$RB0b>@Lr z8)A*%!_2*0*fw!0cxlcd?75JKM&^04I{_%MFBY{CB4EbImNt7KmVawKH~=A$Ng)97 zGgO$ES(sAH-$*|B2Izd`+dtC!Y{O?z4!>25E8PHSuDb0{)$)oNL*eTlaFP}602Q<@ z%iRV3)_?l||LLPEK>m1Id9ZbSj+f5ZePElHmSzZ8&8byKdSJX*oPPZga$n=;Tn&Sx zLf^+P@d5j8Vv9wEzKtY2;*PULTjBZ;d~R9Wr{P=#JNI`?EM-(<$jxyAN(krY$giX*4ZM`$V2eebjVM;5zzIs>0<3L+FD404ErwYsXW(u)b|RWrEm@1~ z)?Z6xiN8EjWJo%euuSu%ngI=2)heF%KW6`Jj?KDYUz?NXzH|ueQeQ37Z6w~8m;W1G zX*|)C<48#2Zd{g)W;_%~#A8|Wh22Y?lFNla#Mi{13BAhFK!boB`?D78Z-NoSp@*__ z{=q~Xc4hzlc&n8KTeiozEl}^X3+BoU63c?NXUy@C9w1RRW6bWk!;^zakb+QAmQ47l zV%&}i*9X%apS3Z2Bh`dMiM%v}TjY#8Bdfr`=J{~T5cMW_)dUg-2i_@HvD8c*`#m5t ztsF28u5g}#CTS5zwWiG>Zp>_oWy#;LVcP8+6~KVTwHx!<5BtT>Dwz2lvcVoV9}WZxJ=hK2B75uPx;`g{Cb3@x+PUS&}MRmzqjnH8bO^-h&3xo+Y`R z0DDe%*QP2UNDbe=Gf#B0M6kC@lz2bSxost=sC-K%GtLO>e=Ifod>aIGJLub~|NVBA zg0f7ptH;o{|3_)LOr{)^mVLez0sc@X6{ter`1m`2!lS<QR32Dn7^_eqG>&*uvcVCZD zg@)IVu-9<%KcV1#^awD6!6X^bD-s9LeahGzOtR2M$~dcpaW0RDdkAPge?Ndf^ctT= z78otp0I8dwNFLk7bI(FoyHTjip$abi-ci{k9r=5>MCMF!xP~8lGRismb;f&81VrbU z@<{#(T8AjU=>bn8Gr&UuAB=#3N~XAd=Quy|&OE|DK1;{w*(pO_4vRTdB;=2xPrBPOE8y@wE7AIN#O5-n26^&ZQyH7eJUJiU*UyE z4CTy<=<5DWkkYJ$;+LAkEeprSya*;6#zk^Ri+x_SqHt%uqw`gb@MV=KbVlIB)s(D4 z{B#xr0}-;z+o@;NL{1I>3sq@$k(gKO!VXTmV&N0h#nm0hTY{llneBhog#-D^u04EN z(5jI8$!)Fn{z;B$>(J8<+lP)B#9g@+;b@|ave5DlLFE((R!`8=*p6ziBA=eiF){?Suylb&`c?7hoI+y4%?z znArF*JLiSGur`?MnBZI1qZxECP15xnM7^NW!=>htKR!SS{((i?+qGE^M8GDewAzWS zW`KTPVoo^_e+#ehWms+zkhjx3Cm8)mwQ`;U;vWd>+O*dH23E$uft4{L)t|`fMYZqE zEGcM<(6fnDkrAT=#A4_)xnnAXSO;++UTgCgfARixHb=I6HWj}PVC|SNOW(3Zx+deZ zyf3+Vg-?K>K*l5*jHm2<81s8p!NIDkhKismg0isomd`ubZ90>Z!@9}eXPvX}6Q4Gxsd-G#t;-(;)kH0UAqM!-^v$3q*{{fpt zD|Oi3!Jeh!d?f3uu^9z5;(dkt5W-7Ps)g44D&51dRwkC~0R>A0f^O@Ih@syBoe5w7 zW&-5N6$-r)P5_e%b7}z1-SiN!`+@cQ)iy8OjH7Esc)}<1VU>xHR?U07C3ND-8x}C# z!ElB;Pj4R#jw#H}{)snomVyVL9nV?nK$8=U=4kIEeSnLrS*+(DMf-?3$o&%@tS(NH zI3+V@qVl*-Z`I|d!t1Z97M?sgKEYPm=_M+Kz9S+4B*K^pVl`cUzHv`=c()1KI$9P% zAQ}LzP6dP>KZ!`dfg-!-49(16p~+jZah}f10Yoa|RL;ok0u) z=tQ{MuL}jB?;jC4c^`E!46f4U4_bLt#g(^0@Cjn%0!%WP|Ej`eci=fd^#~~KeRh*6 z{XUyFJKvS=2hq-i;67>0e*h;`awu?;wY(XiwI%a!2lTh9+mqIts@oU`=<7(|ROxa+ z$c-!ns=tlKU@Q~S4fWXKf{Xqvx3vkWn{jGj9voIJ%!@A*r}d71-0s_^tAiUkK&;sB zA|Vv&d<}i0wY|sxKSL(8o{c!ylX&{PEZ+H>ECgk^V7sqSa6M5|s`-EL5kT312P&-o zH+pH#sHiw5z(#Y03>?X z3Uk*qo-jRt*7!#AEdzlr1BGZ4@ah{50W$`4*ILmbDjMwSDIocZzh&h=?nQDv2Wm2_ zkO{y?0X4$!<{>22YZ^0De`2S;Uw_dMGTP^+=-ukERC04*31fZ_#Y34VzbnRhbC}c~ z2!lxk%?%~rN!Es6{TGvqXU_(9tn-)z=#T?MUY6hT0yq&N4kn$@3t-f-6<*K--2YnS^h;~ml9lrULbb_Ba4w=h`LU{$G=gV*t<93H?F#T5O}Gg2tr(e+NyUMMa-I&s^Q6 z+bU*<4(i5M1T(;@rC!Qlc7OSYHw-r;($GbC4hD>r_HJQY}@V zrA5i7j1vrJsDI6&y2@Ug{t#Ws^k0Efds0*@Bp&FV7?E_SGo7e@K*v1ayRGs4ktPxS ze?v|valet%y#Q|DE`Z1m(Hm&v{+g`yGFhp~@n2M2+!kb*tlQ~UNF-p&F{jb52*Ak$ z(H2^a&3rM5oBa#KF+4Ds(AWcrEe(!08XK-_tM?&(Ybw{*PceOceG8^un{LpNr(IZH zP}nhj9~1TZZiG#!3qdIz!*Nz_dQb37R@pzWDYwAyyGni&kOECjksmb)Us-Z;1pkaF zL@6}v-8yxP+iqkz?}>>#?&{%LuIj{HMFk~nPW#F?*PoJ_C2JPu<<7N8o3^Cipf#cU zQ3;Kpsm4=LrM_}qC$>x2D2RCOH~7MpGOnr%JtbypGCiV?u+fP$q{nCI32mnAx1_wQ zpCx@v3bYkZEgpvPS5qiv?Qezr!e&PYF*@E@aDVNcNi}5n19$sYN zF6`XN!!IyaZ-*?2%GEmVQ>&}QJDToH{gBu1L}@{0Gda96W1e=WO3^~~{gmdc#LR9o zTRz#>zfl*c^M?E2JOp`OVc93ZUp3mA?P_NnCfGnu)$U;$h4TQ-$exD%5yCWn_=#a8 zSBCQtPsV5_pQEr?WYK<>CzDN(w8lDz4uZbvlwjd<(vVH0grcFv%oDpW#q$@$i4S?; z778jb&S}Y=%ye6Du%slD?P68n3L3Mkg9r=x%T~_Bd++`9DIB<6mKs}PUf&P6B)$}y zF-m6%@92L$4-OF8{n#TLq*|kf=9l|aylm#^0e=84xifX>Ku^L#rtAvWTj6C-uXgbs ze5As>mu(I(RxX$=5KgW&j)2!W_Hv{WZYkXnLDE{i;SBLy=a>HPW?y1ty!@=RJ1W62 zZu6xh)OFp(Z3EVnp(h~)N%0-&OO9jWb1~NSDXIML@0d+H=?xe(GJJpFn?AlMu~ zw8xOy6-ay4WKc&-;J0_b1I>HS*DKwa{jbNeu{2iV#vT05??2e3E*bV@d2LB4-R-Al zGL@8OrRYTBxCv;X|J^6p__GR%xYMR=pgY{ zLiSm)<+Kw$eJ)x5n{xDSrE_g1PP~p&AHCif0NZfESFrF`r@o9BiTGidp=XbPqwE9A zC4yfls~Kvi=@NyhC-zV4O)V)Z-5|gZm(A&^q^mr}rM;x;p;at(ncW?H6QuCQKD|IB z$)GhTmf4p%G&A6n2HgWb6zpFXCGg^ix=AE!L#EF(nn}5Xlcjm9kY$w;2A(_7OYkXw z*RE7}(!OkYm6l3S<%kh8{uMmk=U4rJI zvo7O>sP1A5pTZyRG_JDTczMDz?#qF#wIwZzrYWSB#++(_@|7xkJYE#a&G?oJ?VVFk z1Ouz}gj-NNetIz?)V0giTEEJSt+6J|dMcmI>0CA+GsM>=eVoTnA$dr|RC8jQs@n04 z>+25Xb7={<$fDVRNyDijaQ4S0t#dX~-laYbk9`O{USi>=$t8r1$SB->wH6F$Z+x7OQqCzv}tmgcxnCV55QNuf5um)p1t3( zaFuf)wE8-;=JaSGR?K^^$y;iqvICr_0jmakql_1JhWRTdiySj*ZaX2eaWNr}G(7){ zYmsmRt3QCYo)1s+`t|gkHyMTCs}Or6xo!RT5Vr{R`AJxZiUfsrNB2Jj_^)Dd#V}J> zRHFHQG8hjCBD8k?s=Vv!?7BoJU!FPallQu?Ft}%41fkdeaVyxBuq^pl)5p%>Ve_Ob zchpWtol!}}j;HRf;vq_D$$oz!cQh{!-8Tug=GhJrss^?>lBeZl>o(15HB9R@da-RJ ze#XU|{+q&x^1}Q)`W&`32hsO65Wk*LQ$PE@N2_9Fv8G8zS~P%|YLlpdj&zqIoH{rK zyC*42Vj!oi7@KC;O<}4$JB7zfRJpxz?)$e_l@6nFYF+={)b@V=pTHkikl9&V_ zF-pH2dzB`y2;4$ulDeMtM;i3Fqn)Su7lH^yW*{n<8$DR$(sNJO8Pq?&K8~jdCR*Bv zAI7hyl`~>7StXb^w0*^`19ty<_mH6$*J5i6$7D!%cC%@sEzVEAH)U+vn6%hvb5o&f zdN4~Z*1k1wrY8Gy&=KgsDzE&-}rC` zjjRbq4QG<3;@%1kod#{qZ54{$FNZ@1LA(D!+giI_n^5 z^6_2nBBD%zCHY8g_CcxqCI>jRsdh+jmB@a=*WDF-05|vR;ZIxG&^)C#6Cd(Y?Os^! zJ&}9ccK|P*o|_|GiHV6dQDG=xOn6D1J~QyhrTV#f2J!nC6{uT>y>aVp4zYsCVY!aU zTOZ|lQaJq8OKO0tROaQaa`i1)8Iio$RN#IkU7af0Hp7b{gm8~p6A}aQW`angGiyS7 zo*l8!XnE%*TE2e$8mvx`W-}S|FY|-Y6M^vr)&LpvcoJ-nT%eS1MZQFpU&F>4>E?%VF(Q}1PLMk6K%C!B?xy6=5X z-&Ibflt-0MkkPE|kH636-y6_?#K7rQK_HiJS9W&m60UT-_$%!$akUVMBI_F|=~aq- z%V3iWwfj5B`hy*57{Qkr%;2-@N_4XGahT7XZH%+j5I`Vrk-&O*keu$e#y|Iuyw_K{ ztgL>#V_R3x9vxSpGtA5)vmA#`dh|BH4RIy%-H5VovS}a; z81=GEe**4%+ja;L6*%ZZxjI~&lr>9YT|^<~sa8hj!GV{BfW?_#pol*|MeL0!I@p?a zc431+K0$9QAMPAI#dc$gfmgTdkg)8O8@#*@d28xaXD9-{Tiu5|Po^Hv6%G<|vwR`j zwbx8e&t9${RhODyf4I5$+qU*ET{6NS(UC}-!D9%r1H*?z?G2Ccu`JV8yI;d-!GLT2 z@?BO{1^YXn1Azph-8?7zueFlsN&BszIS>`y_0npAtCRbd@ZhyKI}U-c>&gBaqmUfk zQG(Di>8~~14PM$+g1m+0pF)A0zyWAcXUFS)buoK_=U*_s-#u^V=}N-q)TIp3{v7Xi zHeRb=RuqYMiVVqqygyY&EU;B;GYV4!3(;l-mJKn3olZYOC1!ToK&^p&@S(N#@_AXb zgCt8E+uhI6!snuf`ue*#5S7+|*mGmNH9U4^mVNaabcpr?=$rQ$vwze3@QH%W|?4+zVUn^_8CO`$&56pH$tK^Rw6USuhX; z2)O-+y$Ms4i=DA_lLth6b_g@QW>z)VS7NnG_2KjyKWQLsch8SV%_o_#Ex#Z#w7Y`= zX~1e%_q~`2i6k2h#K63MbnBgo!UoWE6v-$-b0{v`s>TI zGkVGP5Qpy02_eV!jxBhx2i)6*U*mC!BJV3cY)`s}0Q=$Ogqq99+x-#ykd;!DjUt<4 zm>P5sfvX=@yB+OcUV=xMv1b0c;f09dNCR=K-_Op@tC^Y3eY290tgN6T~ zCBD*kpQ?8cEQuJ@5ImOq=6}*CTh8S`sI5*rY=H&XZ(YLp$e!@MO zcz#LE_=zOjwjDWz-83f%5jt?M9<`@e=cHm^;&6d)9GyG@*QFNBf@k;!p>w>taNMqG zWM-*dq=Dp9*l$nAS8DsjyE9&kc>%RAEbx<+h(r6@Uy=&YWJmefOQ9+qG zk2PyK^-n_O++a33H8`=}!|WMM$CMZ?&{bDeL{2dCoZ=Oa9Ll)2ts9k*|V z#Mdm)Ll1#SBm6coh^Fs89{u&s_BF6R5A++42>xCtS-{Ib4%T{L(Ug?mr3rZI4d`cl zX?AxzJDr<<2lfn|%XO(CXY%ATdIE~k6Mk1;t*5X@%L9w+ARd@b*C zi?_QbXTCf!hMsQ>U>Dj*((zoRd*av{9x}1~t)no3B1*ZMvkYc>xHW62D_&slN{xv3 z*7J^`muo6A>;>CYVZ5&d^)Ap0%>BC9>zr<9Lb*`40~;nhs$E0iLA2M1A;50hf7sAW z1I*{>4REjy$H-t2RBzrw#O>lT<;`_{x@uSh>+xDBqxnEp5*U}=VvoJR2^&U@(;+3) zmDcS*j~7H6eBFRdiP?vBF@vPawxm&LPE;`5zvm=IP3up|>VtBne%Io0hG5|IN>INZ@1ObbwAD5yXb~DJ3HdE+2 zjBQN0CTO(wwUOPon7#_Q2{GWI$G}6^d5)iVe*)T$F?}6_N2K)N17sO?5{fS55Gggh*q77FdyvxQg)-&nk`-T4M}&YEN=iybwJU6<9Q!yBPIN?! zbVPg7q08VG7bC0?256)|Xudqhn6O1PpRU0xis5oj6w9k8fBK04R$HA~X9bV_?c&-Y zurqYn&B!ad%FE;0+8yYXdgJ&e%dV+Gp#638IDYew-w?2FVT0yMD1bx)wr2}p)$AnI z%6xJiT@)Z@?ZBhhArp9LIUt~S|M+a9o5rvJVmRarGHEOX3b*QK}_Ya#2iU*aT{PSSQR(nmk z5(IA-)=lzRBmg3$e>mZ+(gPmS^^y9uXR_VKR4>@@U%+j6(Eo717Mg3l1gK0dPp(yI zlfNF14T^FEKgU+0-$6Ls=Fx6iWjP7JfY5pXf1ttm_JFm+;mI`4P?h2fa4~R}4I*zvQx2v^kWt=rN14;37GR_g5^06F|7gHdUSjRKGn_-Kq?kdvn0`zijxff!YOF{|_+s?P?&h7y1P5z7L;Y9W(@P+Tu!=5IC;E zg5~JOP1tjgn?U~?{FZ%R7u*XJ;k{XQ15W&nN2Oj4KuF`lZ4ULFfyEY*y?taSaWdMN z4Ub!B)xR}?B{Q+x;uaL&2IdRS2m<7~cFp}7U|-m}+Y6Qi$HJ&S z)~g04NaJ|2BX`;2dAuz!2iBGm`yMtPHZi#6o}TRTPNyRhmxW)dHIL3|@^;F#=7{F# zRZRmY+Iu{*?-gpcIe3P?u5`=NOb%$3iJAY`+XvHoN6cTC_jBt3@K$E&&XDT_GN_*h zLO@=JMF?Z{%ql#a?ZqajsNsL?(b`&Adye5(rIsXp*;1rnSH$kABR3=J+BQ>q>|q

xV9B+miE#pbb>U$ElSe2l6`IpCuFDq=jU>Qq2D- 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 Date: Mon, 15 Apr 2024 22:55:38 +0800 Subject: [PATCH 270/274] Resize sequence diagrams in DG --- docs/DeveloperGuide.md | 5 +++-- .../StorageManagerLoadingSequenceDiagram.png | Bin 43300 -> 46852 bytes 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 49c29a0a67..0f567afd1e 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -104,12 +104,13 @@ classes when loading and saving data. XYZ is used as a placeholder for Meal / Drink / Exercise for diagram simplicity._ **_Sequence Diagram_**: When **loading** saved data upon starting the application: -![Storage Loading Sequence Diagram](diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png) +drawing + Storage Manager has to load both the stored nutritional content/calories burnt and any user saved data. Exceptions are caught if the file to load is not found and if the file to load has been manipulated. **_Sequence Diagram_**: When **saving** data upon exiting the application: - ![Storage Saving Sequence Diagram](diagrams/diagrams_png/StorageManagerSavingSequenceDiagram.png) +drawing Storage Manager has to save both the updated nutritional content/calories burnt and any user inputted data. ### User Component diff --git a/docs/diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png b/docs/diagrams/diagrams_png/StorageManagerLoadingSequenceDiagram.png index 541bbb92d778bc2105b1ce16288d0d29c03a08a7..4238b4037e9e0d14868829b391ac7ebe62ba351d 100644 GIT binary patch literal 46852 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 literal 43300 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 Date: Mon, 15 Apr 2024 23:01:28 +0800 Subject: [PATCH 271/274] Regenerate diagrams.png --- docs/DeveloperGuide.md | 6 +++--- .../StorageManagerSavingSequenceDiagram.png | Bin 32182 -> 35289 bytes .../UserViewXYZSequenceDiagram.png | Bin 66051 -> 63298 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0f567afd1e..d0ba1224d9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -110,7 +110,7 @@ Storage Manager has to load both the stored nutritional content/calories burnt a Exceptions are caught if the file to load is not found and if the file to load has been manipulated. **_Sequence Diagram_**: When **saving** data upon exiting the application: -drawing +drawing Storage Manager has to save both the updated nutritional content/calories burnt and any user inputted data. ### User Component @@ -149,7 +149,7 @@ For diagram simplicity, the following choice was made when creating the diagram: - For the method where the user would like to view their nutrional content (handleViewXYZ), XYZ is used as a placeholder for the specified nutritional content (e.g. calories, carbohydrates, protein etc.) -![User Sequence Diagram](diagrams/diagrams_png/UserViewXYZSequenceDiagram.png) +drawing The Sequence Diagram above shows the interaction between the relevant classes when handleViewXYZ() is called by Parser. @@ -165,7 +165,7 @@ This idea is similarly used when implementing the `handleListEverything` methods 2. A `User` class consists of zero to as many `Exercise` objects in the ArrayList. 3. Each `Exercise` contains exactly one enumeration of `ExerciseIntensity`. ### Drink Component -![Drink Class Diagram](diagrams/diagrams_png/DrinkListClassDiagram.png) +drawing 1. Upon starting up the application, User will call `loadDrink` to fetch all data from `DrinkList.txt` and add it into `drinkListAll`. 2. A `User` class consists of zero to as many `Drink` objects in the ArrayList and zero to as many `Water` objects in the ArrayList. diff --git a/docs/diagrams/diagrams_png/StorageManagerSavingSequenceDiagram.png b/docs/diagrams/diagrams_png/StorageManagerSavingSequenceDiagram.png index a24301a47238646f723f7de51e793b23f28fba07..011b9d3c55a1dfb7515697c24ddc760f02a7d70e 100644 GIT binary patch literal 35289 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 ==^Zgti>&Kn9~c@8+DDKggyf;P z!ldO)G+oEdF_k}H&ZbrDK&a_5QgWWE+tEVDHT6uEM)Xi!%`1+6(&%<=mxp?K!}>KF z48w-C_AHk#zqJ}bw{>BJQOUHlGG^a%PNf&EO&&!eH`n@}7A~N5<&2gWGNTe|l1p8# z8yVGP>B>$Wd@nX#F|{qT zICpS7QwBRM=r&5p<&4!E4_)oL@BAFgj23fD9_l%1VZkLR{0lnF)!eyz_pV0g*#X*~ ztW$Y*-KssQ?aW>jT=%>A5w*el(RP^~dZ{a?X7k9YC*nh0)QgH+v4>XvKgJ{KfYns9 z4b)4sxq7_MFg}>AAtY$+{WrLE#ju|G!33|)`bL|j`uqD6DBJN`86tw-$RHN6uk#%# zMHSIOKME9AK8>cg#i(0Z%}lv$x{+xG`$ulbnVDr9HmnT#%hWdPA^0$h#^I+hS{&9Q z=9bZdT%m?2q=|aC7=i@4RkWW>%T1WjDAqY9%-`iEF@Y?rWuNU;&PP{p`115F{BH@N z;CwjxFTa34qwHqdPas>l{mU_06pmwE=Q_LfbNP@6x9r-ub`Nr6g-pw7Mn9^%x!GAa zBByn+S%Q^SEBua@mbo+TFBFb+UGFO+*<2YG%zU>|D)tts+mWT)lVjY%s#RpAp>SUf4M zv_^58hj{_!bs(d1C{2&UICChsR9jYE7&i&^wNCz2cGIty)l4H7$Ya#Ia9Ek3cfaG! zytS!Pm-=v?n>TL;e1)HL@N%W2u4x9`5EjnV8ox{T!xchAi z)%<9S;c$J#km?CFQIEQ8Dq%$G8V)%S@ZV`rEgwWvT3{y&rv}RgDt+>dnr?WGvtMbl zS)a5kT^pd@q%%Cpq%z&nvyscv@R5O$(d5IUT|=r%M2AlYM?{!KE*$#xd@ok3&QEqT zeJgfcGK@ruZulwOw|r)=qM~xudhj!iROrQv7sCY{l`=y3?98XSi;ctm{YlBl$jHgb zPoB)xsW_0;TN}b**J&k|s+6wfvTln^>hJH5i;L^+?S;ze=XVU5^l)u)VXRex{~{Y3 zo3`^xe5VA`DWzlvO&P&!JG-=`oo9X~dp5LQ#QBbVf@FxGOG)rjc@c8Xh-@y+@IHCh z74uH>h;lScXRp~LOHuC;BLcH8G6);Hpz4|$4^K~1fR}?+{`BikGZkd-^sq0KZ{Myq z$t-@bfnCAW1kuvc*6j5-$;@jzcHApACWf7ZLqbBr_%T*$9FPJ`ljUS*ff)5e1uAAP zuJ_T=(J?VPqs{Tg#>TU<^D+k{p`er+y$TDH*cULz!d;m-7ANjMlGc`{Dm?0?ij*=u zUrN{DqR#N+YgX*{QjUd-D9DEMzGCQH({JB<1fzxBKIh~Z0&+SY|LD>4wgua4+o^7w z?xI62gFrUA3YXrod1`5{6V8?2mO#7IV)O z3=cW2V9wn()poMF`{QfC;9zo$NTQjhHaDe!Z9`=7XxiYRo3-X$G2=4<{GGur^aS_! zI@IFU(q&ptRNp1&i61UKC~<8POPZok~1UqH_{TVH5jTUlY%TqScZ zzWUgNmu;Zkq>CRLv^)BHqwZlhqQ>XNG3s*w2db+F%MOyU?Af=^!-`P&@=JI3BZ9V! zEG*`&DS@^hqlH|Xo15D*wY6ns&klFIH=%W&vma?Z$8(B`N=r+N#qPKsa6RW2FJ8ck zN~{V%+#M0t-hBI#GzxE4t{pLObgBuRVE&@=71x zYfB?rn&6Y};An^woc>T|EhX1%bijp&r_dYQ!^-P;r#r?C@xi#oK<*1^jTTbB&y{2Y zhnJ7PiHUXme4znPqDp~fI&X02JV(#I&3Ok5ZE$~i1@Y>1*=hWo~EQ56NdGReSwDP)XKQBDO*b|+Dt)NQ1^^^gEujQv zKVQ&k4z{M7#$YffPMq*M#UWZR6T+^)_~To^qLCdBk27`|i*>5@ICbijm6er_oKkX= zF}B}>HFPL&E9&1-7~WW2oCpgGW29DkaZ-Msv%vxFKeD*7MxAHU{;@~!?&nwcMn^N# z)R!JJRh_npWAD4;e)Jb_G6mixz+|?z6jd~d8ZTddt-k6!TP4lrJRGqw`@bCdBg)e6EAWPkT&hUZU0UIvwA-~xG+=MG(Y7@UP0mX6XEDx zIZ&7CB3cq) zAgx_98M{fFhfa5}BaWJTtq|M z1hjZ7vy*|0 z>6q3E;ON+h=r{Kp1-5m*)pl{VBS(0EjcqPhx_$e$xn!qOj+Nr(V!IfpYaPj+!M^{+ zUc}SJ#@F*jh}!^{U(MB$hSVokFSPQp83-c?2?%7a(xE`JQflZMqd{HhiIXQ6{iCph!-AVg05)k`PZ%G^9}>!IR`c5QfY}ZbMHU|& z9d>P%PV8bX@J~Z*@C^k8yDao^eLSHW0F-a~^=;j9#%8;g`t0&R6^_PP%T0AZ9K?FC z*01B}8oxlzHeEw}HH>=r0*z2gK-$R+vY-mowI@hz^6+mQj}I5To7Kl}=XF}wusY9p z>>?y0clm3W1$An!@}ujs(v5|d08{Kb;SFJR?=xZNUG7}fMcX`n{Md_<` z=EVv!ZB{(o2VEOL9Nf{&e7wy^Ic+(N>)zctG;ZP+!g?f2?Pp?E^a+v_^QU=FQ(UK9 zAnlsYrCO`0tp#M#(-1PCt8QvaJs#)Q>hNtOEZo<3n~B_~WGTWGTA~_b)PZozdy)Kq`U5HW`o=%M*4xTsN2S<%`0c!h~w6^Sa>2 z*SQhVdn0Kw$fYj3(VWed2A9xMD$7F~ zU8eX`=$g->9uF;BqLty&rhA)+=PTVfa09`zJp{hD90MdN(BiGh-N=Q*BHX=Yr?mGr zQf^#%3S`LX&bnCM!gxCgu!=DUGgR9MO}*FWEM&#|*r};AcAfV^)6!ifstspe!FoR( zrxmQlgvkpaF?2d{-6G$H?=-~+vQ`%ahj;NCho(Ayb&l?<35x0b66vSoSWd}&?W&sV z^UT~mLTqP_dyex{qIpmpdhEK9!%`q~y}egPCE$>zS*TR&p`Ld7vs<^U{|HT`&Sje+ zNmN}P)DTQ{pfx*?tE*S9van3{esrzw@+vRNy6p-aYH75E_VVRd-W)pRe_5SwVQ-Ol zf%)+fSX8-n>sHNc=FvSY8u`-$HX7?pa0S2##Od?Bt|XECNOo4%sppjDK%*>>NF?x- z%)&`jc=+jo$u?K)Qt4(qX)MQ&)>N|M1eVtQ`5EC14;gpw-aVo)TpKdiC`{5sK>>o1 z%Z%Q~;V2g>Qc~eocX#*JROK2?N$ritg!_mNkzeo07#!3a_(oAFx*aeP9e{XCJ{LB5 z&3^2!@F-nh>_}J7Yc4?uo}BAHX>!J~4EV*!GT(zAmt6$R$t^amnTTKz9VHL>h}Ck8 z&e76K%KnHJx^ZK7X<=}{;KeguL;*=x%)X1bc9<8|p=#&991k-B1!Z$(bG>x4J(~R* z1&Pu8@_7rt#7${r5_(o z-SLxYbVrbXvBorhE468FWDs&70%)6W1%p2*I3q?c+RF zAbbCN4!u;f*74ZUd)KdjXo?l{TC0A1bmFEzfIaKyJdZudSha8jVl)Ty)qgL7y>z9{ z!eQ};@%M^(%)Wj5xGy^mSHx*B$;fRD0D5jGAUb($h8kJydLAzAqjoxLo~qN`mH$BT zLS6y?XRU-Ppr=RA!s4c(r8ks)dpZ4hp@g+xOf9fMPUP(1^t5H@3vX{F77lNEnkz|? z(r}eC#3IX=GXl!1`}=hU1_3>l^Hji2@7{kZG{UCDHNZq!~PqGlF1#upta!FJpkH(P7WSh!UmhiK%QhPYGo z+xar9=f=%Ixm;{hx2OsPB*z*3;bJ$b0dM`IU4%x{-HuZ)w9n+4v`c5O!4py=2YrbG zOEZCD@eo5tXUuwzsdTx5)yNtENk^_(?BnHms0_MBOwK{Ph!NQV-@tt<-x{1n{rfdt z`^gfjNnh==;#QKTsO+ya4&%0X%~7o%E9w>VF)T3Ppyba?R8iQJ4(KMQ1{5s-5|?lj zdiA8;xa&TWjeK=4MZUa(PQASb>^wXnB~L%P?(^v3-`#vI`|SI4cM zVx7HnND zg9qhxhHp`G?Wl_#Spjjt_I3F3a2dXdON_hYhB=|#_EEd!t+cHvj8HFi7GRDLblDJ` zpk-xka6%C%Pvh=IK=8F%P{7B$I-X#0tCB!*W~}Cix~@yEpi{ycsT^;qej=l-|H{=>Zpr;q)7KX-=MewJ|DBBGlkhcf>R zSG#a^H2?`vE9Vn#9`VCd+7kTsux<^p5swU}Z&vf;j#J+u`s4Vo>DY1Ze|zkIb}#fz z?%7V8h9==vS~U4u`Bgf)TRg021;u(@Pc}5Uu4fi;W&7!_q9u850@gm441B@A8Bz&) zDjt~-5ahbjdppZI$gvY`CiXJ546N+&IWMb7_84snV$b7s0 z-qwkCf^Ravj8j#8AK74&XTv2LlNr@$3jC`}D4Kp^6TQpHm&>Ohg9~-)^%r+#%A^M} zfrbtlD5v|f_~HwL^ZO4SI&}Cj6`M{uEPms6adCQ} zi@gb?a+?0=Pb*Wc`5acB{q$X{BQ0;r?*ijT#F~M6R~^WR(Yt;7z!^an7U|R4ljkc% z1*uRea{+0z;Xy%mWyIX`6CHU)MMZW~-R+uon$ptstqpUf7bv6ljvd^_bHfinJ7aw} z#HP$Fng^}y#z#-;6Qsh7EIZ8dng$1a1f>Vy8it03EobTJ#V2QdT(AS>FGx4}R$JYU zx$4)vZt~`gzEC6n(#mC}M%(Dst5z2C}+4!U&)zVnXEdM3U{+47>5s}8SM~@!Giuq9Z z(Cm9MdhUzB&mhQxkxIo-Vi*p{S#JRRpnf>t1S%-#0md}EyrDGocboD-+@q>Q&|!+K z9^>AHh)5pf>?-k=kk5~O!xbVEBKpl(w57&x%-kSzRK#`qgA=9R89 zpFe+|lM_)LKySS<(i98j=)nH{Z#ac#=xAvx6<0DgK^S`G=C+TB2=`1q&THwT+jkEE z?05P!5b(P*9uk-kJw3gg`>oYIJ(~?K8`%rJ)mx#pT|ugAf>@WPdZG@Wmy4J!807y# zwsVdbV$|yt2kQLZJMPx%C#6m1-uh*+;=reayg~qg;f-sWAX3vcj-cK4;T{$iAdEnI=h|Biu*o|Z&idHOZ$Iu3`cNTpxIZx-ZCD)QY@Me?Ce z+0|B8Q(V6Lh@9l~)ysT*>aRcid2SOA767qXcTquU=_Wv(ay@BjX$=hxXi}=Ee0_O> zaj=@Z+ddW+4>~YWCW?w(?-nT5ubI^iyv!>qD#XRbKYsiO(h#tegp^i+rOpe^YXvZh zr%(5=(YJBu-;k6B-4gl}I{Yv~2RgLuzJEUNN#wGDIImlkKdpAYf`WF7SJfya86YzE?%k{OJ`?*9$WhvVcmmia{ai3_GF?#Hc@oOc!ES@g&`*Mf z8_eMuz6T04v^5UAq!enw7O5-aL4iil5Ff&COQvTIOHR zo)XQ={(PPDJ4TWq%}^cx{&N`-`_MTaDo!I=HMQ@n3*!e590;fq_lA@S%{xig3u4|X z%5sW(_%2*SNriI0h+Ka`8~KW(tqjE=Xm)!=&Qm7pT35`?ga2^^w@!V2;_5m#I}4MK z_B<6UDQz7d9?lP?@!h+3K$z5&y{QGS2?|D~;6>_$lt8CUbxFzE?qWwEFH=)fF4$!& zwn-qe=H?mXEzzL!>m0Iugy-i}TJ}Q9I2>84I~EtCq2|HwlpV+ZO5ecX!Nhkietsut zWwl*5I2{Gex^nlUIo7Qyifw^FxNxcSz=4-uUS01^g3{Dp_+g)p0wFp=P0iZw@ey(> z=!8sYi06k3t;!X_L^1*k0p!AG@WR55H>I*J!d?7ubu@8(ZHa8ad3_Z#IH;kykM$Sh z!hy)Sm%+io4U83Nbf`(M)D}wq31YOeAY~Uag43Z&gV5r)zxr>Xr->QI&>Ue@MQJEb zu~_an0&>sKa8)9H+EF0Atn3d8MV%6vR+1xrvfRz{BTSyTaIJvyV`|&?42A!b=OfQM z3Y7jl9Wtuvf`NEvz3nIbU2;*=H@a|ghdxzm)QACNe#H1w+|_=8Q1fB6K5eO=xO2yK z0eAzFUJ*rrSglrIje!uTefIs)&!@!y8o=)yw$3kS7Kpj`%a_&F)$Hx}_nQy%Ze25) zyMeVR`VycUJit?Q7AZ(d8i^0miYY&N@?;xy(WWq0$jpZw@Tcc7!0Fsur?Yk3`6gm?0r~~DuR1hf zh}#pEMy6$X9DjG-m*(fazP(;Sd^DWNq`_%Ulbt`O-wxCw{p+nUF)=H1!%IKDWos5b zI4^xuOw4hiWq))$1798g-d=M1AQXh>cc1PC3L2K`@6~m>qZ1;y%r>?RoiiJ^ZWw^=CgDUf^5eCn53FQmQ#1#R72qKBsOvuTC;X&+Y-wQpCQvwu_ zqJ^+@^@AaXkyW2R9~nqXO9K_(olXCmNxkc81^!yU;>KWnB=^CDnv2V(s24?-!+1Jm zJ~DqE9vhYBQgFff4p zhDM{Cmt7kAtTDsGEw#`_Z_KmMrl>*oeRxa=BPu|Q`q^LAuMU71^_T&Z!APHv#7Cme z1-}o!z1?rTs5|B$101bL02$CjQWU}(j05zJ%-SXVoSXp$G%}HrHAZjkXLKl9&i>Ok z@Mx-Jjpd;xn!9*E2|x5#Nd);F=8anT-~5$t+(NS=i_KN=1S9R^o{;Zeg<8k9^k_VP zfuK|u%L7zQbMYboXw0W)2Zusy6t%RZX~kWk$3a6wgJRHa14D_7>*7R*ym{D==3NdA0!!qEpsx&ub;A_m3b5{pv54)P{$wrsRN1zO z*j_IC>0V$P&}1ws;%7qwJ)56L+%|?Xe7q?=Cnvxgjb1 zOsk2|%X)G(pb7AXj;^lV#CQGhxIx+*=iclR;8c3kT`+#>@s$;p8@Cp&)pbI}QEYQcM-o&sEY;Raa?n!P$q0&73A8w59t$jJp0 z&Z@+A#N70tkq$QsJw!|#|AP(<7|gsWrlQq0$#BP_x6wKpAYt;PR3DWpDkhex_C6&h z=7y7&kR;K*eZ#+6$V2JR4w5z7cNZc1`<7=0=H}+0JI~I}4mK8zz^J>?u`j4|n*@!W zdOz&SQn`GSo7Wj;_~5~VUjA_wJtYMN1v-+hPzW_O-5iE8g7*Aeyb#x~BO=a_k`4?H zixqe^hXvQx*8ceZ-o)O1xwF7VzdPo%=m20bcempO5cwyLAHV1_V7%&Igo~ZJ&u%Od z2uI+Vlq!u_08-iy7ZkIeZ$)+D=02XSad;8RGhxA~R%(Zs05sUB_5wT1B@e}5a> zGe!MCZW)y`m>3w?$(WY$iE3M^!cl~Y(2DYMCoOvDS!xhwR#jJzwWX`yzWoyW?ESGn zQ{sapIO2`Vf6?6AGFSkzmZga}`g=@l>}ZrG3h@nP zYcig~`)4T$NhIj}nro&Gt!_PYFa;H1UaOyE)$)wO^^y&?NRiWvS~HLU5;eWD( zJD!0*PK3#wo}PaD_VR$wH_5GM{F$74DFLJ3Pj+tS!?51I1`muz?N zKKy(7@19w}s=s{yTtHA$>5HM{)R}`Bqfb|aPieN?yVRluj@e?+VJ%Rj2_WbcZLE%? z{oL+jIPFc^Gl>8CD<5Lm(;tWsBxy+C3S$uP4i2l397IM#4{KFg{z`TWfocUgG|TFM zC8kfqv$vAIdGlt7o;8(Sdgfpe;!`VMnpGw^+`!jRv@#S10(@77W}(BvSfH=(J(Y3a z&?wPB5L(*P)$L~bZw?HuFZBo-)`!Q$oWE@fKat==g51DzyB#sj`*-b5W?ik0=la;g z4tQ`F_rfE4ZTz?uRy?u0OVrG^?g7p-cyV{%dLe%; zj{G|?0XC(Ky#2o-Rq|or9hUU{8?OOb@mDVS6^?~)7*6I7ctdBm7^Y~pOC@rC!76fc{V7F^2bCu@j3>Uo2dfL%T~P~d>UkDDEHpOO){uX86B3qv`lOVmBE%8F zXV+coB1l}aGDJyHsL*f&41@xDpI?DPk4ZgOas^Snw=Iz);;rrD7aHQO+vK$0P+B>Y zomy$-5-5-YAnGT4gv5R9*s(N6TWHe=3Tk^k1M$N{=-$0PsNSQgv1h=2$Vii(I9O$@ zP!Qz1fb3$P>@Hs8XyCu#BF+%frcOfFRvW>W2TYQMJJa2*ONIDvL>Iy;{>0i?D!)+w zfYXT&HsHKY^#)!6;t({H9l^zosbl{~snlt9AS0tY#iW+wK8b-{9w$RQMQ+{%KJ)tZ zYZmPi4J?(}>|j-nClRo}gshsnZ2rZsy1)*>h9N*4(2%5Y_aSe4D{Y#_-HT)`cfk=2 z?N;q<1LB9q%9*P@yLptH_XF!qK-_3(%{FX+45PY)0^?!V%~t^d0qt6jUXc;?96UU# zk_Vsmma$M{YVy$+LNGa77a(u)Pl*yV zMzZ_RXWVAtmN5C$#VijQIdZ_UN)vckQBsmS(Z0i{Uvbw!m2QdfBSHklujK?Qbbqdb zbVz#a7<#XnH2qu7xucpL7eV#NA z*^OV6lPQSt6Qx)bbmWUve-Ut<<}R;r^CW2eBfDu?P|hmZDL04 zqYZ^e333vF8K?UFBMNa%GVJbgnE6=)u+Xve`yO?f+@<7H;h)sk4dZ^PV#N zGf&|K+?+%E(1Z8Nq4&dMozq8;o^w`F1Q7&UU2Mtx@eDGt)y1AEPFl&xxuJkkjPUI~ zP>6I)HMB9i0yEu*yZ$2h4t%FVu?l1G`w9Y~=$X!*F6~M$N?ME8kO~_b8WQ;sqN1XZ zOoHc^mIT4|=HsY!^vs#!`>iQ2Umlo2?qw6tn*+HVKr5Rr`g0j{&0nE`BH)JPx1~lP zLc_0G#jx|zklPV7 zX#PzIZp@I}iBT3Rx%tCajOwU=wS3AfXG&*HQuT14^Fpe29ax-eSWDv?AAtBDr0uL) z5?E(H%|Mdm1j`0(^6Xdr3GPoBw9d|<>Fi?PTXLY6rzEIT@i!ye_l5=;Nr0T*6kH5+ zbaYp)JOIm^j`jRV6JX&Ds|Ln*+1d25jU|ZTgn1eo4h{||{}fbI*X$-WkR&H9?tafU z^s!HJdJP_KFLJgg58|#Sc^D(Ud6S>U{zQGIRlWJ}Y)lgBE}_t2k!ro!^Z+Ek)c z*z14*Jr=?*=ca5gOm=?%yoKF5Ah==tbzDn$I**421*uRi|6vO|BA*4|d5a1BdvrvNW^I)ptOHR@$LQ{Sc<^O{j-^X!+dn(1L)Nz#>EW|4N;IyEAy8e zxbg-sr~krD5zu(r2Qdp>Ca;-FQyT0EpUfvxJD4^&YRvvJbC;o2aj7-6D@b&4A zhjS1{w73p$a_`-ES*iSyX2+l#DPzJ~{^h1ey279T@yPSfedwd1`T=kL$nOeT2BF&Ul%TN_%hE zuQ!I%Lfp-z%U~kzbIF<>am8(U&}1{Ydu~{Y(C*5X9B(<7R*f@sWFgz^=%8E_#zMJp z@|ad6XxJtKBSW0HiEa}yGD<>@-B+Z^W+3~=c7_sR(B*s1V46dF)t_eWw%>;RPLdzD z9x43=gR3$znV!BrG5O^W{Nvp~-?Ou`>$0!G9Q^Tj1kt3p_Y*H2!FvX5i9{yYWPOGrsE)6u~iQb8e%)zm_9P(|G*y0dGp=k)Y;EDAT z^e(|c!M0dlU^5(g#q56M!qIB}gpEb|pte0d=kd@Cr;Key5JO-tu4|I4*k3M+t>*T3i=N7i+C8rJ`Ep;poKgc z9F{-Xw}peY@&~oNB?a!ycoC6Mfu){5$ zAdIrjg5^QhV{WTr|_iy8L~|b7iArZ|BN!h!~I)fMo||jPzd|7SWA}Ad$qK* z0OXVumktPMs)K$XFnS&SEnhemsGO&#CrC#vw@FP9@{`?wv^zUB*cSINPqt@9{ZH?+ z9nBOVMBKT!++MnYNx_z#=1jPH>2~$V6%ck_+UaP(ewq7Ul3@49*RNke_zY1BRlyBr z+g_azSQ~s&aN&#m>>CRpYX34*+e`6%wv6C<4%k^>vkr79fXnM{y}e&5;;%*fz5pk( z3vR-uqZ>7#xzuIjmeemsSlp+3U~3tt)R{qi!cL(p4JnQ9pa~sf_|R=fhWjsb3&A7l zWkxNNFt#Xag&oQ%!FAfLmCmLf;rY{!fhWPgRa6g2yRv-k{iCcCu?Cy)OU zMIqhVYz54CaJn@5r=bI{7;dLqwMtW4_MeUje4gJ*|U(H`WSm$6p5q>SwebYmh-3 z?hU4 z1a%7v0H8SCOs(Q_!{e{I$2|UV@zDEXTN*t?*3qL!Z&@ttEK*xhC|@>0^Md*la$ySf zm~Y4M2u9*^W5Rk{H^X-4$NoJUn4Wfe~NoZ62E)ms`8 zAcN%ekq4{uqwr|}PUB|1Z}0TkV+RKZ%PT6tiTM24vvifLPl~6s_t+hjY|GFbpPK4{ zeO2lf#kPRTbed7hK;pqBA>#^A?m3#14y-z0**SbzT2hjUp8hBwgG}=+>E>P#NJhRS z`!Dx}1hYjVw}l1S{rmSDHbe%B9r5(=syt4JDQE?hMPI@n6b3rX{L|EwpXJq|jC!9{ z==YcAIM**|MoT>|GK3*_@bWwC+Y4gVW^w7DOPxGPe#aVIv^d3CDN~D?Jw)PtJG7>a zPZ5LcC#g#jmymGs_;F~MGijnYnVF@2B=L)1(5(%Hp@a6{4%_#J@22=|s{kh(c`m{> zL1b0v*TL&ZbKLuR$=ZOUVwVN_Qc||432qi4(sFE`AxQx^2+mPxsfk4xY@j&R><} z784#l-uxS$Z=djYzy@k&a989ANVb(+`Tr0HBguP4qNofvIUXkRFn>$KhcMIt!TJ5hO z4Gt&wDAWluvb_7Px9cU^ivQ#E@#~!p^=ePp?Ex+^Wd#LJgIaQ)QG5s8;PD-h zo>LT4VUJMx@QLy`>&$=3{G(2ImA^c0_M%rBTg}xgkt^WX9(3%YLJl4+P52oxP(CfDEz>;ng>Dd#0=t_>a|RltLy8%U%Z$B7sFSPQ7K7=rDGP_ z9XMi&+hn^FG`tYUh*PNQzP2*upM&jSm6es?Y&uMREgWr~r6&+@nyw)o7>MKyrl6B4 zeSZQiuIC9tBR&n7-Q-RZ`z^cfX_6xRPY3YjMTDF9x73fdI+7@aXnFLHG*1B@CqJWO ztA=NM{Qdkg!f7;qdK9<%oiF$P@$Wdf z^VpF0j)%bGl=t4>#`JJq-d{imk7Cs-r{%eKUVXbJ|3gW5S&>_n#-9RmD5^L|%ojH=WV}`fpAa?A@-h&{R zw?bdHEfBUjwLr|Gu!!9X;ybRoHH)eMOCADW2D(g1MMZV;-unJN3r~y1>0g>mlLo{qN`Zq$0 zE7*Uq>0god4?c@S27hqnZEW}3soP-o-@@@X>i?f(>$g*3Q_fZQop(Pl|2{17eqf$Y z!$4G5`=*aA^ebCYm8B=Sh9?H*mJOE{q~~sKGw>}bA~`c1*Q?0;OFP{W%bYj_zOGt% zTldW|_;^5_{IzF*w$+xF+hc|rjqg6)rYg7*1h0Ni!80bfe2?}0$wa~RWMsW0O8nWDxBm@oRENE^lJgE6j^@8M!46+Z0>_hw z+vFk_YBGn64vhg;Ywn6!$5(VVyb!P&pgWK~j0$jAT-m@+;)MJI|D=TVAu zon6j3n9grI7GOVOt{n@abqjHD$?He~N3d_nNJSdWu2qn+!5(FU#_M}!{TY#se#4EqXxs%OcWem{fA&0HBe1c(3n>#swH zYHMmp{h=xMW^*Lb(GaA^3V}x(@{!)!N=l;KC#=TdO9A&>8IA0+Vxyv{yRH~nLPrl% zS9X=Yvf4(LDhdtI@1(9!L1q=s_{T@ZZ!cR9n>hCE-P;uO4VrPQF@yYFtbDd(dMHDQ z>dgApVr$KHeFn0xTYbed7)Jf|q39M3^Ag_irE1Jt1kqiWpK4(6Dns(Nxu#UGv-&$#9w(1gzX+zzHS$U12%MZ#s1eP-4>OZqsW54BvFGt|QqpX@DJ`DO!k%^SHuz49 zND|UQ;88~#3(0XwVHf=s0Hhp-hwp0wcKv6z;dH6<;5&jxAWDJ{S+CtGu6-6 zehDF!xY@|PPTcV0hbgLMd1d8=dc?N>fpHyT5%7_~^`Z#_=r;BPSMCF%0eKDY9JxdT zPEl^y0r=h5+`2lf61HcJyZ{;NwjF!HbzI=8`y_X^-*TRuawWOu?&A|Q2P_ql1G_e> zLOy@~Ohja@CFg8gJ=OXXfZ-qhV8nCj7K-1p@mOjcj!iLtQWzcbg{@#GP6XokJx?q6 z);nUwNamOnbR4QGl$wl{MmX!vLd~(MumKQ`lS{)y^MI3Fl6ZZH{BksKUtrReT?)J| z8(2^H`jqpkvCS?9RmZB&YBv)LT%}t`K)q1Ov=_yTxTa)X;9m3h_rGxAg08ME7*Ii` z^ejxiBP-iDk=LW8p<&8${SrdWOek@5A3$yXQmQ9r(3#VW3B&e*ydVIJRFnfIEPv8jGDCZHgToiyFL;s-onLKbf}p@{ zJ+X>!Q#@Mpp?=F`VFvF4_8EA)yT4*y7>V^+9BCpHJown;i8O40H-mZtHz&u@DV4X; z(EaU?q@bquab(aSMNkkB7=iQz`}Hrb#QFjR0uOMf{72z7E%tXXcd!*ly_(;kWrW6^ z+Uw$_OMRJUkKMp<)tm8BnvnKG<#G5B1g@P>+twr{x8dbTz=(^rgAqh({!?1}3~y|? zF6X>Phr@c?LCd)pT%vc!Cmi{h0_RE zO1C!-{gT`MqiOG7of&`c_4@lB|M!{y51Qxy-jz8Emdk+g3eTB0RXE$PeBg3%K8HuM8Y?%_-{$z!vFvfC!kp-_(LzimTbvV^xy zH|fj`*VarO9C(ReGpXXXsa35&uN%HV=*WpH#>;oYtHAo<@9TRGJ#U7DEyGce*;FyH zl-k8Kid5U*mC}(!ehC$dc!bw|izK>m+oHh@`^EVB)@>3B$ABuVudh>b-A9b4=b87E zXi5(KE<8Ok0GCyf%ciq3#;46l()AxLnk-#V7M3Qvz|lxSNhvX~Dd1KU2pgI?aOT6F zl844j!_UCS3O%Ob=6H$za}U*xIy1EeLxVUH9-oHo7SiB-#CcZG71i?bW3Z*ODOsL& zbrx(xh5`Yzd>lIsp>N3fUjFn)=AHXHIe9f#L0gB8AsxQ2qQ{Oa79kMUo#;Nbz=q@bxv0&~tGcHz`y(R3W5Qm~C=-|hC<0efa3wJ8EN#UH%n;uNXLSZN zw2dr>rX;)m#kNX(hL`i)xqGmw8g`XkZr8||owfEg0Q(-a3r12rRl#0@2Z#6Ei30rp zSI$vA=a}J`6f5{h&V$)O@s^@lg+N9xH#ujVrL>%K_A|c2#2``Mw`G0Y>Dy~-@@lSy z{r#YOf{zJyM3fJ1OH@1{QQe6Pfsfnp-heMysHgIy7J0Onc&O!Am;n;+1uL# zpeC1qmGJ}j$t)u9b^HYn0v;tJFjXdq54=0YVbDlnlEeFOHOIEOO9h!y9oWXf`Opw3 z8GZXpwg_SP+?cb*82LYK*ap&sID-@{aJ$wW$PV)lWXG9p*>{7YA&gsw|Fod96MXOr zW(jZjNS!4;gy5VhyRu5_g&97yNB(lm0IZ8b*kgEg6y@*@BCS1DnUzP_@YesR?#sh! z+`_jvPB|o{gcM~eM4gJZ1`(lXI7*TxhZLoG9#JTYqN900lS-vYa~Ue7NwaE~+M-Ew zR7BtX?j7RzUDr4K_5H_g@ArMzde?e}`?;Tcb=iYo&Md47VcldS6{;!b4p;b?Y@v#7j?d#HSFptUw41sfS22|IuY6X5(kSmRf#st zsfkuyIe*agSTtpU%)sAOsbLSE*H=it{!(#q9=}1-sLPj*2dVi+gQ?0R6>U7Wl?&YF zg9H5Ph#o)syXP~nJaYWF1T^uM8!0RneFH4`we+@|M&$v*;1&*$!|v`X{oEU$6vR3H zS0Gy}w$?=^l}JGlRsw^Qc{XK^)f@sHY>*Gs8Ddf-7n}4I$GWdf7s(VD77#sE>=hI4 z(tM+$9Z~wjH@R%}hx~LHNW3u~_FG~ixGGCfaTP_Qyd=82N{X*@DJMOD1v7#yq^+%O zwP55+M|o86eN+pj_FIjbzolM&4A|~CLZj*Z72g8 ztc-r};C)|%J(dVj(D3tOOsNO2YAR8cRptSbp zUprOR)T}`nUxYIH#83y8F*T9v&iCuBsAe`lX{o8GSfOp(YK=}IJkJz|Ko7va^-nAAjB~|JrQsa>Op3CW^ri+53&E6i^^WfS~b+v zFP2$dgfjR^L>Qoez5((#*QoZ^ zPqnehVK&*0@Pa?wsb(hyd=PY|P@Zi&?Xp6fZMm*h^*%oHY$oW{8;-dJG8vHhbox5k)f$x%5fOn1hTc3rpJlazjn3_a zTCoAN@WwrT`V?G?Arwqquz&hHu`&C4d(mvicC|3&G~|JxjUheR$u2rU)HQc(+Uc2$ z!qbv<`?WANXjNGfuB7Gj$?EPrC2dyf(V!`e3SP zHHl0YrJMAE1CE_H50s0D20%lTlYd>1oB$-nI zIV(707*vY=*_fnH(@d0OP74O}#>3?K-({I(c3c5l^e^jpPr>Ysn_U$`C7^{JzP-xi zh9%muZB(Qp1zCt;-wPWbQ=3*cGBN`C0LM~6u3rE2{MXU&#HCt1>3eJEfqtvB-|0Zj zV6kY?_s!Yy;9sv}L09h|ijJZ!uBB>Q;f+mA$!-um$@Dx82b`r6bTR8iP+wZ;QlZXb z=oSe(jCE(UIrI&6JnJ|vLSXkf9SDpdZfV5G%*+fB+(Cq@fn|VKNkrU;B=JD zUw>`yt+PF9yv`0n`_w9;8o!S8frc`065N_9rhF*Bu}E@SuOTn5gO*?LX~5|T2?;h9 z=qkax;*0t)`1-Yp-B|Zw%SFJ*M4QU4NDXVCd9yrS%Kp>vA6J=F!UgR=&GBS%Ele1@ zUFzX~!U@!Bef_?M1QWi@`t(Mf&*+BFa_1}l(!p~6;i=TUpZous<}kf|_4%gN`~5W; ztS561e;x5J(6X*qv*DIlZ|**z{)}q7{)>r}YVM((Gxl@x!Fs_8*}4t2HSxPYjpuDvYL&F*@-oD3T;8r@Oj+{!U}oD?Ss<<#6BEn-*lc8MY;5xE)2C1JzI?6r zU7;WEPHfS)KuJM=XtFEZvudLtYq(%$Rwl0;<)Ch$m)(NW${dq-oIH;2g~{xc7v=MJ zML)E7`vToRP39UJfq5GB)z#*2Z>u+de=WTu_Mv5hIpv+E<1ZtJfZIqeP8_swr;Xr` z_MO7s3k;(43TqT(wMDklY-ZH`-Ux4L!;_b?@`1@d(cZ$Z6hbs&Szgw8ctS>7J2VtZ zzZ6t-&u2`%!2IQ$EV_n(zPU=^mAs|6DF$R}dLFtl6cd!djf$c5naomTfClatAUs!e zqUv1K%}Wf+?lIMsm(2O#nt)plhpww*QVYU@U2p+)2@r;JDB@7hMNESF525FunB5zv zu47;1S8n?xZ{PbT^Lf&IscWq5S7@7X)V&>**!2Zi9N4sZkniJ5Gk%@_B{n9^!t^xL zKyKNpYp-vPR;epHl8k7}>Xq1>HV zC11cb$4RdiQ5wM3A64Illi+0Ib755VoI9}8K%;3XB#Hw!U zMC7&GE0YqPo26)Km$#62xd+0?ncrl}jSgn_Fej6}Z1X6+n#{$rb2nR=#;7CJoZ zQzK>V{_zZU`-$IA4+&pJv`L?J1fXHnTslclcTJi5{N_{HjQ^((ofOs}YW+5f3kG9X z8skY87k>n5Ltbq|4jj7$S$}z+xg`ugV!Owp|0hEU+hke#&`ah`iUo{Vq$lE)#@yW#8Tn{jM&J7-?UhhB|7REO+(t+e@4 z1(#ExYYZ*YT~AZlQp>k2u6ieMPZO_A;p>7W{`z}%9q6XHjvh7IQ`V<8oE~~%_5^8w zDRjq&&ZWUL8ozqDMk?6f!-NQaC;4TGIF0-6Oq@2SsvEB_AucWsDQx*7^y%pdE)<*R zjD0naagm&j{sV07#=5#!$zPIAlLx!I&zw24anmMFfC^w;_v;-Iu^j#M&RhCZH?W^m z&wG#?+-O?=<8}w+es?>R&xDSrZEUiy9|R6%>N3hD>VmdlD3JxdFF%HWv?b3mV^xcy zYw0;uCSX%hebUOcGe31ILX)*~SUMer>spj< zK%8w8asxn-mP1cehXyYn@xK1N`rr2zXFb&ZL?AJfimoVsZJQ=Y&mKB>u(_p0k?j-o zgl~m%_MyQcO+eMnzxta~_pW1*iFITp6YLjzK}G#!%o$VRrGV$1JZli@jagozMS4hW zq$03ctx;wB3c+3HLC4pkZxH`FLsI->o94(EtKZ68FBo7j?=szweyUca5V}V&>dcCp zA$4pyi4%hiE(WlU228DkkG|w`<0Z{S*TmDeL#3~>^yGC@r#G;`37q8Z+hOR-){ASh zMQEbbf<)oH9dHaZl%q}O6;g!W-rhX|dsQNWGbc0hKP341Et6Do*N{SU+0YhNb|fI@ zFBL`wzN}i}z#$h-%e;s!R)5ymc)PzF1X+_xD|eOuQ_QE-bZbQ`;&B6N=&C^^fAlmx zJv|+bXNwaS$zM02z7y3iw}X1bUV+=m8dHVr%9-wyUf!FCWcT;8RG~4LJ6ef2^;v55 zl|`H>a9cy?bg15L^!%7^O=(+xyFc@4sR`5bpEd1{p7g74Xt;tsS-tf?#vmR$ryY$yTUq*cOWhK)n6YHlFD9mbOIfVj z91Hhf%+vNVi{29#C~JOXyR;=ykrE=Yg4gzkG5&GsV)fq{J`F$B`ELZi?vR^h^k@I( zH?}s~(9~2n-)Ry^#YJya-^e#KqX}wT+pM}@%C3b5tIJmlO_A$vGVgvfNk=q~AIG^RKt_e>AqH}tuttjC z5f;W0gP&(E=4h+2nC~kB`&jlbigIf*HblA2@$oA8?*8of>V}*xG>874b8Plc?_O#A z{Q3yO0r9gnk!Xfm9z%4h;#?kSCfin$$86V8xh*?u7+OAv?e%M0Z1YD~)dchW`q&}X zR;d)lOpHxKL*Btt^4H1MThSWAA#jue;H?V;*ELLZoBR#Mkg`m?7i_IFy`4dC&M%9x z(%5P*<(GvA;SgTw=-DX5V^LW$@4)QG_AuE^Az+^wWTc9<^+M*ikcV)-&{8(%pS7~~ zTJ2@!QKe%ubZ6eqd5_B#B<$J9i4^g*U!Kszo0KFBtU4iI-di2<932E*A7cllZ0P|)0L6?zGWZ#0kc@?Pd}Y-Mux%Z& z19x~LyS;AYeupV+MGc0%b_c;glS2r!Kwf4h>YE!@YGG9yuVJ~&-F$y=q@YshoJtO1 z?^0%d!W63fFol)!R$$pxc`R8cm_I>9r8d)xFdxX6QMi>|n+$mcJp-rYd&@38fHJ_t zheHIgK=c^9d^VO0%&z|lNO-kKLPBEY%9RHX9z??FIMgnabJxyC#-wJ^GC?gIEO^>9 ztSPYlCd}SonB#zO4n*6>;51rSKWL}6OZV@V661v>Wj`)Oi(&a0zQwR}!^HWkjc29l z{)gk@8+Zh-clnT8v2ZY+Q_Fw1EifD zG&Nh`f}xN~dG+cHc`1v?#ucg1zq9Fnc^55sP279$8-7dTnaYI~0!4}{BxA2uFc+Sh zCjvusx5$^4MW{Ud9=HTrvbECF>53C5C&b2fLsB4i0pG?<-tHTc11m5@f*lN;&}{3& z`kzzrY)%|Y5qwUM5$S*8g9mASAKVneR;QvCeOuz}{Qdj(UCwK=fsai|5g`von!IJC zCcj-wU-|#TBqiLr^Z1WVqB~rsGRro?85$cJikQctQvy$9DC4t$4E>WqXvQ8seAvh+ zK2)K#7pTa)$8dN0PXn3lp|p_OE}(Bodu>#iYrgu^M3rUUsIIN1;6`f!GOPDiThQo< zpkt3G|2jV;@sTI!NjwpWb*<07?dNCG@~C2w^z@Xa|6zje2eA?K5F>lvy8VglR=Lx+ zn!wd=RrS=YZ){W!+SXGkIhe*$G5qS^W$Rb#`PlhT^@xnNuYsP?X4~`6+?VcY{)gKt zBGH5t2e5!(Df^VNjnEXs9sB$HS$2;31k*ED_Y~glW}_tS9_F_5=Vn?SNeElb4h)bA$}mP1KWN`!*9ojFHYrJH^X8S}7LlAe zMM}Mil-*K~C^A-_K$aJ54WnU3zOHo42&iyXh;KKe>95(xe+}R~s?w~S1;zcs&{-ZC zM$JR=N2=2vSl8XK;qw~V(brqNxmK>smrw{1`k%dT@a-i+vmFo;i~23=)b!@)cK+`r zI{KWkYndk2KA&x8i2#chBsl#p4h}j^VVx`c%T0fim^HVx!PAc*ak;|OH6QNpms_0t zfQ3;dHL9?8?_O)`4{)~6-j42n8-X(xJkjtH)^$ z{MRER_>O;+mIh;(o{};W9c;3B>(&iFmyBw$e?ERMOItg!McUr;r zL8z@;^Xfetj>ti=(48IxxX=`Heu;=}{^ngx5+IS`nH2fFP4-Uv6pdU0zjUqEM<|ms_j;X7o#o%AL^@Pf!J_O;1 zO8LVBo}h$iSgijN9aS%1{tcCCq*Ne0HZwy24J!5?oxWrhwmFr_FFxx3kVv;|xnI(^3?$>NiqtH-EU_ zotE31cI+h$k)a!QvxY~s-^&TXPkyaO zpx86k7XwD3 z)&W&smuALNJ!j{v69iy}QY8Y&LtCE{c%R3p3J`s<1%l_)mL zcuee5`r@}i`L$anFHs2Ger+Q3;LgnwTazTVE~BpyS{%z4J~5NFZh!IH@`0m@POAR( z$@8|Ne@*jDqgOashNwGi4!D?g;>gjX%^%)Pr()}yFyf6YNt#dHCnv>dKCSNy=qGD? zsfY32^7OdGL=&hyn&>0NhJ2)gP1`2nman#FMJ5qUQc!0bxGO0)`V>5qkCS;mWWVR#u~>^e>eg04`(ldZ>M~kTiY7qB&RSn0*%058v_A`_ z3>>U%4%*9S!E=%tDk?R2$hNkxI4&Z~cktKX$_h=A=>M*(uWu?P8p%V%YZXws(~vR> zj`>R&#q@ttvov{EyJb$-IbUmG%(CSr;0iEU%|;0brQ#EqTRDM%$~!<0vSCSR7bQez z2pyl`CAyx0s7|=AnxA3)Mo`y3GoE+YbBjxvt0U`j*=kh$_b(|>r5>(6J6U@+`3|5Z z8qmuZ9`=3tBf~Af9gS#AXZ3qMOUqHP$I7QIu|!%zo%%m(qaf`3*$l-yP$D)73MM8b zwC38UhDxEo4aD5?EAQ6who$!iM+oJOsaS5XWGXzxIv$>_Y~I2f3JlIG{PRb-^4 z1>`wHDB2_%Zq=0}$>~rGih363aJm;gF0|pMG+fVd(xxW577C?IY-Jjd(PAZ_?3Meb zl&&7w7qekBdS=ZKh_r(A&KZ*&_s`c|cHmjLOt+4XeZi5>`A}1Omf9T&o`7P_*_eo0 zs?s+cdrM;k8e{rg#v*vWffr>&#Rcif(V?pFwQ@aCk;kKI_jGS#*~lFJKJJ?XK6Yb& z#>bBzbx{}tKB%ys4FacKhP@z|zqV;H25{IhS0d`8%HM{!l|1*v*z=}$xQ%U|LbKvk zgr;w`tN_!u0xU#_pAnytp&<;rL}IiYPblM#p6MODJoE@Zi>=j_ybHiTbQ;xFLpDh; zn`KX#|Ec`Mh-R5V*T?{5;ke4Wyd3GCLVRGd@s47z9PaVEwJSsixLe$_*NDcCMu_k!P=Twl+&z*6IF(6wzd!<6lsbs^+)t(2e=G71{1{{_DP%0jq{$K%o z545=cQym%l-~4D$rRp08W(EwIq1ikUaL#6H1G86a0|A6M6^m|O?N1`jUnMUqb42J* z5@~qm^A?Law0|q#3l={v>G6r*i{e_Ir5#mJHKtCbtj(UYn0$ApV(+`|GE9TRj@o#G zNE&3J)b*FtlGc-#x*2y&?dYVlY4{E-B+Rv0w0f1?5xHwYyO?A%R&*R;`0qECsrCN~ zymx|BlMX3NQG`R}{obpM`HjW0+XZy{+Y8D&aX{>66g?l%0TLSvoCt?Z4z=T}vM15W zYeFbRg2>=1@N?i1TdgRiWX`U~S-?x;PNd8%iPD>Uv`~FF)8D5Ck%hK~29Wzoi#(T; z#l)IRLH3A>$CNpwAyqgDEN!L8t3=sWm*R zMCTJcxebXTQ$s@ui%t*DNNIn&5Go((rS^Be5q*a4Jq_eg+bSePwl7(P1FE$(GaZLqtJh~eKmlCx5YL-a_b+>IAnQe!QmZ6iljR^X6zC( zC2MgNlwOu_R6e+GNOOM&0isZ*2nVN6oXe%J^5%$~S=)8+G&uiuO7Z0?OPwwkINX)U%>D;Z$Nvyi41km=t;g0f}_{SRSX73J=rVM1sk2{{P z`A)xbDvn)fHevpqrp6dP%ry6L$2X<~s)eMHx!?DG%JSB1y_^?Q!kg&J4 zvQ=5EW%!-Wj@+EP299X&$!=_XwQ_ zR#w#AFgt;Eclpa>yNe8IM@ZkdZzOa#)YOcCt%}@$j+2|(C2?JFVzs933%f%jQMIzS z?it^M$`P1|(-o#JqBrHxM4=~|v7twwGRqPGE_y|k&=-l!*@ z0j#~UAC6tK@CkUHy(SwSqX62<`NU#!bBUOKTHx*L zD^*WlNni4xV3t2?9htc#Y2rJ=ZS1d2jHiUlc)fE~L<3c}m z3fe&1lkY3d8)4nG_?u5UYL%KYm9**csVP^I*%-S}E}ijcAq-j0N^zy!neUygHU@w- z{dpAI#;5BH$&|Gf z(I2tUXg6TSsnneeKc0HvGHJITZ5l3+F)S>P_ASI=-=vdxN@9;;xWrgY%NXc0VBW|~ tdmJ3=eeU}gNhDT`k^aQEL}BqXLx98I?w3VbjBqKE{5~bw#62fm{})@1`k4R# literal 32182 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Π{93U)2>hT0iiHHUf})VMOaf(1or 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 diff --git a/docs/diagrams/diagrams_png/UserViewXYZSequenceDiagram.png b/docs/diagrams/diagrams_png/UserViewXYZSequenceDiagram.png index 954b9cf0ffee8aee8990fc278eaf7e53dabafd54..05c085bdd61347a56a295207a58fcf72f00640b1 100644 GIT binary patch literal 63298 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 From 401cbdf9f67ae0f5d6aba64fe39f97522c893bf7 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:04:57 +0800 Subject: [PATCH 272/274] Update DeveloperGuide.md --- docs/DeveloperGuide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index d0ba1224d9..e84b8bc612 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -165,10 +165,10 @@ This idea is similarly used when implementing the `handleListEverything` methods 2. A `User` class consists of zero to as many `Exercise` objects in the ArrayList. 3. Each `Exercise` contains exactly one enumeration of `ExerciseIntensity`. ### Drink Component -drawing +drawing -1. Upon starting up the application, User will call `loadDrink` to fetch all data from `DrinkList.txt` and add it into `drinkListAll`. -2. A `User` class consists of zero to as many `Drink` objects in the ArrayList and zero to as many `Water` objects in the ArrayList. +1. Upon starting up the application, User will call `loadDrink` to fetch all data from `DrinkList.txt` and add it into `drinkListAll`. +2. A `User` class consists of zero to as many `Drink` objects in the ArrayList and zero to as many `Water` objects in the ArrayList. ### Meal Component ![Meal Class Diagram](diagrams/diagrams_png/MealListClassDiagram.png) From 1ec0d36b7aec94988f31264c4b3800fd3acf45f2 Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:31:08 +0800 Subject: [PATCH 273/274] Update UserGuide.md --- docs/UserGuide.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 32fbdbe25b..102c02e0e8 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -429,8 +429,8 @@ approximately 2600ml of water and 2200kcal per day. **Format**: `recommend` **Expected output**: ~~~ -We recommend drinking more water. Please drink 2600 ml more water by the end of the day to hit the daily water -intake goal :) +We recommend drinking more water. Please drink 2600 ml more water by the end of the day to +hit the daily water intake goal :) ~~ We recommend eating more food. Please eat 1610 more calories by today :) ~~~ @@ -683,7 +683,8 @@ Note: These are meals/drinks you consumed today or exercises you have done today **Format**: `clear` **Expected output**: ~~~ -All meals, drinks and exercise entries that you added to your lists today have been deleted +All meals, drinks and exercise entries that you added to your lists today +have been deleted ~~~ ## 2.8 Exit program From 8cd1effb48ad9d926b94c032e3e7d78123811b1a Mon Sep 17 00:00:00 2001 From: claribelho <110661804+claribelho@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:33:28 +0800 Subject: [PATCH 274/274] Update UserGuide.md --- docs/UserGuide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 102c02e0e8..0bb615f092 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -429,8 +429,8 @@ approximately 2600ml of water and 2200kcal per day. **Format**: `recommend` **Expected output**: ~~~ -We recommend drinking more water. Please drink 2600 ml more water by the end of the day to -hit the daily water intake goal :) +We recommend drinking more water. Please drink 2600 ml more water by the end of the +day to hit the daily water intake goal :) ~~ We recommend eating more food. Please eat 1610 more calories by today :) ~~~

xV9B+miE#pbb>U$ElSe2l6`IpCuFDq=jU>Qq2D- z6MMY+#Ya3nk1DnTw=Y?yEHQc9^H8lMy#=L=G|0}B2qf)Fg{OX-?+i(~94=Bj8C+O4 zfv;uhb&Ynrco)`ySOKwmXJkHzoNge6vH_FMRqvWRHtJN>?ZhVurJ&2+ z6y}A&y#Ny;y{qPtMh>Z0CTl6HgqLHjPtq^Gb^);6O21n-xX!_4MNZ84as# zCSN--%+FXXx=!NO?X~NvIrrnn*mj-HvDHCc)J)Zpe6aF6hBN1z!GM~d>1qor4ceh(1r1K!J?R&3RWvd-^Ex73#z!kt%va3YlJuFVkxJhY_%_1w5e4C zac>jC$PPeeso9`cQnKW+Q0)61@QL4VJ~8q1O6zjoPx&+5L0_2#pK<3ZVOhayrfl_6 z5MOJGIb-~L=wljBU-jBsj#y%k{Yp+KxNmTMv7hIH0wPb&wRP|k`{DLLzIgh^sE5-I z9fXktgM{~`fE%~*bXado&qiOlb9I-q6eJDiOQxv9X%*Ed%`P~mmuZi%( z10$^U7r%9_h|)-g(4UX*l?ZRHvzdGhhzzp2P=AV{p5M?sES3N9rl9Bo%y;)=FM{Z^ zQMYTj`hZhx?=N^N;*V>;60)uirHO36SxpBC3+mlw;Yw*&0`|?93+oU@1c3D`t#&2M zUJC=~wV{C#L%_QEYcz=ldO!DW?uT_C-)C2G)@8CW%fry~z2dCX$G6%_Z0_qYvlWND zD7Z_<4L>qJE> z^kMCEINlIYDL2@3Io*%;fLmBQ^Hui5tGR>z>uxGd6$z6=Te27dg(Q*)p-{gNQ-ivv zmj~kz0v?_+2Z#6F{4XtJ83E7j+dXtZnQmN=GKYCag3Uyk7uHJo_rr!@keGi2G3Qp4m+!*7 zA;kQENlxQUc4t*W?L!JT!88RNNK4vq2WWpb!+v;3L551!wj~U%nVX{eA~P9<3KhQe z1^Ba>Nd5nbKl|K;Ox7{5O=>r=k-W$DX7qkoiK2rfR1stVR)9W+5qs|aOzNFnt{a`|L`6@+tVnhQ#q?(sfofM@$IUF;#K? zZM%7`Fqdyc>=DHlzc>LUYs zlksZ%Tq=Q4L}4zhhCVKGp6ZZ;iXRo?nm#Bda$$1qFR&(y~sdV2Y6EKl!L&t429a=jgVt)vu`HZ7zo7#&H9X9gEvXQg~ zi=Cu+p&^&@4KFd2Q)9QebX`ElVd@ihT*yIGQC|KZ!Ib6@V^J;2CxyGhszLU8Tdz2064x++Uxn{N4+8Efp=~?BiRyV5Q&ZfOhO5HAd>K-Fl0Ylrq+AiNP#w zl(C9+t2S(;z|PFL&k{tu1PzFdv3Aq4cN?T~qqU0d%!?|{zYhvnOlv`k*a}Kh8Gaj) z5q|A~Y|vgt6brz#M;aGK5pY-y=faS^HcMZzAV7j4->l1J|``d1Cn zMSB8PVs3XX4Rg99uv~whDV2O7SrUoc-MzDU!j>VANG=LUH%EPQjg zUE0-s!vPK3zj}d34kN|)z$r;#t(Jh%_pg?#lm`7GEt=~y(2{L7PvFIC==0RGMt|}% zbv=Rer((s0wMM_KP2(xgTDO7OM8Ew-aSJj3(GykQ%Ub0Ock0mrTJqt3pZgygbRBrg z49uqJ+16g8&ledG`qty+v+D+5SUj$!B=(xQNPscS`yC|_ai1u;tkwhzJ4&ySq!L=+ z9MX?^>B=W@gyRSjo|L61*A{CWIv=#sa~Ife3{y}(zOg*R88p}Z1>U6C7kj_azpls4^!b$kpxUP)dz84D&wlTg-gbTS7P>=@6jTE%*Cj7BGwES9F7`7Uotj z=;L;M4d$;FUIKmD7U*Z{KUGXsw~??1{lc9f8q$sos3Q)( zb5xR>4Kq69bRL1zZs|HEJB8Yz9*OxO;IUj_wFlSv=;wyCE(1Emmacnlu`gElsEC>Y zcOe%2lK=4N$@6Z|QpT?2@i%4v6ACa_KbVua6e$lA&-(4W=qXb>g-!Gnv3CHBr}lVk zK#v|kpxRfNzvJf)yhupSYpE#*^A^SUpj2w(lw|IY7^|1#dP>9Y3oj?&o8a27_9B`| zk6yhE9rro*C@-&624I+DK^RA*8gcq8TRpOPLiQa$2I!UlXK?j7!_APFR6K;80Npb| zM}|~Aw23>EDO!59C(8TN$6^eUdj3yDQxF>DLJ$i{ADtI1I@>mr?x4hTGrTiH)o%k} z3O$0=ujBpn0*3R`@{WxLQ-gIDOSCvbl~Po!JA6A|WmafU z3hl~C)bbkaLZ1X@@(CR2pA3euk*DqVTuUoos+m)xGZBKG`v0(rG`T@^43q9b^7SBK z;?ce)C%b&4tloUQ=|SQ;hH=4IIl%B$^+HF6LOIoL7b8~OH1+MX|HVor)`(^f`DTT5 z*j}nv%N;kSd1|DT@O}82{C2cHnG<@!(87bpIEh?lX8>P7XFs>I>d93i3!p|UrER4a zq##N-TRr^!Ap=ChnEwS|mCrnCMtmAdwuk&BPy4WZLiayaGJszGeaE;8;CF~s~Zva)#Ya!T^Bs3(mH zBi6cxaj150XO*S!9h<-7%9lT)5P{{lDJzjB2AkuZSM7wu6zf&l{Ylwe9f`4{Dgf_9 z#a4E7B9|WtO{K4j4r$4J+Y}P-s-8N1!Y5%;@LWRd7J|R-dBAV0=|fPG;;;1_1Z;qA zsMV@c03Zc?5&;s{cYq_3D4|afI@MD`Ye%htGf)`HOoo~h_^tsTNyIy`Pvzo3l{YN7 zeYJtnz9ZJT!J7p$2uVD#;AFMPftKn|%(I3fni`gg(9*R_zxH!efmU~E0T4Ujt5Hy* z`vDh6pGNsUhi0_(aJpWGqVaMnvHZ*nu>yW7N;AOMap<<6#Uo*M24F+tqUdGK#cA_- z?2ocuC35%=qSns~B3uEW9r_$y=?r`sYm97jei|Yr*r5ARU&6{`s*Xy&6}&#%F{<$P zmtp_`i}=?dwd`*La(a0x`)CtH5kB;FAl@mP#G4LZQYS2b+GWMm=uswVM_uVpH#drq z4PAay{pFRCsPyHt2WpQ)?}|NmTGCsB`Jwc2dH|ODArzz{k~QnipjcINhB*WioQ zW9>ZmG$rZ?itnZv>ES=rcTEnbC~N^lsuTnXV&i=Zr0oUlnABEa|5IV*92nS-i=ot+6B(T9D%E+samZ;^b@A`x*nKl-Q;0TRf;?Px!$jREo>TsC0JJw$G1L((j5CO*OdX zSr>h?zAL;5iUCllkdfL~esY?mFI#JiXfKmj7@8$Dxx)r!0xG9T^k#cL^iDaWru0rp zv6220%MK|gO3*3N%{Vs2RF}wcS!`SHlF8YGos8tP5-5L{GnIJjEB~?Ug%7B3wNEUk zY<(*koE879)i={I^MQ=VdrUg|vHq$=$Hy&TG-#U^qn*+Q6%m{UqQ7HJ#HDOtH?p%lwq;`<)z`hKtP{k^`w z-*x?dpTBl}KKpFDUVH8Remx(r=j&REPQ5|8JNQjqRJ@Is*xPyEXR~A-+m5Ilb;W~d zNu0i!c6WYxDRhiy9?+Si^sWnCnYs7<%|BDj+Bgu_E#NtebpC>LZC?_F)zAAHWi8j= zX5NomWwtWu)ovm)9Yn+|+;zprMrj|P)%GMg$o@IeKG_YhR&?(uD-3K!Hix1?WV~Kgs?g78e`lh?oVN-;6l|&(@epXrJ{`t(|&ldaj zI00p;jw_*zgtfNqk@3&eL{sJ8XQkUlSmh`vcW(i}XQhNYny7vsfxk*JOtgRp4P6!l zmNOZHfRt*=+;)mZnQu`(rdh+aW|8(?&0pH)s-n|y+7+8(w~3L=k$9U^B;}ztDK*j* z%3yVQpiP9Nn-5w}k_4#PtPo^uRN;l%+LI<3ISq!Vj)iN6djz^ndJN}NU9mApcC$G8 zA-V7#ZtA@%f|K-Glcv)4vkgJsG>J9BE|)2KDU)a1bP$=ZwD=_CKN=i zB(_GTd2#`xRnIJ_z2R2k6GndX8TvWt$Lq@r`%fc+H?3r7P}dW_LHBt)STVS;x*nk49CuI{ zmi0R2Q`x$xNMaX*q?c)MN4dn0zaw~1&r|wT#I~o?qA7Z~xt*)kf58Jm*FciQO}ZDm zxlcOEI7sTHMNQ^DpjcBZyQKY3`AgQ9om z%OJk2qm48MlGfLz}#wh>#!V;DI{^YpoRQoZ-S0p zn#1MgvnkeuIquA~^A+?3Yv9Ixm;S8YHyVE~LZtM;Uo{_7w~#My%^_zz?DS3U|J`pk zrDyP8!&xxp1j3=Xv&B&zFN1n>g_!_SaNA|sA8z4>8zfXj9y3+Yrk*&Mb<``{jTdBT zg_3GbAh7IK5o}_sYq2t=RZYub;f#_I`K1IqMf70%-uSYG0yxjfhE1$+yGU!7+_E4P z{s!6!WieV?T@RcNV_At*Y?#USW{hRg56(|E+8+nyqmQnV1_?z?F%naa1|S7{^SkAU zNH%(rhGSF~`1#cz+E%1t1Q%L`3|<>&3J^Dk-$M~b_;?8LaWAmq_^bSr%gqoo6yfa1 zA!~;IaS4j3|2Ov=o7~=MpV>od*e2^g4sj`7Z1cp&$WSmCNrQXT^BUpHxP;OM$2)q! zo&U^!z|MV+GManqkAs4OqIX^L1xjuXKQ?7bZc0c<7r{oUohLI}|2CkaNx9_64)CRQ z@hbLhExYiWm|*|!Z}#~>8twrcSLB5cv9aRs83$3&A>?4(#7BjT6KyX7FXxJTQU#ac zS~Lx2SH5Vv#9?g(WtF^09gO&DUittx@D<2g#7}`j^xAujBICRe@(>{WX1AqzAE7td z=yA9xFYIyMP_X%9L2)PoHi~)aGWlizaW-Yl+rf$JG5mN9WHhX=UwF})l&T2pco5PO zxK<^>zuPpSRuq=x;J&gwiGp+YI!aZnz-FDkWb?<)k=hq$ca5mf>+8g!ZU^|u82$UH zd@mKl67yyUP(C4VV+YRd3~-#F1(Pi)+seb+5P*aTnD;GFycL8Kaqyla(2SYKj?q5N zZ2InRshuD<1e)!YhZvgKJG=6h#@Q|1BTZ(hC|$kj*Ml8YTT*_jyfQ4!*USo){sV`k z};Z%?UL~^!lu^D=6l@@`1UgAe! zS|vLewQSd+Vd=uc(rY38Zl=Bdu*uga0~V^~dSc&mb;y<2Ppof5i2lj1I54>2R)iK1 z*cv=iC080KEu|WKQz?8Ri|K5+%d95TKL2#Wn4Ew)#M8iIi-0wrPY$jz6E~RlgKj|U z*Udp29u8ci#vMEsbP;<}Wmb0MYpfOf0DogJs7{Z)3YyyF_cujk<8OfuMj{q!())CU zPVd4I|3(D=Y%=`+Tt4az+=(>#-{h-=DFP^Rqmtgmz?j7^?&KDiQ59k_0=Vtrq1l(AD=Ol^x(U z5A_Ii9gL%F8$C4~bleN)2x#*vc2k0F;jbz_SOlP*vK^o`ByVW2 z$uxl9u`>A^aCO()q@fQZ3Hd-dRBW2_5MW54ZVMYP1wvJ%n>4S%XN<#D;f|AGo%wSq z_s_8Nnn1sYvSV4(Twj;ZVTEL*&B0&!ja6+_?Y{kK)V!82t#o88M8H&zvfSEq)YIw# zleZ$^UkQJLwMU@Nc&VW}|B9HFKK(~VRX+W{h87gm&UijfEbQK3(b3e6@4u4Qbs+{8rpos18R5ag4bwPGQ*7O zMma%MIdOg3ZW2OG6)Wh1It-Khk~ka=B96Y=^0P;O{`is4WaI%daa)O9weVVtaDZ$< zBz{k=PF*mnlH*s^cipDlUQWyj zIEIlRvTNu9pmQFp6h{Zp`gdBpe{)HfsG<-pn})#*9cV+jEZnkq4+d$-FnuRk*COvi z(5GmZGf+BmKuAnXE!NgcP1bv}UT#A)Gp2S`k-lcAh zA3!1sy}fIemB-!j(R;Lx(5=kAT3~GK!HCqiD>;Zd?fA&hwfZ8sGYVOcB*E3RN@^AC zM(L@$%cneAwPx&48YF~t(Sh&`x7{D!v|lyc6#Z##PG|i(TKJcbCwq&pWlBaRD6HEf zV7?BU$otXlMcShh8Z82eZcx(uueGPajD+3BhK~Le@!Bu3;-j?yc`A}hQRsyY0LE#f z6_cHjlIItK91mfqzZesy$&m{LAoxMj;#YS&9tI&)xIzW>L47smdB5yKwsq6~H9Sb= zek~qUXpb ze(r$WG1u35Np{z#jiE9)VpjP0(Q`0hv(R7_!~K}ssNJBv|I`;qr_%*T^)z?6p3d~G ztOX2*b+w`BI$cHW0W;{CJ(iQppZi<+1O&ca$p@MWtBz&A0OHDen!prVac+XkNWKlH z=4mYGDM@eNA+<|Fr5u+FtUYVD;=rwy2j7S{jfk(4oeUfUW~-GW=@-zJSL$|^e>a{8 zJa8)qbk&GNfC2x(|MCp4+kD+y*dmf|vjZXf$TwoxF39aYz7g1MR?e9S0#gcbdL9@0 zKRDCY*B1h@joMf9J}TD`>A?3ckH^<(fVC!+z@;_=!H}$O`!K z*h)yjO3T#D-bhE+>WYYtiH?Pam5w%31zb~}@) z%&LO=XDYm+pz)^G_1nC1bay@NU3Ri;bxp1bCEZD>-1=lbh`~$tLGk!a>^lgPhLiAv zxVw*&><9y*xTi6ZzRS?*gjr9cyjmf4WU?zfIa}|wtQcM1m)6aebe{?@4GqR7Kj=aC zFFZ>$GgvyEv*@x{&8FS)LHTAW7Ajg#3`>eeq{r;_>_c(2FW zg>1c2MMVi>Kp{)<)?5rkcOj*CK4l;oa<)PRiKDFv$}pYWAgSB4X^r*NGQ}Xen2+_9QI#`FR}2?nbHbATikqw3tdiu^ffv{ zc)X|{@p8B|Jo(|jgTz~7@#q4A1OykCMqu4LMsG_`xqA5)J-iD6ScMvvjZ8ZBW*scEY{3$hr zZtw}lCz$;(UGv*yMjYS4R~n6I&-*L-iy=i56?(n59EYB=f7FXvg3xl&#s$4pPL~zw z!M%GI+S!xTSaiF*wCeyWMfB50q7mvqR`WXgfP^N9tk2?R+R~$9MF+{0_v|&PRsJ0| z!3E#vtWIe~;S~0&7Bn+gTs~Ege-uI9qRc4l5{@lCta0c zo!%wM<;o-R>#FaTXwS+iz9lzHKObl`C_H{9pL;y@xK)G?zcF(9^)$=!@g~M<{jgBM z+iW?0MT*Wf;n{S1dqpA%-@13^9Q5e$qnV#OdEWdS#4N}JOf`AV;aL_*b{d6Ll=OBr zsyzd^xhSd68x$^$XD?tGnJJq#{BPAS>5xDEn0VR>Pw|jB!Z8sVQ(ieXB z@A)?hG|}HxzLrYkMdLP;O?GRhl8XE>1v=)NK3dJc*6u4ERqB#8^V3=5`+P zRJl}beBG9LJg(x5-qy|6GCsJvoo;zBZd*~7E;+6u?%28u?-nLB{(<-_U`*`w^~;w( zx(6}{=M_iv6aAl#=v%G{mxP0_h;N9>q_UF`KLp=2nS3^UckzzIj=VqLo*ZYGa|&~4 z|4D@>FMsd%A$2Elnf1*ywo2hg32-TGS(q|mT#$m*m&W5mI2MusCX&WOPxywbWYiNz zdV29-S*T@JOj*;gCtOa1{FWQpt>>N#0UNwLJlGIf?mti$IAb?+QhoHP|h@QS=b67YJH{os}(vyxjx#Jb#QR-77D<@9Vxj%#d$ zJU;f_g=H8omCo*0NxnrBuPH)x5-w^S(m>U6K8GG`Z9`j(K(EwDw2k zuWFt9ueU}IbX|fuo9_;>TMgug>5-iKdS>Y#>#u!Y9)rQf;^h=w!%1l}ZlPyn1b*Bj zotjx$Sy-=GTw-xG9Q@?HD2iF7B=*_xcC7?1u5lwC`FFMY@0`oDt@}jhRdD)soGMDw z2&0%vyLWXk(`c?rrE(X;l^+CSdZ&Jz{CZ1cUDF&#-rwTIF7i^rPc8}c!tPd4o+ZvsoUDq=@!6lzZgK9M2l7jM-gqg)z`&466dG%>wqh)Yo05{d!{1ta zl~qDc7d=$BOOIbswRodq>s>*K$_E83B5?br%Z!d~Uqr4s-JY?%F|X*hL@i5i99f<$ zW*6p+T}4R}AOBJ+)9>g3p9N|AX+2pP-=UqVDmitf#u@VFE!7D=J(APv)<}p&S;DZ< z-KQ9gj3l`5@N(%0t|uKMM^{RgrcTDPrLpeNAGl^WlfX@GNyjn@oboYCWk2vTk#;;I z>A|4&ox~!AUx_yiZa-vbIH1XKQnQ<@#?f&MDl}v$+Nr3#svCce(8RS4#^-V#o#xBQ zX6>Yhp5N!Zb;Wa*#$+(<<=3WU*MpB>pCOj!gIrS@*Ea8NtAo)X7pzP=7m=F}sVYv? z)N;35R@GW8l+?|dx8Rj+t;nO{=X@Mj7_-U}Y_g9PbdM+QViA{3k4raYPn>_5J$Yd)|L}adBT0#NNVQ!@ zBducK!}fO1_)MA9)ei#gB3rz*V|nTa8tu0ZVykE>4SqOubsrrGy`0-P+tY2&#Ttt* zNHnM!@ds;5b30n9n0&dx+$WcocE7B+bipV`W=IF8#UiV{YP9y&j4e9i4qco$~XuM$8>Wb*Qh+vG2!M)jMHNQi`FSh&0*T zpO7Vx`+GYsE@W?Q+{3?*Rr1X!u&k*o2bpp$GuBDlM22l8tmWbP{tk91sTb#ujF{1_ zt__;Cd>`!+xdl^LHj~?7+zW7(QPFgLPMM)!nKGH&n8*;D$xPvS9aD@^Ol{S zrLOK`x^p~=2aYi2O;1p*@B?~|3#7bT;wL6_MK^aFM2~1Yx`^xUP~LJ!91v7HA{6l9 zzzZ`va6Is$HV;ucz>B7yPs*ad3i%IfQ)yk<2ED>4ebtLnIPUf@r4ZD_k6K^-pWf@Z_?_RBe*aFy_WQq{)IZ+P#WlFj>-x%=%Fn~nI@B`Fnx?ZK zyEAE^nL}QbD`I4#mb|2JdLZ;2O1|6k+A&_9T1wi zZ}CxVNJ%~irP{bu8gUQvIE@KHE99qC-nE;AOe-7UG*|MmlvTQ0KKW#s=KNIOCPO?n z<3XG#jJ2A)0G}9+D50rLT|$JSW6mcQn=L)^)WcmGYp=6eAhb8Zwzd zr)ZR+y^fxf!sx-8uAt)lu}P{K6Ba!fNuxg6qN|^KANoiT8A~g@UjW9x&_4(Yt-7P= zL>l4NHZ6-}#%r@3d3Y?7Wp+fMsdjtNilyr`UuN$4OZw8$x;9#B&Kn}jh(kOOLL9<5 zAd)E95bQDf#}jUl#LC6d2csnn%DZ-XWV$ z7udGRv%L(p40KVnokOZ5JU$=C1XpEONYsqKS?FBPbY!g;78q>46&HJ$!Y&m@^8#0n zI&hU)m%YV|0XiIGo1F7l*hz@!6KZ$1y}!9}1V&R?a?f4=K`pS}ygY)1rOU54h1C1M2Y(4b4E)AXmpG466y49@t&gT~|UW zEsUXiy}9St&8~;AO!tGrXyd$@m;8|HI$BNZ!yH$f9!9s5HTWSbGZ`|wHv+KyxNB?~ z#?|LRiQr*bb3NZ?<`*<~#*lc)_0wT^b*~USTgV(ny0c@ zd7hV_gu_nOk~TX&HfEl*{o-&Mz@w8v;5BOFG325TnnFttmFLrXb-(P`Au*bgvT@PQ z>Uxfzwd+a+;^V?+P(s6@M4vtxvM1qX&f3KJywNX#Uq8rOoBKN{36kXywt~nE$<~-QZJOR%=^aslu-=rG6tF!Z0a;Y3#krCIhehg)C z9a~aA+-E-!;QM*NcBaU*c1rE7b*yGjXt*Lpf=L*-%xD`bRLCVOsu(ApmB_qDHRvPN zCoEw<>sf3s<#>FEyeZfCY<6ZPeLv6UT=of%#gtDzFTRz*CH^j`DIV>!kFC!x<}6V$ z(@`MZ^!%dwlFMO>t7ui``%kUjD#u!mVjBAbntg+C9Sxmr?0$399&sB@GpJ^^ap_4` z<`yh((I}^$n5!@TaJ1{5&W)Rg>8l3K+`$w}J zTU{9d(ephszLZa2E5h(0Jw6X(Y`BHGjv2#qS6b;@&AC`bF8Fz%INSt9E7F}V#e}bK zECUk$DXeAohL%kz>f&2MRwF^!o?~WtMv3hBp-Th~N~ zs_6Lp8p@w$9KJ8M>(DQbdo<*X&;F>GsG-UwXTp+=o)vkJdF1{J!lK2sRK;8y%C*!7 ziDoZ)d}pyW3Z904LzTT#mPzr6BnGr4jb5+CvblD=OSvEr#1_Z%8y07Y6{UA$q#Hp+ z+i>2u9UDy}RNLxKCf-SJjwFvHQi#iX6f2sQ35$T-OYH_(@FJ>dVc0WuWRFp_u14clL*LChZfbuY@UQT#={BX8I9O=83#6!sI>I zYmfSDqS8f`uX3O><><2eIA7pntYCJZjHg+t9e)j9;y~;OW<|L%ZgyLL*M#byUd>~1 zj#7B66rlAueP2y>(R-Y>5b|Rlh-90X;3MJKK!on_K0V7C$7!ri3WemWsKjN`q0ojl zq1@b{zR@U?5zt;!eKn3ldwJlF^(-ylh}NV;*FwlN)FY94+ z?fB9^a2-M zL`_fNg${0P;SHe*v450hbN)!k20dec#;!QashKj;V#**x=&Cg|jD5340$Sx6uu5)I z_+21Z8n&}y`>+!l{*!5JYD#t4>O`ykhTdgM#Ea+Q$bLRK5f>L<)L8JH(BLR%`m}LL zSei$q^y_}nh&k_fLi!`3Wsi}?{tby(L($bP;Rn=?4vsPOHNAL@IB;~h({f2JeG{Q) zQe|c#HzlvBzn=Gh^&7#8;J05;L+tu*+rNh<)d;2`NPfUq05)ylCp< zyHlztFMmeR+27VE6LZ@0(fDCZzm12vCG36iA+<)DM$9!MF01Rzx+{G@*2H!8V1Yl= zz@8OrQ|yE%gj1%kgQH(|EiVV(Vwf{Pg_FTlK@7QZGEyV5riP7W94@>FCk!bh@Hu)0GE+6M{NwZh1h%=@4>K9;Jrl zSzYDNO$8kN(bdrp1`} zL@ZXjzCJJ5_Nq06Al6Hy$Do_HIP-}t#=vPZbW$=KFev)nKq>!jpmLsnrZT+B#9u{2 z#&pZJl5><6BIY5+X^Y96tVm#H$Lq`-E7h>FLV1A$@&^%1SIpdRqqV;r4B@SyaGg4yW)EIqt zT??i>%3*T&QZ5{dn$y;aTR3bL9qm8d_RZakx!;ZaQ6jC9;*kiJG=?SY@W*h!E`LKY_WUB$xKbF&lwHt$(N6UsIK~ShkDp1&y+Ubm%k?r zU-~}1lF%eW)BOW3GUUhU1wRi{nqi0{;Xox0b(rflTqHT8TEWxW4-8O}DHl?P$YlmZ zOfn2ppMT!}KD<*BNb_po+MB(Ra=%i-gYL5#Nu##UZU52MK=?=2a(?wR{#NvR-)#{U zk3T)&wHV*d6mmPAIbl66#?Rd!=}43Unofp*wSZdGaAO+s;VgieAr~x7(4DX7=h_s` zRbs$flUNRY`trl4t%rwepTlXv0SV+tyUc>MB?17C;aDPFv{NR$oqTJhrY}iSqUC{ zr0)q6KHtt^7+1_&br0-6AL#UbpQWY&Q>O5N^QAlw@fy1J=CCt~FjHC4bs*USwClLD zWNJ((w#S+$hWm*wu888~eG7hq#@YkbmM#HMM!VA#>Dx_EKvYQ+e~DFcRurHTt5c$_t&Wer2#8LR{PGB!1gGLJXr7@O;%_CEVVTBf)QoZi(-* zTiSxjmf71mY(Etc$b9};JM71mO8-;6Mzhcc7|T2tN3f!~&ff11Ct^=tR+R9j$XH$a zK@YUP_3{l-{Oc7=g2yo@>h1l%TAWJ%f3!IJ+gms}XiuW)>riY8nGPaae)btzr>hp; zm!-F0%4TL}Y3i#}&QROm+L4dFOZk`5z{E13Y_fR1a&4glC@kgzskRXA7|Gu3H-^%I z?P@!j1oQr+Gs&-D3$vuvj(C%_fQ~=|WhbsxUR_XgIM`=@8aC=()9+JKxV&DJzhBf8 zUr=#3g1aw$@bsJE@?!4Yc|cQxiQ}W6A-~j zCsiBi@|)dfJhzj02!I@rJ+4;Qnje0Y^k~gc!!cSS3-Y1H5%R&j?;97D3v_%0lE#wp zn6E&bJb*M)tr5BhTAhC6n>Rf-^*n&KVdiQL_Vq&Uq3t{KK_D@`8^JL!UI{+(wJCTI zSyTqKguLGUIAUz}Jmj#?t?GSt>hpnXpm*BlrwwOU&P`MHuuStOc=~Psm{)G1e=L3Y zd`2W@e?FyBDe*MjHWWqRx5b!BqOQjUBya7RgUjUP}tvg3hFdi*+wzqM0of zOQFwys5>pTMYbt=;H?>H#ISID(_LKAsY@5KUZbafLhZRQ0_p|IfJuGWog0yBI~jM_ zv2K)M%nn?M%d*20CibtO>7rl5H~}T$V~x4OO50d~QY27ZAZ?HPM*1js@U%1|8|CMp zt?KNq0;vLsGb~RirC}Z$1&4!nG=rJoLuDKgiMO?Xc)rWb5+pwVcXL#{8YoVZW>4Tn zYCOX1?d?b4R;KcaRYg>;1hKi~df`L;qs7@~vR7_txxN`h)QS|mOj#pG0h)r@7H)wJN3zjeJhof z^(_7bETEYcpNzt}I4+YWb$`WjC#QbT(TfW(qvT^s?9eb?cl|)%9i;6@3#l7Twp}@7 zQSa$V%t`rfBkEpR4k`rYeMyPo=?RjDu;9Y_m~Uxhx5PY=7HD%8redzdaUiju=eKKQQzaJ&NVTy$D` zxX0(7xuvDvfic&8{3j8kP2vgOX&Cp7U$!oRLVU;oY4eJR<)t^;x!d1o)UG#gn=ScDB8)j$pLnCb~@MhA*I}tO@N4dQu}0& z$87TL4~xAG5>!9P_nED>{I~%TAlFzYA(;-oKB-s{pOahTn$*jIFKxUndhaL1z)>p%=s7eOG7wAbwUB|d7>wTh z@Ey4KB&@)Us8Pn(BqR%Mc$KHAm+IC`k;ulJVuR}W7GfE;(bn%a_l|PETPu!kgSETt z&g^xECM(p|G8_AN`3!HaKhovj*;E5^3i=wMj|x!Ny-J=|sE_9xm)YUi&z~$TWMi#5 zvsN_|Y1iakbWAiYk7tnA4NUwAnSGEyILr16)B`5~<)ES{SHGaDBrv8-q@_EQH}e+# zPpbnZlJEP9$V%w7R7P_4z8a?Xb)TxIg1#oI^`)V=cQM|%g}QR`oZno4Fhj6#iA+-r zst(o`=-pLOidfB*)NiBRiT+J7{nZ z!#R-}$nhfOaPGbyw6{O%x#X=2AxeF(bzMV=h}XHiB39n)k3Zy^FU zFd${`5{167r1vl?EDVNP9zE-rG%-0}Nw^S8j9Le=#-waLnlwJu+@w%w2G@5=}} z{49K-oy0)bE2LA3>u_KPwYGxQ3L3m@no;Tg9y!Yr70Yr%Aa8=sjpw@i3rtMQ&xv?B z@N^1(*M_NVH7rIlUoTg5Y)Qd_F_;hbXLc8_f;T74iegwIa&e~bk0RErPY7f3Vf7pa zQpBZV#(0mo-ng%H@}07?nWl4g_&rT(&E|C@^NQE9(9b504Wi;Jo`tI*JqqQ|xd&gn z|F_-{Hfm4))SfE2@U-gK?BvVg*EOlH*C0aW>gf5grAI+0z7M}a)?I|c)y<>4k^?q^ z-eL2Bo$^RgK~80CGuVlDZrcOpsZJYHrlL&KL{HCE&i=c&@fB%w-_?+G7u)rv)Bo5K z0LdHh-rlTlVC7CG28gS*o(~j^22o}d-=}p)6ObJJ1rpmVSe99&xme z4x0AShDx5o79pQADO9T!5+M0;VM1k@;7)=&Wb07FrA=&$fe}llyLig{$iq%>XM0O$ z>xq(B_j&$G_1M^xbLVR>C@Cy$*M(HtX+r5&<+ReFHkI;z_n#PI)wJU@4XCb8;W~ad zP;~?apSKApKdXW=pcN+w8#yQZ0@|kzyefb1I0NRiEQ5E_qrlnlYv14yU+6Tk1^lMA5eLJxv8(DSF(bm^5^IMC98#Ec~%@|d>SA%X1HH^)e#XhQ_8WyofEx9_A&`Z=f=*dKmV zXhreb*e2DfO>37zy$3O6{(=E#H1rFTOCu2x=<}8Cocv@?6XC0{S?`wg8Ee0zlhRd@ z#}pHm!l>vrOo)-4_%PdF0ucHapx`6)#lb_7C!q`9U)+XALh_w~6O)lGBNw#ChX^1rak33+M&jb3^`Dv_ zE##ap&&<@ef-2zjwHHJO>cx`z-i(#OXS>*7fP(0cWW{Bmi$!uqz?Y@Au0TXyb*-is zy4)Xdy+UpC=$@)dDO7V1nKT3AN2`+LR{=qzb^u`iZ3IxU=z4Jlcxm*nbGk~wnOV57 zOJdJ%I)oUCD-ss4B4bEOp8v$S0nBI@I*&Db`%gfVS0`FL2X;07 zJxEFA8CKDbn^$o}&S7$H(HNXFx>mKn2N#Q&R>I-5UDtdi8FBd_+zG{Ug+DYkBVxHG zIy#7Z=^8%B*{?ogQ<(Q}an-<2X@qe|hvs_6QTzjl{A<(G-4m%LbcKo2GRan*LG54H zSb3F=lc?{qyM;03e*bN-Zw4*xV%P>sAW`u*BaH1gU@3PnX9NB?mJKO0%HiFQg@xg# zef^N*?}JToPXANl!TwOc^&=Y7Q%qKRYa+<%qm_^+$-mLZQswxHzB4{dlMRK7p zHgT$ewI1m?VKjSxtgdj(Tb&9?Or&mJG4u{7C@l4!)~8ioU@L6uSs}P0JW_+wAZJo* zUZo>zEIZrzELd@GQV<6)BM{plNq8C))*%oM{6q^q?yw2DeeVCS-7X7_Svr>i&2nJ8%Mu<#^rPPi0>u z%F2%{WDN1c%>6V#2j2S>Fg!W7n8dE@buZ$)+q^jf-1lsP+US+FA?0 zw1JT$Rc3>}Od%vzc_JmpEO(`~;Pl~NmlKaZS`USLv0^?zZ~&G`|vYOxH! zlKN~OHUMtrO}X#|D12H2e7~qwIxg=M4)RyV4{u#q{;nErTaADrWxym}zdIXFt=E<` zH7$5xcRZ6cb0U88JAg20KpN9v;7;HC`2S(jZ?QUdsl6pc^R-NS0HO{7FD#5BVy&ml z#S~*ksur!d*9t>B>YBu5Mu|lZzCRsvU@;bud-F1~%u@u!MT+Ed7Beum5+1XmUkJ%a zRz)Kd_p~b>72HFbR*sB)FqnRD|4u`QlgER<9P*cnmr^nx?ZX5Zi#jEtG(DH1D}9yf z9A`YW0A|I@|KvvH_5aF^)V%+l8x6HXwN#y*ck*t^G1#Y=)VJm2ZpR!6Es&wiv?~^d z30_g zCdUYT|3(?T?$YLLkYk;ju)%&iMs~vdjz+!<($0?WwQKIjl|LEv9FvBeqth?U?Hj;H zlP~h$Zf9s--1X_v`ye<5x;!$+ejm*$+QB6A-&**=$gs-MnR*QG8wL&iUSYjvFlm(TV= zTdWIY909dW_Oye501r8Bkd|;CY~wWB3#~njV2*ptXGOQIxtibJaqI0bmDXFO^`m@*N!HL_P1DMIIs2wZ zAHBWKyhbKVtlYzZSF_!Gaeg*kN503vf#)TQC{U}aMZ=}a3%hEKpry3WFh5Fb0XR65 zY?L-`?<4}@kE2j_Y;d~|^YGb&t>30}RI9h1H9RR@9VIpAW=ySdLf86MRe~YRpu5Ey zBg9+&_H%=5lg1+Bh?$+xZ;O}n0kC*IRAL=l#{9_oM~>>DK!3egHrKahVzOR*{SDHO zR&ELM_QxAdYPc>{dml%wWm=e$73b7<6Y(M9r_Ic?t?5$LaX(YNL!+b+s9Jdq1Pq@f z$ImG;`z(lngce`^k1=>nLw{JN7A(pZp7jF$4x(7Z!w+;$sRT31 z%o89^r>8iSnYx%j=d83VPR2+Uj0t=KTB9=%4P^GEW3hOD*u)bRgZ2IKC8){aUT@`+ zAQu}5M98Z7gD_K<5|TCP2XzQq#ijC#R{dQ5S)R7Q#yax(@yQ*KeC$JXQOFOeyd~QY z;k~y|(Wfz55wW&&<~rd%)vBh}vS_6el@uE>tMG{R&SBLS(spzo($@IFM{kh4y#kEO zcVs4;Mvi_25$XhAV%&Bh3;TW*rDXB68fdJxs3~@$f9@OQ6 zb8-|FMV^xpRj>nr8xS=+m1{|s8J2%fb}OY30c?E~mA5Z|&Adu2_k@WW?Ing!kreQk zJa!xt&UgXQD{3>~2Zq5|r%iTcz|`8O#7mMTXi@tm{4xj@EdZD@4k_17G{b{IRIf7# z{(*o)T{%*n4$w_Z*7-@SVjBR-Y_*6YaF*x0aAWjl?p zUoaO?L;^E`6Peb$+dS6H1%xsE#UGjT7c`B-@#rwW?g?1YVkxBm36DMUNw?a7WoEeO z*pMn!fQ!|xY;FX4c#}Ml^o3uy$4mLdG4b0nWxHpe%{8!0QjX3`nDeCRsi7eKXaFR( zkJO(H9g)St4s*mXfr%?d#Ei@f2A;+uz-Ps^pf!sQS2aQu|qHIxcYsoah+{0%QD>h5gT@8I0uu5*@uLHMy>d zEd5|jjx)JgQ_^=AX!Qf%J^LJX!L$1q|tngTMtw5b6QW6?#*Wp`R_%bP$H^IK++b)1h z#BDhIy3!~rlY*J0wiBXSJ?m9g9PG+=oA5;8uWTBQr~b-^y1%%e^@Y>>me^9>(s0a6 zO0xo(!4#i|?<#|w>?ffZpf4TfaanWDmdtWtS-K*qU~E9GxQ$Ab3q5cl)m>bqo~gf? z#5bv&`%uWbR-uh;vDe>1Ju+NxsM@^!Mm&!|-t!ZA6Ynx@hp8*`zt|#(gHN?>dof=y#h#q> zmod&jcwor}T7Er$g|{VEU|9dW-{J&6mx0q__W7y^=s z=g&x8llOy{KU`N5mz-v7l;L^S$PkY5mGnZ`L=WzNFhjSfYJA3)3BMw?_LjQ5)XK0S z8-q{oL}`97?4RDLhin-TyUv=Li>rg$hI6Fi?KiIje0I3N=Zjl|fW6Rx#^)?SzPFDCja7+KV}eI@^GQR!uf>KMDIpBc~5?LVy+o18DwZQg@90%TB9qpQajXQ zs!rBB_JI3i*wJHCgvI??X&vt5mLJI>7yDQv;*jZH=<^2h{L)MbyY+vOJ*msGu|qOL zaI1A1U3c-tI}m0m*i06=Ks)~%v=wBn&HCzF+EWp_?Bp9avfayo7aKn!*pIOG$H7gSb(pB>VXQ211$<8h2;1}-FzQtp*^^>^o zvOitbUzQm+8<4ExFmsoe#kD(tT-_SfRz25iEKssT=k^p@K7?t}B;C%QvkAU&*L zFK{KFGxmzhJtN@6&gKiCZu1aNWCjwK-*w4VHf|Vi{p+S_aMc zb$A+(LLhPx((z>v6qI#S(q_4}??YqOO5e(m8-6IBraVeW1?+T4hT-4PJ2H+nQ9Lc* zltuva7|~Jy-ixaS#mB_!S}Xnv0-5->^S~9CDPPaa)n|>JJXza#nK9Oh0^B|+RS;6p z=o*%Ss>2$A%ESB?s5dVi%wt`IR@|UF#$q&cxFEc`Ct}dWdwjb^_rk<yoy);MIC%sVok!_G(CSO@{({Mg z+ENE{03Ncws}H%}72_+10ut0T$Dt*DyJ!e>M;>>Pz6PerTV!$3&`!D7{|8wuTKpxT zCacq6xz7>?5P}5O7m(B}j>9vX-B?-h*eLmjf_n5JlfwE#Uiu1VQLe3yin7WH8j&)H znG|Vd3ebb>*Gk=mzs$^>s~c`4f70BVUmCkL*7b+Vs(kappnTi?>$6;mj45lZl2q3h z)L!qbNcAOv$#niN9K4CpNA}v3y-XkUjVoWGb2Q~YLc;q}N7JiZ5GRVAa^V%``O`fxV$z1`VM+v5j z>6iBODCu_b$G-h|vQ_0MAO;&Q;t58{;v@_YBr(3dVAI%FK~iUW9+nttve*3?c^2fX zKp9vmdxS1U=;%d}tVyp#EP2w+^YeX50@o9IM`;Ksaa37?oG+nynF-~vaT{S^e)x{Ha0Qvk*$+Fcf=t5hY`h=$m)%jD!qr_KAI z1*B{LS8;Z1uPREd-tRJM^?oCyzmpFUwd(7;f;kD?##bGHQ8Oy&_Vgrsm1LAWF{!5^ z5lJy;%NWRfZk2ogWY@gItE39yE|v*TQAx1YF!#2<%Sy8@n^Rm7|3VaIqV^BHa@wsw_k`NV%x@ zK=JD2J$@A&1NpkPTf&a3Ye}g~1th2bsv-t%?rw(OH@PQfK$*hes?7P7q_T8%Hda6W z_8{`{Rv?#uA_Us;7}ez%Y-7;l*WlFBYg(7nl{I3AXh#sqR6J!&1Su1tjMmS<4I0Vx zPbv=jS5a3b2uUFIf+}CpZ1aI|)!4Hx~?5j$4Em3BDK`(k_+=m9v?Zn z2fwG=Iqxc?)kvJu=@-YM(yNB+8S&&vJypu-QCrg(2?6Uz?j?OK8WOTqwgBD!V_AIo z?!QoI1J{hx`_eD(Vli^kI4$;|$uVT{8-nywUHZ7?`L}Z|ZDpp~{9mBav~Ob|6^P1fj9Bv)|HU#_zcF9x1UeyvL%ruuBr{<>h#!sC&n; z?JObj(HiLTvAXkSU_6uDHrs^w4cO;n;<^#QmAE(ldW?kV8TU#CRbi3~xcUxBqMJ zS9|G>cL+t+=HlEy%XWdvs15L)7wTrWT#v1CVRsG!{|*AR!d6BGNz?jIDH9I6lb!9C z*TFPde`kTEoHt{dHv;kF(N_|P~y z*wxk~k0pKTg&PU<;@%I7sq)kr3B!;1e3+Tj0Y>AEYx^e>w33tsOOmDoPDQ?2>}WTY ziHM6degB47-!fkUOrTDMJIzm(mrLd474I@ywqM(K>!pZ10JGI^)E2J z@&CsI^&-hbfOB^)$Sb=Yc1->DK0^nR_cu7l(H%?Aw!om;N#)P3-ciRl&o#HcY8jB; zP|3>3IFAKEWzWEv)I#n66VWF|tpBD*i&AZoGXB=1m3g|Q zMuP=dKOX?A5%25yic3YaC6Bn<&+q?XlFppp@BREeZx+mOu%2}L4vI)dYu-j_a<&ze zY4@;|WIl=Vggfv$o2yU0SyNPTuGh^b1~D%n(dAlz^+T!Z@+oYxosk6@f~g0FY@M?1 zB0c&m*gVjwBk-_2c6EN15R`eiDpHPDmhsf|JWgn=TcVwRbns%9GVOU#Ce)I%3pCyk zh)w=erB~z%Mo8iW(b2X~iW>d#8!-BK!lS!&St)eE9PQDEVnTKPCDXf4Po6Y)-nh*B z)V8ZCpVvGNevAk=)8mJ*l;$Ue4c5X?$8f>4;e9X?N?&~D;}sx;gz(u2xo*{x{q|JP zosK|MILi6W^BE9NVj^N2a|n?tzN$w4SK#N+!I!^;A>#~WbHKzi0$wItfE}#Y7KpdT z7h8~c=U(D3Zq0(h0(@7bCaHnWV31*|S#X3mkC(_R*Tv!tNit|DzHwSou$z0P`&nq6 zl(=Z4uF9vj8dR1%w>53!!jR{eF;pHzaL8N%Vng>Nu|xM`AqZ8}&wu2cX?T}%bGYPL z<1brQ8P1aSOWkI8c`nrfCX;9KTcaL~0*xzg<+aX@;h(@xsX7s^)cqe^`Z0DEsC$mBTw42^$p~Bo`n;OcBD@F^$$qa9b;72Gw9T2 zfMEUF@syVJvyAckg7uakzW=ssLC6Jk8o;|-;TLX%`hdI;1`4}tQ2oH2K7_~c)twC0 z?Q)cgncH%6b9YWM=*{Nl_Ds{vNnkLq^$05JoiR0K=h91a_I^A6<~YdV*RTgcfF&!1 zk%O&c&TBk$ghENA+T9rK@EN(jQEQ@cTss(eCV*4ZDc$P`oxcI0eS~D`8ig9AYwkkH z9Ud)JMUWLIsSIN4%z2^`#2X6>0cH1u5GS7*Vp+2XZ+p906hHJi9RwFBkZ14Tqs;Io z<v_(3U+>9 zE<7%?LoTE+UC={Tl(i8;qP(bJAdCgoy+rngR!t{vuuU3%13T|qSPeoYXLt!!`M&fF zExqo>?T#1&i3>`5ap{4(V}pqL&UwOJ-K(cC&#M>JM{(9k{|p~l8#JMvfXQW$YB;Ks zL>*o$3B4v11Z*PI`C~pX*rPfIWLc$iz!C*fZc!AiJC zU?9ciI40FVAlfEU$<(ek3B+{{@mW=V49E*(=0Qnppq*QE< zi6$R#LsWyHA_+fp2M{7nkAn&DAe$RFY( zYo!aZFEhH2_+F-W*ItAMjWc0vZ~MHG01#d6_qT-ZNbybcX}RMat)d5PV#*}t zm#%N2-N1zrEvi2G6VfKPJ^$m4ltWFa&Zy1Si|y6}(C<;+`N{J}g&U*!4sg$Ah5cp( z)YW9IG0oe#qMKPTdjT<&0qThZ|}oNz%krzX&&5gyw?>;={iHywuNChO+Dj$Ra<# zw9d)jl6!#Q*C+=Sc*ctxc9P93o9mt=9v&W;mw1L+yf!%A$#V#vM}nkubobs2BFTFq z(uk^YL#})3<9DD2N>$(Lv@yS$e_hB9HuJ#;xjDB0Dmdkb7=Ok&AJ0x5Iew=AzZyA| zBxYv~!jP4^u}fMoF$<$Q^oho_$7(*+=!RUG4`Ks;9go?}8AF^~WYF~a(bYY!(S z0S(#gVN-ES=ep)B=#@_8P zSWE7+Y~uS}9)lTe-Cfq0hR8_B_WdnJT}7byNhuWDNQ0!M$sp$&xiY&i9FFcPPL&QI zyJi4im(_+j%_xHL0dEzH6+3ozTd{&ZK9D9>zH&zsWpl3^WPZVOD>f%n8tjKDl{^qY z4aOS0g8TJV6@eIVRWm3C5$OsB&JrS0bOF**3QRG>PMI1YAkJS|;RgY$`cJ=_n;!v^ zYcE?O&5RHMUGQ8HALi(qfZFK~HRSj-=FOm8E>T&027#5or=vLMe8WT8VNpc;_RYj0 zdFON3EMV??msYqeOe;)&kx>2of#djjW3mx9bAY0ZCxi5;&<{p>rMC^rqrex3G=V(# zP+$vqJV_p~9V$_VgZZQH!E1d!bp4gjO@7nPLE}Q>IFs_86zA_*Wt%UVHmXd>5MZY@ zpEa=d(Aic|00K?%`hq~;0fRP{7F$ve;TTVSlEY>3*qx};aKpi(o^W|LekVpl~QT?P#JnB{=6R(A}Wu1O%ZX5dN{!SG9RS?4}$k&euD^uwP z58{wuRPfB4U7!A7Px2peU_FMG9ae-FsOq3~GhzP`*K;}I|CX+G@^#J(|3JU!h;Z?= z<{A!2Ul~Y&Ntl5oFE=wM#UK|Y0sw`R3gI_XD_jDrj18UsP_L0Ro&iw1My=Gpc>WE{ z_Wt2LOYi^fJtzP6o|(TYpP>8}uWg0@2LhUmTx!>DOu*Lu&u6RriLikswNT?7O;0(Y3{P+s(|t;UTb( zv-#ip5~O%W$ctIL1`qJj<@qZI{C~)M>#!)dwr>~{0STo`P)b0$K|xeXNmO>{sJI~%5b%`)22RndkVSIOB0A9m$?q>e{HGeRY8%KNJ|tUWH;yKWj zs$FKnz6#sOETRsX3c1Bs{9tIo+WbzN-pqn;*o&QSZu;iqku_N)96{s+#uz`V^M3Wa zS*v<3rz)N3J?njNbkv-1(&cud%Lbp%JYfDysx)WX@;uMUQ@>@-UL?;O2kF51>+}-S zP#Ix}66Lch%cxW5*B7>Rj{36dj*uugFbWSG0Fs;Nfw2)^>)3V-5^n|X(ynrJBEwg* zhhIvWqwI|5*lx=I$_)!JaYV9RC`(?IS%WM6i^)r60Giw+r^V6SJ3_KYudvjF$hTsp z`BW-OPVNNUG1dVn{LJnxYL)q&7nY7d<%O4#0V)zaauM?xXq+;d_}rPt+oTsq?K~Yp zsM~*=`d&a3e=It-X+^+DNR@!=;hep`HHoP2YazN&vs z5W_q80`_PW3F_fb?xf}oedTx8glHktSh{{WrzG@OZ_`5x-KQ~G^{>Brn%lqjG<3#v zaQe>gmZtN&rCCNM=1Foh?F?&o4rzD?k)7XrV=8%ba^ieLH*!#Qr~c#6S)$l4!5`Vw z=xzpqG4(8`oK2#gGbguhrAWLKe=0-FcAf{O{^*dim<|=*RsTAj@Vs@<`sCIGAqmA- zszyqas;?^~%OHmjBK;2z#9j>7e*jZ&Md^;1eT0R(1>C!vf1IT;OWg_v(<-dN0a(Dp zD+KvQ$aW#}u#MWR*6VjpI-E}%+#)|Rt1JoyWLW-vgc8BB@P|x{>jjfMrv_;b9nv73K2>?Or()Ad zFu72{-{M>Kjcsmh68VFzBEu!xmH4Dw7x8(F=i=wHIvl^oCcXye3r&ZDX5;{j>FvUz z2+k^%0YC`1HZgHaG{ld73&Hf(bsv|Wj3|X+1jaQezXCMY7*1#W1J&yiID)|BOSw9{ z37|xx<6qs5v-m6&4emDJg`xlri^~HrwDW+IOUu7UL=Y$QS`~Yo&pD3N^_}f(fVEj7 zUbnS0<6gP?&IwGo>_1cnBO4sTBdx8I5)R9tBRn9ve)IAH;BrYK;xA>sQtJUk*siV1 zp=+l>EcvU?F@f9y(0WNGEmuzu?|?^C&~|p30OjTNf*+~lFfx7Y{`Yv5mUyfrH{NUJDYl0<*#Ib{aa!x$QyBI z9rPy55X~r8R>+9MyBu^~Fs~DX6Vf{ag>^r<9ahV8=P&j4ywG3jZMZ1ePy}Xo#ewn6 z4yvimtDiQtBA7iY_1i+u%0Bg%Y8!`&LVZOu!oW5zKgJd*IHPiHLw}=k?wvZE->MG| z!0|abz?vWP3fFw8tBRL_c@>9L@IcIX?!gSO?Y1{J{6OT!h1Ewns1*P~hnCGjXzJ4O5-PjN2Ujkm!a$ASqze$f$9$ zejO@mJo%X)8S1rra~A52UCIXA_0O=Ao>0@J%K6U}Nq%$&Xd>`YVVdGn#j7&Xu ziB+eO{f_CIl3^w3BO}zDW*6~u773GSq>;<~18L+QdVS>BhZA70T7rO_iJf4VEn@^DuK_G)Ta)J_M zm`Hl-T73sHx;~4Fkx&8f%kDFD^((R4g#zDO6}Zd>aUjFHJb71UR_|gaPzUpoBb(E7 zsF6)d*INm&Ef(67J%US-?Aa;SKw{p*B}>*VSCASCWT=77mtQ_=Z54WeGe;16JDhsW|41(#1%lc80vf*Wc`ir;^CuX8x%%;{ ztr*24Ng%r>0@-y<0hv7huplVBXdNUbE{umLV6f(T_Y5haCLOD)UPT(Pof$JHxB%=K zQDs+KJ6&k2)hQa8u&9d7dh{U~uRk%l-|pH<_HfuUjsalELgtJZu6(Uv7q~sZxf4^{ zWPb_F&&+8f=Vye(seb2x?*?530plB0jDbjM%U)G&V-F53J$V7|paz~Zm^)cKRB>?v zHyhOh_a!2uZ>B)sHPG3B(?%b{U+Qvv|NfqKqmTj7$?Nl2HRdk|S)I}?4<)a& zp4ZQt`t2(DQ*eYP^O}*F((WB_n|%O!Bw{?byG>&D*gww3diRC+=q#`^K2)6Nd^`Cm z02vVCzV%oCquIp#miFN*wiKIxZ;qGs^5P1RRwKk+LA-O>okqwl1$E%TSNLi^DIR(L zdN*<#p{&sLCScUC6$8e{Qo%RDoqoqh~~IDoZqm$aRu_MCD3;DSLk??^g0Fz z9ea~NZdUT2YNPnuN~VfT1gv+4KYT(SS@oQ@C>w-V((8V;LJuxvE7ZHgrPXtmIj&;= z?0wEMU~Oed89D31P6!-MDm;>lhrr^D2SWT^v}}6Q~h)KroY#I zo5lNAf8>_#H8xwVfZ1e_lV$vHmN^z0xgf$ufG1%ce)Ytm)X3xp^Fs!D{gLL`A5-*M zDrH)^6pDG6qAiH2&*IxZU(MH#^k^LbxNeTVhgb4=g=sl@!P?v#^!fEfH_b$joMHuFbPWO4Nmn@;h#g8ueB#9RrbI(v~J%{ z3l{Yt`Fsvf3~w$PZ;Axp&#&}?5jz>X3g)D120!x^AFU6H*D0=DxME}oov(=+!CA=Q zs6RJF!DV9>Z0=OMedz4s>@;xjW(*{shW733;+^D_5)nW0) zxQ)Z)tpPAc&FzM^*>l5x;+UgantO!%BgBfzWjpY&k^ZOFCHRwol#jdQY){^%-L&&z zNKkr8Yp$Ntgh?Ji;j*y3k(JJ`wDN4+a<+OoITTl*VC*NsiIz;i8OTP{yQI0>JbgCq zvfy#cA9DWISn9)4)lTtmHmUAou0N8k;i0C&cH%o_r9KoRW}U;8LpT$1_k)5Z3(;@a z;R=6hX=&(ZSk}uE3vVx->=PIX2!hpw@+#GO$zG$8!n70?>nhdeCF%V`>PJy#oST?E-((X6yk1{-z@^}<)gdR8RKDy-QupB;02Lt+lWMVp z@Gz`}p{ zCZng@-wP}bN)M=^=3ph3TXeb+X1mxesp2Zb)+7ye%5F$8PA1EpP?-?O8f@R!s(pJT-GS&vy3hSMQcrB!q&-vA#I>$!{DGGGhv3f3@;5%&(j4Ax$r1Y?cSvkg~9 zufn7R2-ak)VXrQYdFZn;P7<|#+l-V}?jLuQnOJFi7s|+ntHk~BQ&vO^*pEtssH@M( zWz(>eJz7CrE42S8C%orwlWIPkJt|kWUlqk#I3&@1!EUR2lUO^;PW!o)(f)==3n8op ziczlZ891#!O;|ng>aESvXMH}ypN)EY&1PFZWj^`qPiC{gyZSuo^Jzhqs3nm5Lw%ju zEYxPmWMKEtf)g)^0>CI+QlU}H1q zW#pn6vuUhnIEXr$Cy>R{x?d^5yN^y$Ir^2whWTD|FcksCgB?+tMv9}O0iiblr*|_*VQ*addF-WL zq=VDC21jK_GFkL&*sbLT+Tg=cnPV}wy1eh)62=WIJmBv- zv{lEb4EAr0i0ZF*g^mDbKalP=)RRM`f$>;CNzstq=7g@$AnR2>uM~Hh zT+skt5t+^+nV1mf!*ZOFC>AHHH?*luc6b+K9~xzFIphmGdtfXIzW1Q3;yoPb>F*M(F>)^&N zL03{rS$^D?UbMlu@FAizxT9&}O9W13#g#E;HN1=QAI#EV9xm=$$&evc-eFtnsifSh zl}hhv5eP%CnL5j`S98UQg;Q-JjZT$Pl{!n6DLV0TNYqlmxArz1jDVlKWXW1ppTIJm zi2EYm+v%GZX}ZWu&lhb zEGs(6$Heim;C02q+BivxtZW5X64s8?@Ze8@Z0W3Msz3wE3OlxY4&$`aHOsTNK($(^ z({`}_WH)VHErVxsiELQRm{4DNS>O?~TynnogGJY#sNS~n-OKl4`&!_fiBQw~L+9;M9?M?HMtCL|#fRpq+IdMiC~P&pc;{jt9yfijhj3R=hWzSbb6awy}Y+&c@P!Z#e#?Z6gk7nv~y`*nZxnX zOXT>6xRYNPzms$6DOxQ4Xc*a9w}WjyHC47LsI-gUi;zj$p#tmOSzhyp-R4Or>FY}+ z3ABih;T{kTgIQTG#%3zH8?WCuzkFgLIY(USRmG+P{rOu_Mm4D8yjGKECQXbp= zjjvBUD<@(5?L|?ip6^$4b!#W2%hp@%RswuhzI_-A2{x=rBTb(@NCsu%Ckx$F1|yeV zzDgsr9-(POR266tG_zrTGmX%i{DaBWcSV%XAf}QpQ@$2pC}wy&5$7{6J9(t62srFd zyJ->(w_(yr$k*)eP?)8(O(`BUi|l3@sQ2fEy7@5|#YQV7i!^q=2@iWbs^1YM%SFVR zY-e~2vP_o{6);vP5AG-Y%CeMTXMoE+o6*tfX0CrldC@oxk<+&DO3NH@gP&a(Z z_hN4z?Dyz^*r4Ow+*^&My@jPG5yFUy7h;cZ?R)kPNBuyL*U+7rT*SBI8c1r@Q?p!* zS!ry7PCOycEP4k=zkYFBs;<`{R}@=EQ%P0UJ@1}_{vDN;IpbTh9N_*NPSJN&*WLC0 zgpL!bS=4^e8LMN5L&o7jdI71dcMpV@Wi*L$D~OI#sg>}J?%QG+yML-qWE8APe>K<9 zS;IXm8&!ZzYPX)=k)9Sma;3wN^FB+omeH$=v*=nB{f;IjOGHjurcRTUpcE6?Wg6C1 zS63TG(p8ZC%kHpu@u~{ryDs!|KW0x*mqs4kR3~{{;t(VKd(eGrvs}9QIONe=|LN&zULF9Pv=u ztax+wKs=YjLJXorW95km!;M*Fu8&;hz z_taUC>gLTjz=lOw6pHYJ(-S%3As_PpX+W;FE+lOR*IxUTSy9 zTlHDhl^nJ>oZ`8#AZgWipTTbW$d`3GQrR}BIvWhg?JgH$d@_I~TBKd9q~Dn(+VSsc zMz0Ob_$liUIPPt4IW|~j1K7SapCoxyM94YvuM!X?W zy~=kNL&{lPn|u}vwu>%f9FZ!kJeH}R@eo#b5< zR1On<0Jul}_pFb#iFS(psNHNpoU3F30IKXc4UKV=TYBP^-TvP4w1z2)+>Bo57HS5k zsVwHLu*$ktwrHiDpIBTOLieMf5pE;6`AuK{wd!4)`kI~lEOhk3l)BGVYJAlOg$hA5 zLcMbP_CbQrh@o8KU8mzCLXL)q@h5>w2fMCq);s33t|1oZ{e&(ls4CK)hpU3 zN^PA4BUo6BTFIkygs!|>kv7OB4+-NLkvpj}K_Br=ycSeqk-{_IJ?puk8s=?nrAsyN zQmr@@S3V$xUM1s{er9bDj##cd&L=msx zlsO?Q)K^M{5@E>i>X?82zoP@9izA*R@=i?T>S3#)ELSRp#$=4KjRMEw;^ZlI47Tbv zime4}yBZpG7UMovn+!M)Nqi|S?T5H@Y({L+1RckctN7tpnooY; z06j2g(fDGoF@8k;cEUc z$J!qj4^{fGF0DD;cJOi3BTgOMgzGM}j79MBI&~}tgMvm2mB<^D?u_GW4(^n@7kzQ~ z(Lh_6@cUA}c2f!A#@36XK`Y5HpJJ0W%Ks4#Xr6$x)}zQL)_u5}#T$2Z9BgG<*|^xyddbs$m-MIzW?Q!M13&%XU?0%Z zNs+pGa)nPsxlN>4VLr8;W~O6wLWL9eAz=>pyW!1;A^=%;F})|UW@N+8t?p{0tbgAi z_eAy~&s_VqpZ78PhEJAlx1U{AkQRLGAWS)>>RhS3zo_e!fPp%eGPjhpzQ@{l+^KjdTnV$jGX{+G<^|WujoR;0+As3vYtO+!Cc;i%)}9ZZk$+D2pj2t~6F z<8YdMC1`nXq^hRB<31y_WR3`|G89^PpLDa|xZ8&UKYnkV!G#E)CeCpki#cP*br3Ej zw$$)RQCv2z1HAK!S_oN|KmZUKSU~bSo3*mrj8DM~DJi54B}#78Exf>i4m>cd4hvGX z-NtE-E)NNSWFg5$u`*#VdN5T>UlggyKXin6HtdcrXk|#Mp|agn3Qypvj$nA*NqZ=u zxtoA$oG!|=M2guvp!N+23{|LI780Ad9|f6@3tu&gY!DBm)bFqs8e{V{8}%f7mM_L! zl;130O8egTrm5=A;RZUl$ND(#s!GGCuPff{Da=Dc#vQ6e5Qs3I@>PYD6Xz?L69 zXcG41F_q(+&`{rO`9WDFU)E^ThD_^HDjMVVtEaMo>U8v>S&ks92K^Ob39>kGu;Zu? zvs#RpY*vP%;eto%S8qA>8(xfr7o6=F!52=4jLN?X!zE=Oa^pq$FQER z7S-ny2K{1u!>i)POZWpU*nTAi(z4{UGc&UG3_h+9PwN7s=U8K=>zZ6?Pm80oP?+E+ zDLzf>v)I#{@bRi47qc>-2p${$#dsQQ`DBzsrECqa6sT77;|Hy_;^BQsM2qh_8M~J770MI$Q-4t5>H5`%iL z+Q1?h&IySTY?KGvd`n*lEO#p*C+i0^$+J1E7;D$t8H}S$hiGUn!N`hAg^yyCtNQ_# zaoJmV5jejW#~nJdQ+TojGZ0HtI{}a}$(=s!W4LEg5d?Sr0Vv}e`y>cWQXie=v@eXa zCO8=PtX6J_q=I#HdrPyDgIi`)Bt36NNP!GOG$j<_28Yq^kT=1)ne;zbT;^L$A>+>{Zo8a6+wQ4`;j2;$*$O4Q1>t2uqzgp0-S9D+cxkTi z$yoO?qWlE47aRSGC>5c5RCXd8umi`q{>R#gRPuX@=shg#g~nRuI|>1AqI!3rHK5Qx z{s56vci4gKWoY<9rjy%ot8A8nfZ|ZI!ZSd{k~c_BK=BnJnbv=y`u;73nq5)iB#S2$ zMyZKW)+ljdlNwdnEQ@q+j$tCjg?ChY%dZ zVbg3BL}wAH^Qs-(209VGTed2lg*(i-)0j}B*>6X^qXW+0rz6JxI=!7$AX4N~%x z!o&F-LPAIvJoxB^y9cHv(&t+lFQ*(ThPZrAY-JgJP*xanXP>(+*r}_D16>5MZ8n^6 z*?7qX@gt=uOYJAp`2l$;>0*+qw1H`#SHNclRPl;$q=elan8sy5z5J0e<;d>xui(_{4>(Q%L!M99#)XJr|iKC@W{!tx9r5`tVA{@!C+ zrRlK3gZ$OX5uLQBe1uibjDr9s^0)6e4aKT59FvWzGu0@ z&$~vS1HUpuH()_4CryB%eYg9+dhn!k0->Sg6my~!hlci9>0It5@CCPMbLYWxfuD{` zB}B-7W3a%}f**e3E-3O}3s&$7;OG1E`^M)!x4R;?F8q4wbv2^@+t>crt6X<+M*F;i z_W$ea$euzR9j}$u)^y_P=B5_EVj)F)P6|GGiwnylD)uvrwh+isJXKNe(8Tj|XcqU7 z_W*lc1QCze-R7H^wQAi6?~HDi(dgY}PrT*mk(1Be5J zM?f5}-e{ZU!rJ%rWVFxf$fd#OMrS{>{*;soa^tUc%U3sc7$9D|0gg30k2ZRx3;Lak zSfn<%i=m;ew->D(L(sD}gZo^b&;05=%rF+j$i(_*%>nTG2rv1^td6xk2kS1b)Pt*| z$LY1z!i+Tc?y2uLT=;p>fMp$*&3ww+L8RIGBA_u}55m^`#FICD(dRLcuW{K;G>-B< zo{2qfKDmLPy(6z zyndl;Sii*(kezFswNyI~I<`R~1?XEsBw#7j{r;}Zqsxq%ZeZ)#S zA~|oS3N$A^2xWk@9LumnL~O%-n-_om&lH%+cKEJXYe$-IVi5S^&bRZ(f_M7Dhsy>y z*wM<>N~LOQb6PlpcV8psK2*O8T$iK@$sBO~QgyONYM*=sxDLV(d*&_HDwy3QKFJxa zm~x9Z(&ZejU%}QxCj#U=e z+jg(Q=btL-wXtOmf=|~=zv1nxbc5r)Apst~noQ$;vmGB>APQN;zr;`L8+SbVlCHc^ z;GnPxlt_=!NJCQ|`eHB2m(Yy0JY|sU7+tKlHEztUk6({f4*E2Z(oHNdG+-n(_ zw4McUxb>xXO2UmBH*#VE1z!Mokn{Yx(>n=zp#^T{kP9sCGyDl$zn{3GusYG3DF1>- zfS%{%eSk0}g;e+VJ|R*bu0E7j;AooF)(7U7!4GoM-cX5ko_)&NLmKAZ;P4S3aJiu+ z=jW4P+T2Kl38H&Yxx$6zZvc11CMdMw?K;-gN$7~hoP_gZ4wc^^QnW}NV95AwTuwz6 zNM6MTcG)2imr}?adH=elB%=cFYG>+I?3YH?S-W%Y;5-7RAueJH3nJ_|W6Y9^je{k! z9rI z#dry^A9;#AWE>6Kq5*MlaU^gPGloa(J<<%J!eCj*eq{%~fabH@7Z9xh799{b^im1{ z0!kU}>q-dH#&JGb8YZ^k{q>pKS@c{F6G^)qPyG9l```;PdN|8Yc5prOM&-_I3fIoy zUt3p*8qk`0y7Yqxnc1!apbzXZw}0Qdb@mpZcs7E+p6XpfFUHvtB)S+YXOP?R_6K?b zjC$S%wLjP8K?VCf^u&1s?cTXM+!yM9l!E`4=lS2OOoA!2m5;?7KRzdn#xbf%UUA@{ zuU}OC+G%BaTWXlw-6+93oSFm&8VpcWY@8E)1DgBpF}@zkJGLT3-`Ck^7gQ+wPl>~F za$MdnyDU>$^d8=?=Q53s5omzI_^9kzBV?v- zUUICYaKRc9{)|tA+8gizjW;{hQelpb*>2Ql>%p!Ba@QE|^PS#JtoECUUt($K+tn?O z#$AGSo96l8%lR+$&(sOAT;Mfxg%fzon&b$^fkn+6UyZO9*Ep9;W7r(M3D_Q1d-VdK zkhe5GY^?wMxyehka&P&CFb;g?8bJ#8qM1`G?!w7u3bHilr;=G43zb*#U)X%RuNuj6 zf%SV86DP6ZlWrYRF8mA5!wV&l2~ev|yPyp}fLX*s-fCzHJqsbod;?XbkuLoP*yg#K zQrdRB>d*RoyyYF&LPUHyycwvDzG4C&pc7hA2-wc#GT{VU+H zqIO)uOWAh9{(b$Eyh}q(5qaa{Q-8$*{OekTI%2}*4S8fUo!1wXAgp=9KP2fB)Oyi! z`}x?9Tr1&ZeV>;{82~Bo1f)Fjxc*bTr1bgrSjjuDxiwk`I%|J)1o+JI`w0sl4Y3iv zlJTL2PoAS}ZVamAeFcmlH8L`!h?|DJwYixlgi#?F3Un3f8=LQpdTr{S0z9l5Nz{&` zcfOJhy9??B+GmDwF295UB~aFV&eusng`)p!}Uwj#G$m)>FWiMyio2@c(;xAZy0m?d+z##ggh z$zX;r|5Y})`ThD$z_AcmYI%g%ry~S~OLqood~@lXAdE_SENH1D7LB?o$i9gMsSIpV zHm5uv`$E6>61d@1$NOYpur9`q7QZXk&=tN&PT~yqqx4dTx@>p^1(Y|e^LeEYB-JKD zwIFz5=0uwBO&U&0D$6M$9e7-b+>=1yZPHM3oNrkH0v3_-GBzg84;OU0AfgGsq$^p5 z>kq5;`BjvCfnL8b`~CPE*2m7bon{@-Qacm9u;=R87%W2Swn&Oe*C0DTGO>f_O6iI! zXM^3)OF;70-o#zs-YP3SxoI6t7ymK%j+?l@z}`L!vfcu#)n6e0-jfkTe~=Hf9&DwD zjq)jUG^)S=c@84=0rDISHPOT`c!3D>X>;~s&0gjuF=A_IXe{eek3^sSpg~o$a|SEcFD$pc%cq}Fg)~!;@jBc2?;Q{h-uxd+@qa0y zHn(%foEH^`_I}zZs5}ut?J;oks8q6}X zel&d?Kcg4}JqKHc5*$linF}|OCg&5i>&@zc&-Q#v>r_=&7&~&M-2qt);OEn;ZVqLZ zdYl)%gz7j2$uP|A$%4`odM!}64VRprjxg*I#e-N%P(=b79{{FW4NnR=ynYCiZI&8Mh$o%Nb9Jh}wu7 z$I_dlsSYuo=?qn3-*dfQ3M??4R#04ZGY(IWOb;d5U>@QPtq(~8lRuBXCVUU*$R!HT#?GXvOYyb#K{ zo%em`kU^|QZ`t_<=2d>{xRHiZBQwW`R>Ed_yk!<}mt$pc`ztU*rN-+YR^&CEIjD(u zQ4Xr((oHe-T-wafygUkn3tExmYHBX5EoNjdJX6j=v&{iJuti3vhAINO8$Cr%Qr`jZ zb3pf!X2=Avc#EuTw=S6BvPU-*Xo*=C+pm8Au|P^eB&;_q10CKhPH{&$se$*&E`Gt! z-U^Qd&QM_%ft|-ODLu(+gu}LuuQ^z-*_AQs>u2@bcBXc%+aF_p?!5%YJLO(q9Qrf6*WO4RlBRj zYm>@%ank)t2~u=fT?9WBFC=As7r5aEYAOBdxhJSvs?3}db`Q7;HCX0I|IpBtGWfDV zZViA_anFtC2+av6{1&4I)qWHkEUlJd4Rj3!bhr$0*;1FOomSVZomuVRMHJo)b!+v! zW%yM3i=pLn;8yQ_y~YBw=TXi6?J>} z5a4A?A*C3dW`^WukryZ(&elDPPMOp2EeU@7yzwSYA|1z69PJ80??9(!ULKuK%&+i{ zB?#|W$#upxQrU=zs%%*N2DcT_rHU5a*nJqNwQCR!ehY%81)=4B#a588gIs3clvuAraavs3E+Rg zIUwT>t1aK3=6i~ZcmJw^&&Y4RUhTQp0S1O7M{)^CnQs0FvLa++K#VXWEtZznT?*P`{N&~j-tsXp6P8OKsGH%5~lLu@S5ReoCkr}@KtI7tl zAy0FqXOO%(J);0@UX%1}?KkG8$1`GJn^K=C8;elmCl`u+g?%2l4&6B*cXA@^28Z0c z)qQQ0iI$R9yWv^FPLoe)M!LWN-l8m~^0EMjXs~a~6JXm@H7XvxWr=N7>BmY^o{27(YuE~a` z!r}qf`!#XVT$zYh(Ho4fzDu2w9xl zq@SsTg5u|WeEC#Mcn-B5HUpRRtJ&Ry!HWtVXTgDFd{m&H@fE+&ZE1Zt1I6q~vI90n z30WS$t(@bJCN_2hkW1K^urQrYXlV{Z*7Y?$4eHQ)>qG6Tt#JSLHm!6DjBH)a=Y@Rt zS|2D&_(XS=)sAuB4?L5YgrLmwq*jr{a^r~C!E_?G`GJ+hZZI9;7LTZW0qefVf(JSx z_|#}iX!S<70IMdbN7ftGvh43b)oNEMiFr0UVvu5M{buLxiOwO$S0B&6dH?Tx&8Q9B zP&lka)>!l#s5hSW-eD`$86dcaVz>UB+_!=u<0X%ThmY9rwQ^d@Sa|69uZr!cpY20P6Nh(^jS-ez!j zs4=c~RYATyS1dihJM?1NKp{>t;I@S0q+jtJ8cr@z*A+2|={Rtdk8SV%CrqoN&gnhLur??4^2s%KUu5PpU!ai^}H=hX6L= zhpLh+k4+qE6ibASXTE{$>s73rL(cPBaF>+#C1$%Tm=8#=Ta{|I9xzXPh>0X+1VI%n zw?{Uh;(Go4Lfn_^mqP1lKume0sPIUobyrDql#Yst>u^tXtp_tLH?rVs3{Nyr8pQ?p z2g4?>6C5jooD#-WW@GhO75A2A#7+yy%%yGujA|%HoZM_vfPe+3Jcz$(2twDw``?KR z1#)o)l9E`&zK9QaiwbIJ>gF@01%L-`$eyXn;Ejyw-9u`ML{va}>`+xM-5(@Xl8>6* zi=V{N+!q8n@7*CV2tX28e6m#g=GChLs|Sl{ys6j0-dk_dLF{FFRzC)%9)d?jtwz}~ zJy6-4iGE_`8wzCPvJr66^?!m}ALaCjdBYYW+?mQ-l*=vv#-7&sfkg`zreOsF6B|lC zyQZ2fP{WouivEPNv4Uq6d`}YPtY?dBxGVF4JU)ZxGxmc6t9YQ+dSQ281(++4*X+Ek z@7;I#%>ne!A!)W4W#|#@TEchl3^mO7x+JNj&<=Hc?`;-4ruZ=*O% zxe+U;O>^*ROivQcF&jfO7MK(Gq|%+&{{#B0B=z>-yr75wu(FNkHG|c9Trsi)*uiBF zswV?bOaDN>7|;y5zCPXg31nAH34EgV+#+0#f5!Zak=Qn^m>i4)YTi$HkVR@pHq)*; z65*Wz0x>l(bQ7VK=q2t;esW}|-z(-eRw8`K*3fGz)|(;@ZCU}LTCVWCTSBm4)dJ3$nZ&jm;W1F>qky|PgFa(2 zx8ME&%M->*OVVCMLX{cpK2CL$AlFm@)DF4o=c&={3zi<)eW*#oed+jEq%cec<-J@L zL1MMLmTT#xzG1y>^QPQAP}+MAH(a2SKDxiei&&G%s@LcAtP?7Fna$A&YuZk zyr6Ru@s(f-3?Bu;bMWV;TZA!t-WZHDyM(VK(3EulI4TRfFP;l3wI(td7k?&rDEAHj z)3nAWW&!5@2;Yj*5RTwihIxxIh3x$Ksj}4j**O~-|X$PeJ_uXFkFPjS5^w4B#d)qebBgKQS72x(@iQfox8(F7Dvl5fctN7 zL{>7;v5mkq^CqbYgGL^Sjh%((s_t=&aPTSpi$t>5agH}jgxI8;JZ$|7YgRnbsvc#m4r+q9?y4v4$Zqvvc*v_8S8o0v1Tp)OCpS ztM^qiX2au*Io2=IUqIW}5jGjR403;q&G~p90l~)i6~{MVGq#SXlhtz>IdpF;>p7aAn?eaODHkATyYpEa-9qs;&dglwO`+(7K0oN#3 zTzVX(-{{%(mkXy2BIyu@tyX3~t?bj7IhQM$n}nTSwhsS`l5 zpazs!ah%qoylwp%CQcTseqm-8<9P6U$!&iu8&&H(}BSI(G6v z4OiE`-;AavN&Khi^eo(~L6Gq5@lq#QL+9_*R_Fap;OZvlcgnCG`Syyc(xV zQ!A!kzjIRjkDJs7gC|_J^P!i$o>gLrZ$LjI&O~8)Vq0WZzLg9bmZ<}vUgEr<>$+HJ z>)JJ8PWrC`Zd|UuGu>x22_$=i8j$);QdP=ZTAE{{Pe?#2QJSgm#!4ERph$K3IkkfN zNnE%2x4Dne*l|Ga2=n*`_$Vq-zrZSyC#P$v{kjmNKW!moeFU;HK;@k{Z}-+Clq#!e z_w!9KQ1bNU%l!^fns4mMetFuLs;ES&&X8F`9&D20=8f6V8e+l`Q)el$*AEqE-1RK= zaz5=xgc>rXR5X{yK2nZ(DL~ksDQ5@TZK!n^3sg4nF*XUWPhQgEB4vdcXpO>xh}3!c zeYUZu%`HI4a#WzF11HOVr1A1hQfCGNeejbFJ8!`1gEAn+oQ_!L< z_3mUJUSM9U+EX&9H+N}Nf`z0MHritvwHN%+np*@~kt@WO=eM0uqSL9WOn=bpcWGj! zT0+5RuOJ99L6}=2Rs{iG43Fn~P^SW@KtOleo;?P+yrUl0)hqv4gx1hRe#{mcyeJ~G z%ok|>0MJdSO>(P#zUC0Mp%IXGf$H%?J!${g=bzUMh2q}<<8|=+gy|jLY~D}a&eA}y z1z(may(2@;_oZ|U#Zq-r1Xzn-&=GUxl7^8v0oT5LfFMhM@jj}40e>Pxkj2LYlFjXyJS*d}$43zVdaxHTZUPq|Wc$e&5#}<2H8cXGKTENUu={T!+ z(8obbh!=lLG^*}!5>>a=BJ0aNYBRM7#J85Y-{PBeUS9wEuvl?gKzK8QCwnBMZIW4i zREFTf@V|a(t_ceQ>M$kE_1vmj2F}`$2g9%>76qvHlz8z`BzQ_DdGnFX4T3*#;MO6QvMf;07ojRSa}n_Gxj- zW>%eCJ!4nL@VnY0K`!nB(4_)I(n_DkQW*_-|DA1H3)x=Vc3sY=&V8P_4Km{84MBOu z$A2zDD2vgh?jko+E#w#;Hp7T*2T}pF_wX*sU@w{k;e)S6s-RLmw6Vu4{KLc?m2ZXjbh$UC7Gvi{X8zkaPQSR@5 z#SZ_)*sf$PLqZC{j`SRyQkpXnJ`UO%&6^>*6GU^n95s8VBCs9$!{+v3hLw^oPlIOh zn)d#)swd2^S%hd1FEz+>{*!#Kv$&c(D;r}STs^BW-h%qL%T>OoQX?&!#~b z0H|RUcNcBJlXV46>k29`|C?esv9b8Q_$JET2Zpp|7!Cm9=%-0|&SIIr0e}b-;K!z@ zAqnuH4~hWmF?fP-I=#Li3;+O$5=g%UtQ!@4_qIiK;HPbKAcKrJV!6QqxuC}u76mjvvtLqk zUIYqc>40BSrD!G5ti1bgzdPlk&(4k6#I!l$%a=T#!~-V&|Vknd_muB2H;1P6&SCxFlU((BGqEDt!6jd7&3FFlMhhw4P6#&0mtGPBY>YlL-Y=Vw-Xqm{vj# z0@=o$mrm7G@hB10qc7PTQ-z9s)01d*mNw{yn$2`CyBoS3+fl# zwq85N*>jUrS3c;1M77?Y@>MX(7ptI?%HLNhu23HolBW1_e$N}A&u2?n-)P-6ifhwA z%&gWyKhF{VC6yM#QN}Upx%v{cO&2vbt`N)sP7~N5;5X9F#D)UHh|Jc=+dY2jKWBL z>Px42_t^Na4{Tj}TM z)idf3UFqJqhc%I(;{K|8yzb}{9k7`}c3_^95Ee06w5ikjpwb6)m*rmdb629Ysv^Xe;22zd7CD%b<1u*8I zE8RIP@TgB(l(|y~fS2rNJoQp9R(9?#0SNVG`eLLRZXM ze#y}ZQ)f>7lmSanmYUVR3bj`lwp9P@6UsBIU{gS)?OXK@j znLDl)ZYHvwX>#$4|07f*29J1c0kUd$*@i=kaSp1Ayqo@HSs-e=~XPnrFXJ zde6$@iSl3CY`aQ<4d4er5}Y<0ma}Sg@{o;C0Bx<5aO^+Kv9?j5D0HgVMvfZgiL?Os z|H1z$)xlBWYVK~udv&hagQo_5CZhI zrLcXaNwQ%?;HX_apjL|)Fr*uq&vi3q^hir^1(KnUzV|YtX?-BSTYBV>Lu=X|mS|F4 zhu{rs9uWgP?Fj-<=Se9P63OLBnEDGt?cM43Oq`H1Ux3Fm<++yRqP8pyK_y`pJ@F6w z>|?k#ijD1Dy6+YWOGv}?8ZQ#RisR=@Xe=pJ0{(KXb43{sWJ+b(RDIU4^@~I{TGfKF zm4?Z%NExYT0bVFuhsxXhNXQ9mxZB_PYk@pf%Z|YeSBBFNW*j|cj%sXEbaN2b z2HAGcCTvp0y%FZ0#)*upNJNS>HvCffcOz6=CuBkZmH?@DafE#$kf!Lnh?rQhT6K8s zA)?n$nPu6*l^QMoSIg7f8kYm#_=90b#@V^KPg|O_@U{DDjREr2@ z0pJC$e0Fx$h822OHG_#h8VQe>HuL>j;F17{X+Bd9^L9uVHDp1$sF}|xIX7G!`A1&u zO@d$}rz}|MNAWkB;zhNM)akjSX?bW)Z@#|sXTaHyu!e*l{&5rwFkq*DOG-ARIlD4S zXV#_hh-QeHKUq3M1*^nkx+JLsx0pB#9-&i95%rVDLgKpw(nZ3;9Ooh~h0Vd-p@x9D z$Q_9Dcswl#BAh7f=&OAi19G6*7F~^dPTHBaM{b63TH-Uex*$hNw~ZLJl`XIMm6Li( ze9>|NueEjsat8oTDOD3mwJ>>t=MICqmTA|_@UqDO2?d* zRdV<@M-bVw5sXW?)|F6PB6#uC-^BuWzBm5L{eOn=^nPN1T{3s$RwYluZC30nW2QqF z19^@+tAl z+|ef_j9{>q$+?)h8tr;rQ}YcF?cks$$(0x-BeSu;wf7=xH6EIKKR48LF4)8liv5B_ zF9-Lz=f8j(VAsKVNCsZH%uo2C>F@imo}VssFVJ3$mljq zQ^t*hMT0M224hUS1HMd@Vr!@6AAW{~8Cu&Z7Uc&pTw-7@8c7!(IL7v2u?5Xcb$ ztF8r&Uc{OtDbrlOqQD{t@Juvh-x%CN%)JF6#N1QWc&z847XmZy6w84V)T`KVeNx3o zW8ey^CASVNK^TBbD}1!$BKPq|Kpue-TXA)+<{*MUJh$_n;5H|iT2zRoBMH4F3@NG+ zLIwu=XI{cS9MIHf0GA8R8}!?h2(0G1EpY`gX2yxyo`B;3Gh%T0TUW`P&U>49gmsk( z+r@!qy1Md4-Jcf<<+9{?u?Wo0S%$(fw`681hH>tk3P;?&9yDv6R?z-0nGG09E$4#& zW87XTrpR$C>94A3_j13=GQu?N^I@333~UVR-t;>P9J=ZSaqrfKHYn%*oqTNGrb+om zJbpBpu=fTG(U1Z%;cZ^tfsSwXnpUf*p&aR&NZnuQy|C$TY@lMFT+`4Nr45nY{v6!% zTOzH-`r=wiBO+hgUGE&Z$9rCZzz|+pN&6OTc}#t+Pv=OBUr#v<_eaV$59IVUg@xB9 z|H-WUp_%=*IIDkXnc-!S*D{2%1_-r&fY1FO;N0!@JY>EieDY9RUTdhgPH<={aeiLr zFxOz30ne+oW~~Z|?ow(#w6YgrQn`6PgqH zI`+6xLwh(@N~yQvW2$WwsNk4GG||=6_amsN=VbF-;u6;w5RV}$dVepklsTbhv= zE-*r`R`+H4GSp;VzduNC%LFI2_iHc(vZsLR zS5AY8KTsnDp&QVMnOQcu(fuYKu#q{7KfqNWxO$~d&dczN|DK9XpswqZEsHTEMrW%f zyHwC00BC}z`a`e~ZJ;otDOuJ49&$*V=!4>Y1ghX|EVlQ|3D5B?AfU$&Q7fMb=&d2f z91#dMjy9|}%JjMT&~mTnTd<2raaktqjBZ=teJ=B>WPH~B!(w^oDRV?-eP>0R8Z?%? zY}VyFvJN69(*h1Tw+>#@u6EdlkmjE2*!+qY&EsEf4hvNfXPF-qbZB{DJ%# zNFw!N>M9H~nqBvvP;fW+Hx6@@mNZn#nK18uLAfQ?%Jg@ATZyYyf|(h0Qt77{eqxe4 z_EQ#(SMmheBA%QO&;1@g zHd&=hKO=Xp>6WR4$kp8`kupSoWK~CFg*cO8#Siypr@5&;;>V#R`fG~kkhNHG7er+@ zwqGdH>9tEmQEzihIhI3M^K&4hdhT37^o9^gb1;)=Yl0i?HBz8e-%8LLsiY$B&9zwV z2mXT4ERs#T5>~X87Hetkkh&9WvXIz>{ODq%TD819e8mUysuz9YpRER0RaMc$Ybwj) zJe5{b`jA>Zq2jYXe$Y)XM!|2%Ym|q*oimYGt(tpo^|6nRmA<|{#8Riib5%Y@<(-)= vsamB{3I8J&3h~hD=Mb-hpVvHR*S9L&Iy;5F(Buxk|Dvs-cQRM)e9*rDeKWYB From 41fc1a62ac198450cff54ef43bdbc552e25480a4 Mon Sep 17 00:00:00 2001 From: Jason Lienardi Date: Mon, 15 Apr 2024 02:32:17 +0800 Subject: [PATCH 228/274] Update DG added sequence diagrams for eat, editmeal and newMeal commands --- docs/DeveloperGuide.md | 56 +++++++++++++++--- docs/diagrams/EatCommandDiagram.puml | 44 ++++++++++++++ docs/diagrams/EditMealCommandDiagram.puml | 56 ++++++++++++++++++ docs/diagrams/NewMealCommandDiagram.puml | 38 ++++++++++++ .../EatCommandSequenceDiagram.png | Bin 0 -> 29584 bytes .../EditMealCommandSequenceDiagram.png | Bin 0 -> 38762 bytes .../NewMealCommandSequenceDiagram.png | Bin 0 -> 27022 bytes 7 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 docs/diagrams/EatCommandDiagram.puml create mode 100644 docs/diagrams/EditMealCommandDiagram.puml create mode 100644 docs/diagrams/NewMealCommandDiagram.puml create mode 100644 docs/diagrams/diagrams_png/EatCommandSequenceDiagram.png create mode 100644 docs/diagrams/diagrams_png/EditMealCommandSequenceDiagram.png create mode 100644 docs/diagrams/diagrams_png/NewMealCommandSequenceDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index a54dde4ef6..947b7e91c8 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -136,14 +136,54 @@ The `infoMeal` feature is executed on the `User` class. Let's say we want to fin ![InfoMeal Sequence Diagram](../docs/diagrams/diagrams_png/InfoMealSequenceDiagram.png) - -### Tracking Exercise Feature -- Create a CSV which stores data regarding how many calories are burnt per hour for each exercise type (eg. swimming, running, cycling). -- Implement a 'track exercise' function which will be parsed with the format: - track exercise t/{type of exercise} d/{duration of exercise} -- Parse the command -- Using a hashmap, access the data regarding the amount of calories burnt per hour for the given exercise and calculate the total calories burnt for the given duration. -- Store the total calories burnt through exercise in the User class +### Eat Command +The `eat` command is responsible for handling the tracking of meal and adding it to the Meal List. +The following sequence diagram shows the execution of the `eat` command. + +![Eat Command Sequence Diagram](../docs/diagrams/diagrams_png/EatCommandSequenceDiagram.png) + +1. The user inputs an `eat` command of the format `eat m/MEAL s/SERVING_SIZE` into the `ui` object +2. The `ui` object calls the `parseCommand()` method of the `parser` object +3. The parser parses the command and calls the appropriate method, which in this case is `handleMeal()` of `MealList` +4. The `MealList` object then calls the `parseMeal` method to retrieve the information from the command such as the meal name and serving size +5. With the meal details retrieved from the parser, a new `Meal` object with the given parameters (meal name, serving size) is created and returned to `MealList` +6. When creating a new `Meal` object, it will call its own method `setNutrientDetails()` to set the nutrients for that specific meal using the meal name +7. The newly created `Meal` object is then added to the `MealList` +8. Upon successful tracking of a meal a confirmation message is printed + +Note: The implementation for `drink` and `exercise` command have similar sequence diagrams + +### Edit Meal Command +The `editMeal` command allows users to edit the serving sizes of their meals that have already been added to the Meal List. +The following sequence diagram shows the execution of the `editMeal` command. + +![Edit Meal Command Sequence Diagram](../docs/diagrams/diagrams_png/EditMealCommandSequenceDiagram.png) + +1. The user inputs an `editMeal` command of the format `editMeal INDEX s/NEW_SERVING_SIZE` into the `ui` object +2. The `ui` object calls the `parseCommand()` method of the `parser` object +3. The parser parses the command and calls the appropriate method, which in this case is `handleEditMealServingSize()` of `MealList` +4. The `MealList` object then calls the `parseEditMeal` method to retrieve the information from the command such as the intended meal index and current serving size +5. With the meal name and current serving size retrieved, the `Meallist` objects retrieves the name and nutrient details of the meal by calling the `getName()` and `getData()` methods of the `Meal` object +6. A new `Meal` object with the updated serving size is created and returned to `MealList` +7. The newly created `Meal` object is then replaces the meal at the specified position in this list by calling the `set()` method of `MealList` +8. Upon successful tracking of a meal a confirmation message is printed + +Note: The implementation for `editDrink` and `editWater` command have similar sequence diagrams + +### New Meal Command +The `newMeal` command allows users to add new meal to the list of available meals by specifying the meal name and its nutrients. +The following sequence diagram shows the execution of the `newMeal` command. + +![New Meal Command Sequence Diagram](../docs/diagrams/diagrams_png/NewMealCommandSequenceDiagram.png) + +1. The user inputs an `newMeal` command of the format `newMeal MEAL_NAME,CALORIES,CARBS,PROTEIN,FAT,FIBER,SUGAR` into the `ui` object +2. The `ui` object calls the `parseCommand()` method of the `parser` object +3. The parser parses the command and calls the appropriate method, which in this case is `handleAddNewMealNutrient()` of `MealList` +4. The `MealList` object then calls the `parseNewMeal` method to retrieve the information from the command such as the mean name, calories, carbs, protein, fat, fiber and sugar +5. The Nutrient of the details are then stored in the `nutrientDetails` hashmap attribute of the `Meals` class using the `put()` method of the hashmap +6. Upon successful tracking of a meal a confirmation message is printed + +Note: The implementation for `newDrink` and `newExercise` command have similar sequence diagrams ## Product scope ### Target user profile diff --git a/docs/diagrams/EatCommandDiagram.puml b/docs/diagrams/EatCommandDiagram.puml new file mode 100644 index 0000000000..a3df63000e --- /dev/null +++ b/docs/diagrams/EatCommandDiagram.puml @@ -0,0 +1,44 @@ +@startuml +actor User +participant ":ui" as ui +participant ":parser" as P +participant ":MealList" as Foo1 +participant "Parser" as Foo2 << class >> +participant ":Meal" as Foo3 + +activate ui +User -> ui : input eat command +ui -> P : parseCommand(Command) +activate P +P -> Foo1 : handleMeal() +activate Foo1 + +Foo1 -> Foo2 : parseMeal(input) +activate Foo2 +Foo2 --> Foo1 : mealName and mealSize +deactivate Foo2 + +Foo1 -> Foo3 : new Meal(mealName, servingSize, currentDate.getDate() +activate Foo3 + +Foo3 -> Foo3 : setNutrientDetails(mealName) +activate Foo3 +deactivate Foo3 + +Foo3 --> Foo1 : newMeal +deactivate Foo3 + +Foo1 -> Foo1 : mealList.add(newMeal) +activate Foo1 +deactivate Foo1 + +Foo1 -> Foo1 : print tracked meal eaten +activate Foo1 +deactivate Foo1 + +Foo1 --> P +deactivate Foo1 +P --> ui +deactivate P +ui --> User +@enduml \ No newline at end of file diff --git a/docs/diagrams/EditMealCommandDiagram.puml b/docs/diagrams/EditMealCommandDiagram.puml new file mode 100644 index 0000000000..baa219c053 --- /dev/null +++ b/docs/diagrams/EditMealCommandDiagram.puml @@ -0,0 +1,56 @@ +@startuml +actor User +participant ":ui" as ui +participant ":parser" as P +participant ":MealList" as Foo1 +participant ":handleEditMealServingSize" as Foo1 +participant "Parser" as Foo2 << class >> +participant ":MealList" as Foo3 +participant ":Meal" as Foo4 + +activate ui +User -> ui : input editMeal command +ui -> P : parseCommand(Command) +activate P +P -> Foo1 : handleEditMealServingSize() +activate Foo1 + +Foo1 -> Foo2 : parseEditMeal(input) +activate Foo2 +Foo2 --> Foo1 : editMealIndex and editMealSize +deactivate Foo2 + +Foo1 -> Foo3 : mealList.get(Parser.editMealIndex).getName() +activate Foo3 +Foo3 --> Foo1 : mealName +deactivate Foo3 + +Foo1 -> Foo3 : mealList.get(Parser.editMealIndex).getDate() +activate Foo3 +Foo3 --> Foo1 : mealDate +deactivate Foo3 + +Foo1 -> Foo4 : new Meal(mealName, Parser.editMealSize, mealDate) +activate Foo4 + +Foo4 -> Foo4 : setNutrientDetails(mealName) +activate Foo4 +deactivate Foo4 + +Foo4 --> Foo1 : editedMeal +deactivate Foo4 + +Foo1 -> Foo1 : mealList.set(Parser.editMealIndex, updatedMeal) +activate Foo1 +deactivate Foo1 + +Foo1 -> Foo1 : print meal edited +activate Foo1 +deactivate Foo1 + +Foo1 --> P +deactivate Foo1 +P --> ui +deactivate P +ui --> User +@enduml \ No newline at end of file diff --git a/docs/diagrams/NewMealCommandDiagram.puml b/docs/diagrams/NewMealCommandDiagram.puml new file mode 100644 index 0000000000..9e6b606a99 --- /dev/null +++ b/docs/diagrams/NewMealCommandDiagram.puml @@ -0,0 +1,38 @@ +@startuml +actor User +participant ":ui" as ui +participant ":parser" as P +participant ":MealList" as Foo1 +participant "Parser" as Foo2 << class >> +participant "Meal" as Foo3 << class >> + +activate ui +User -> ui : input newMeal Command +ui -> P : parseCommand(Command) +activate P +P -> Foo1 : handleAddNewMealNutrient() +activate Foo1 + +Foo1 -> Foo2 : parseNewMeal(input) +activate Foo2 +Foo2 --> Foo1 : mealName, calories, carbs, protein, fat, fiber, sugar +deactivate Foo2 + +Foo1 -> Foo3 : Meal.nutrientDetails.put(mealName, new int[]{calories, carbs, protein, fat, fiber, sugar}) +activate Foo3 + +Foo3 -> Foo1 +deactivate Foo3 + + +Foo1 -> Foo1 : print added new meal to available meals +activate Foo1 +deactivate Foo1 + +Foo1 --> P +deactivate Foo1 +P --> ui +deactivate P +ui --> User + +@enduml \ No newline at end of file diff --git a/docs/diagrams/diagrams_png/EatCommandSequenceDiagram.png b/docs/diagrams/diagrams_png/EatCommandSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..e5b4accef4d339fe464f767c3ddcbb463964688a GIT binary patch literal 29584 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 D)>46d literal 0 HcmV?d00001 diff --git a/docs/diagrams/diagrams_png/EditMealCommandSequenceDiagram.png b/docs/diagrams/diagrams_png/EditMealCommandSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..4000b65573cfe390ddedea18d6bb82f11ff2cbe3 GIT binary patch literal 38762 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