From cc953ed48cec68211a8a578e168abe029cddd849 Mon Sep 17 00:00:00 2001 From: tikimonarch <65004283+tikimonarch@users.noreply.github.com> Date: Thu, 1 Oct 2020 14:32:48 +0800 Subject: [PATCH 001/271] Add files via upload --- test.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test.txt diff --git a/test.txt b/test.txt new file mode 100644 index 0000000000..b6d9dc8657 --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +dietary book From c12a94f85a0636231a3e56c521a6e8c32c064995 Mon Sep 17 00:00:00 2001 From: HengFuYuen <60005925+HengFuYuen@users.noreply.github.com> Date: Thu, 1 Oct 2020 15:27:33 +0800 Subject: [PATCH 002/271] Set theme jekyll-theme-minimal --- 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 37d97a8e5ffa0417934fab7f4b9aaac22d2c2d02 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Thu, 1 Oct 2020 16:36:09 +0800 Subject: [PATCH 003/271] test --- docs/AboutUs.md | 3 +++ src/test/java/seedu/duke/DukeTest.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..191e857bbe 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,4 +1,7 @@ # About us +we are an idiosyncratic and narcissistic batch of self-righteous +elitist who defends presumably morally questionable positions. + Display | Name | Github Profile | Portfolio --------|:----:|:--------------:|:---------: diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java index 2dda5fd651..fc8da31b5b 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/duke/DukeTest.java @@ -2,7 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; +import org.testng.annotations.Test; class DukeTest { @Test From e8e50dbe37a6556c8b4402e1619fd8e2fedfcf78 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 1 Oct 2020 17:00:51 +0800 Subject: [PATCH 004/271] Update AboutUs.md with name and GitHub profile --- docs/AboutUs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..2dccd95aba 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -6,4 +6,4 @@ Display | Name | Github Profile | Portfolio ![](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) +![](https://via.placeholder.com/100.png?text=Photo) | Heng Fu Yuen | [Github](https://github.com/HengFuYuen) | [Portfolio](docs/team/johndoe.md) From d8d740c0f14838e20e7cb5f1a2562d28c72a12bd Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Thu, 1 Oct 2020 20:45:53 +0800 Subject: [PATCH 005/271] heap --- docs/AboutUs.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 191e857bbe..0a84aca01d 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,6 +1,7 @@ # About us we are an idiosyncratic and narcissistic batch of self-righteous elitist who defends presumably morally questionable positions. +Also we are cheap! Display | Name | Github Profile | Portfolio From 40d517287e771da5588ce12e5dd21c5f4ce67467 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sun, 4 Oct 2020 10:08:40 +0800 Subject: [PATCH 006/271] hahahfdh --- src/test/java/seedu/duke/DukeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java index fc8da31b5b..2dda5fd651 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/duke/DukeTest.java @@ -2,7 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; class DukeTest { @Test From 7b2dfceb65a5b1074c0314e9880ca1803de4df47 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:00:04 +0800 Subject: [PATCH 007/271] data base --- src/main/java/seedu/duke/database/DataBase.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/java/seedu/duke/database/DataBase.java diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java new file mode 100644 index 0000000000..53d9a125fb --- /dev/null +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -0,0 +1,5 @@ +package seedu.duke.database; + +public class DataBase { + +} From e3111ed5d4b611c0794eb1178d2625fa7e3bdc61 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:13:32 +0800 Subject: [PATCH 008/271] create food class --- src/main/java/seedu/duke/food/Food.java | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/seedu/duke/food/Food.java diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java new file mode 100644 index 0000000000..9c5b3f47e0 --- /dev/null +++ b/src/main/java/seedu/duke/food/Food.java @@ -0,0 +1,32 @@ +package seedu.duke.food; + +public class Food { + private final String name; + private final int calorie; + private final int carbohydrate; + private final int protein; + public Food(String name, int calorie, int carbohydrate, int protein){ + this.name = name; + this.calorie = calorie; + this.carbohydrate = carbohydrate; + this.protein = protein; + } + + public String getName() { + return name; + } + + public int getCalorie() { + return calorie; + } + + public int getCarbohydrate() { + return carbohydrate; + } + + public int getProtein() { + return protein; + } + + +} From b70f0577db558740907c3eb652b73675326bd12f Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:17:26 +0800 Subject: [PATCH 009/271] create food class --- src/main/java/seedu/duke/food/Food.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 9c5b3f47e0..a6e9143d47 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -11,7 +11,7 @@ public Food(String name, int calorie, int carbohydrate, int protein){ this.carbohydrate = carbohydrate; this.protein = protein; } - + public String getName() { return name; } From f582e3d086dcb9a20ed123c7ed7b2f3fc3d6aa52 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:36:06 +0800 Subject: [PATCH 010/271] data base --- src/main/java/seedu/duke/database/DataBase.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 53d9a125fb..cf5de9c6ae 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -1,5 +1,10 @@ package seedu.duke.database; +import java.io.File; + public class DataBase { + private static final String root_directory = System.getProperty("user.home"); + private static final String duke_folder_name = root_directory + File.separator + "diet-duke"; + private static final String default_file_path = root_directory + File.separator + "diet-duke" + File.separator + "data-base"; } From 8e26b4c66b9c3e64a0534793a0767e1ec41b7202 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:37:20 +0800 Subject: [PATCH 011/271] no message --- src/main/java/seedu/duke/food/Food.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index a6e9143d47..8faad7266a 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -5,6 +5,7 @@ public class Food { private final int calorie; private final int carbohydrate; private final int protein; + public Food(String name, int calorie, int carbohydrate, int protein){ this.name = name; this.calorie = calorie; @@ -27,6 +28,4 @@ public int getCarbohydrate() { public int getProtein() { return protein; } - - } From 0d8b1336316803f6500052dd812944fef48ce680 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:39:17 +0800 Subject: [PATCH 012/271] fats --- src/main/java/seedu/duke/food/Food.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 8faad7266a..3730335a01 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -5,12 +5,18 @@ public class Food { private final int calorie; private final int carbohydrate; private final int protein; + private final int fats; - public Food(String name, int calorie, int carbohydrate, int protein){ + public Food(String name, int calorie, int carbohydrate, int protein, int fats){ this.name = name; this.calorie = calorie; this.carbohydrate = carbohydrate; this.protein = protein; + this.fats = fats; + } + + public int getFats() { + return fats; } public String getName() { From 36bf98256cc2603d5753d0696fb5775e2a641e21 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:56:35 +0800 Subject: [PATCH 013/271] add Store class add Canteen class --- src/main/java/seedu/duke/database/Canteen.java | 10 ++++++++++ src/main/java/seedu/duke/database/DataBase.java | 13 ++++++++----- src/main/java/seedu/duke/database/Store.java | 13 +++++++++++++ src/main/java/seedu/duke/database/data | 0 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/main/java/seedu/duke/database/Canteen.java create mode 100644 src/main/java/seedu/duke/database/Store.java create mode 100644 src/main/java/seedu/duke/database/data diff --git a/src/main/java/seedu/duke/database/Canteen.java b/src/main/java/seedu/duke/database/Canteen.java new file mode 100644 index 0000000000..3ec0409863 --- /dev/null +++ b/src/main/java/seedu/duke/database/Canteen.java @@ -0,0 +1,10 @@ +package seedu.duke.database; + +import java.util.ArrayList; + +public class Canteen { + private final ArrayList StoreList; + public Canteen(){ + this.StoreList = new ArrayList<>(); + } +} diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index cf5de9c6ae..8a5d1b2bb1 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -1,10 +1,13 @@ package seedu.duke.database; -import java.io.File; -public class DataBase { - private static final String root_directory = System.getProperty("user.home"); - private static final String duke_folder_name = root_directory + File.separator + "diet-duke"; - private static final String default_file_path = root_directory + File.separator + "diet-duke" + File.separator + "data-base"; +import seedu.duke.food.Food; +import java.util.ArrayList; +import java.util.Hashtable; + +public class DataBase{ + + public DataBase(){ + } } diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/duke/database/Store.java new file mode 100644 index 0000000000..2046081510 --- /dev/null +++ b/src/main/java/seedu/duke/database/Store.java @@ -0,0 +1,13 @@ +package seedu.duke.database; + +import seedu.duke.food.Food; + +import java.util.ArrayList; + +public class Store { + private final ArrayList FoodList; + public Store(){ + this.FoodList = new ArrayList<>(); + } + +} diff --git a/src/main/java/seedu/duke/database/data b/src/main/java/seedu/duke/database/data new file mode 100644 index 0000000000..e69de29bb2 From 0cd4e86189502b4e00b10836813f7b9bf197fbf2 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 7 Oct 2020 10:50:46 +0800 Subject: [PATCH 014/271] add more functions --- .../java/seedu/duke/database/Canteen.java | 21 ++++++++++++--- .../java/seedu/duke/database/DataBase.java | 14 +++++++--- src/main/java/seedu/duke/database/Store.java | 26 ++++++++++++++++--- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/duke/database/Canteen.java b/src/main/java/seedu/duke/database/Canteen.java index 3ec0409863..aa54fff639 100644 --- a/src/main/java/seedu/duke/database/Canteen.java +++ b/src/main/java/seedu/duke/database/Canteen.java @@ -3,8 +3,23 @@ import java.util.ArrayList; public class Canteen { - private final ArrayList StoreList; - public Canteen(){ - this.StoreList = new ArrayList<>(); + private final String name; + private final ArrayList storeList; + + public Canteen(String name){ + this.name = name; + this.storeList = new ArrayList<>(); + } + + /*** + * name of the canteen is for filtering purposes + * @return name of canteen + */ + public String getName() { + return name; + } + + public void addStore(Store store){ + storeList.add(store); } } diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 8a5d1b2bb1..993baeeb08 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -1,13 +1,19 @@ package seedu.duke.database; -import seedu.duke.food.Food; - import java.util.ArrayList; -import java.util.Hashtable; public class DataBase{ - + private final ArrayList canteenList; public DataBase(){ + this.canteenList = new ArrayList<>(); + init(); + } + + /*** + * Reads a file from + */ + private void init(){ + } } diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/duke/database/Store.java index 2046081510..31089e9b10 100644 --- a/src/main/java/seedu/duke/database/Store.java +++ b/src/main/java/seedu/duke/database/Store.java @@ -5,9 +5,27 @@ import java.util.ArrayList; public class Store { - private final ArrayList FoodList; - public Store(){ - this.FoodList = new ArrayList<>(); + private final String name; + private final ArrayList foodList; + + public Store(String name){ + this.name = name; + this.foodList = new ArrayList<>(); + } + + /*** + * the name of the store will be used for filtering purposes + * @return + */ + + public String getName() { + return name; + } + + /** + * This function should only be called when we initialize the data base from the text file + */ + public void addFood(Food food){ + foodList.add(food); } - } From 490054585b9a4d0839b8c4bf45831d2c03e92dde Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Wed, 7 Oct 2020 23:51:55 +0800 Subject: [PATCH 015/271] Add ActivityLevel.java ActivityLevel represents the level of physical activity a person enagages in. --- .../java/seedu/duke/person/ActivityLevel.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/seedu/duke/person/ActivityLevel.java diff --git a/src/main/java/seedu/duke/person/ActivityLevel.java b/src/main/java/seedu/duke/person/ActivityLevel.java new file mode 100644 index 0000000000..a045013b0d --- /dev/null +++ b/src/main/java/seedu/duke/person/ActivityLevel.java @@ -0,0 +1,37 @@ +package seedu.duke.person; + +/** + * Represents the physical activity level of a person or the amount of exercise a person engages in. + * An ActivityLevel has a description. + */ +public enum ActivityLevel { + NONE("You hardly engage in any exercise or have a job that requires little to no physical " + + "activity."), + LOW("You engage in some form of light exercise or have a job that requires some " + + "physical activity."), + MEDIUM("You engage in moderate amount of exercise or have a job that requires moderate " + + "physical activity."), + HIGH("You engage in vigorous exercise or have a physically demanding job."), + EXTREME("You engage in extremely vigorous exercise or have an extremely physically demanding" + + " job."); + + private final String description; + + /** + * Constructs an ActivityLevel given the description. + * + * @param description The description of the activity level. + */ + ActivityLevel(String description) { + this.description = description; + } + + /** + * Returns the description of the activity level. + * + * @return The description of the activity level. + */ + public String getDescription() { + return description; + } +} From b9db47c546c90e456706a8bed6f103ed8b6248f7 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Wed, 7 Oct 2020 23:54:08 +0800 Subject: [PATCH 016/271] Add Person.java A Person object contains all the relevant information of the user including age, height, original weight, target weight and activity level. --- src/main/java/seedu/duke/person/Person.java | 126 ++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/main/java/seedu/duke/person/Person.java diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java new file mode 100644 index 0000000000..314b5b3092 --- /dev/null +++ b/src/main/java/seedu/duke/person/Person.java @@ -0,0 +1,126 @@ +package seedu.duke.person; + +/** + * Represents a Person. + * A Person has an age, height, certain activity level, original and desired weight. + */ +public class Person { + + /* The height of the person in cm */ + private int height; + /* The original weight of the person in kg */ + private int originalWeight; + /* The target weight of the person in kg */ + private int targetWeight; + private int age; + private ActivityLevel activityLevel; + + /** + * Constructs a Person with the given age, height, original weight, target weight and + * activity level. + * + * @param age The age of the person. + * @param height The height of the person. + * @param originalWeight The original weight of the person. + * @param targetWeight The target/desired weight that the person wants to achieve. + * @param activityLevel The activity level of the person or in other words, the amount of exercise the + * person engages in. + */ + public Person(int age, int height, int originalWeight, int targetWeight, ActivityLevel activityLevel) { + this.age = age; + this.height = height; + this.originalWeight = originalWeight; + this.targetWeight = targetWeight; + this.activityLevel = activityLevel; + } + + /** + * Returns the age of the person. + * + * @return The age of the person. + */ + public int getAge() { + return age; + } + + /** + * Sets the age of the person to the new age that is given. + * + * @param newAge The new/revised age of the person. + */ + public void setAge(int newAge) { + age = newAge; + } + + /** + * Returns the height of the person. + * + * @return The height of the person. + */ + public int getHeight() { + return height; + } + + /** + * Sets the height of the person to the new height given. + * + * @param newHeight The new/revised height of the person. + */ + public void setHeight(int newHeight) { + height = newHeight; + } + + /** + * Returns the original weight of the person. + * + * @return The original weight of the person. + */ + public int getOriginalWeight() { + return originalWeight; + } + + /** + * Sets the original weight of the person to the new original weight given. + * + * @param newOriginalWeight The new/revised original weight of the person. + */ + public void setOriginalWeight(int newOriginalWeight) { + originalWeight = newOriginalWeight; + } + + /** + * Returns the target weight the person the person wants to achieve. + * + * @return The target weight the person wants to achieve. + */ + public int getTargetWeight() { + return targetWeight; + } + + /** + * Sets the target weight of the person to the new target weight given. + * + * @param newTargetWeight The new/revised target weight of the person. + */ + public void setTargetWeight(int newTargetWeight) { + targetWeight = newTargetWeight; + } + + /** + * Returns the activity level of the person. + * + * @return The activity level of the person. + */ + public ActivityLevel getActivityLevel() { + return activityLevel; + } + + /** + * Sets the activity level of the person to the new activity level given. + * + * @param newActivityLevel The new/revised activity level of the person. + */ + public void getActivityLevel(ActivityLevel newActivityLevel) { + activityLevel = newActivityLevel; + } +} From fa84230f794e597148c6dc8214b276d73245dc20 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 8 Oct 2020 00:15:43 +0800 Subject: [PATCH 017/271] Person class: correct setter method name The setter method for activity level previously had a getter naming style. --- src/main/java/seedu/duke/person/Person.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java index 314b5b3092..d29131135f 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/duke/person/Person.java @@ -120,7 +120,7 @@ public ActivityLevel getActivityLevel() { * * @param newActivityLevel The new/revised activity level of the person. */ - public void getActivityLevel(ActivityLevel newActivityLevel) { + public void setActivityLevel(ActivityLevel newActivityLevel) { activityLevel = newActivityLevel; } } From 29a016bae6efe4a28b42910e2c31734a0afd5619 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 8 Oct 2020 17:50:40 +0800 Subject: [PATCH 018/271] Add JUnit tests for Person class --- .../java/seedu/duke/person/PersonTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/test/java/seedu/duke/person/PersonTest.java diff --git a/src/test/java/seedu/duke/person/PersonTest.java b/src/test/java/seedu/duke/person/PersonTest.java new file mode 100644 index 0000000000..0685a0383c --- /dev/null +++ b/src/test/java/seedu/duke/person/PersonTest.java @@ -0,0 +1,71 @@ +package seedu.duke.person; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PersonTest { + + private Person person; + + @BeforeEach + public void setUp() { + person = new Person(21,165,65,55,ActivityLevel.LOW); + } + + @Test + void getAge_person_returnsAge() { + assertEquals(person.getAge(),21); + } + + @Test + void setAge_personWithNewAge_returnsNewAge() { + person.setAge(24); + assertEquals(person.getAge(),24); + } + + @Test + void getHeight_person_returnsHeight() { + assertEquals(person.getHeight(),165); + } + + @Test + void setHeight_personWithNewHeight_returnsNewHeight() { + person.setHeight(175); + assertEquals(person.getHeight(),175); + } + + @Test + void getOriginalWeight_person_returnsOriginalWeight() { + assertEquals(person.getOriginalWeight(),65); + } + + @Test + void setOriginalWeight_personWithNewOriginalWeight_returnsNewOriginalWeight() { + person.setOriginalWeight(70); + assertEquals(person.getOriginalWeight(),70); + } + + @Test + void getTargetWeight_person_returnsTargetWeight() { + assertEquals(person.getTargetWeight(),55); + } + + @Test + void setTargetWeight_personWithNewTargetWeight_returnsNewTargetWeight() { + person.setTargetWeight(50); + assertEquals(person.getTargetWeight(),50); + } + + @Test + void getActivityLevel_person_returnsActivityLevel() { + assertEquals(person.getActivityLevel(),ActivityLevel.LOW); + } + + @Test + void setActivityLevel_personWithNewActivityLevel_returnsNewActivityLevel() { + person.setActivityLevel(ActivityLevel.HIGH); + assertEquals(person.getActivityLevel(),ActivityLevel.HIGH); + } +} \ No newline at end of file From 38681f25be2d04491d0e28a75f3457c11a122716 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 8 Oct 2020 17:52:33 +0800 Subject: [PATCH 019/271] Add newline at end of file --- src/test/java/seedu/duke/person/PersonTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/duke/person/PersonTest.java b/src/test/java/seedu/duke/person/PersonTest.java index 0685a0383c..7839f6dc54 100644 --- a/src/test/java/seedu/duke/person/PersonTest.java +++ b/src/test/java/seedu/duke/person/PersonTest.java @@ -68,4 +68,4 @@ void setActivityLevel_personWithNewActivityLevel_returnsNewActivityLevel() { person.setActivityLevel(ActivityLevel.HIGH); assertEquals(person.getActivityLevel(),ActivityLevel.HIGH); } -} \ No newline at end of file +} From ffcf350531c267b90eefac148487d2557d37423d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Fri, 9 Oct 2020 10:12:32 +0800 Subject: [PATCH 020/271] PersonTest.java: swap expected and actual ouput --- .../java/seedu/duke/person/PersonTest.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/test/java/seedu/duke/person/PersonTest.java b/src/test/java/seedu/duke/person/PersonTest.java index 7839f6dc54..b599cdce68 100644 --- a/src/test/java/seedu/duke/person/PersonTest.java +++ b/src/test/java/seedu/duke/person/PersonTest.java @@ -16,56 +16,62 @@ public void setUp() { @Test void getAge_person_returnsAge() { - assertEquals(person.getAge(),21); + assertEquals(21, person.getAge()); } @Test void setAge_personWithNewAge_returnsNewAge() { person.setAge(24); - assertEquals(person.getAge(),24); + assertEquals(24, person.getAge()); } @Test void getHeight_person_returnsHeight() { - assertEquals(person.getHeight(),165); + assertEquals(165, person.getHeight()); } @Test void setHeight_personWithNewHeight_returnsNewHeight() { person.setHeight(175); - assertEquals(person.getHeight(),175); + assertEquals(175, person.getHeight()); } @Test void getOriginalWeight_person_returnsOriginalWeight() { - assertEquals(person.getOriginalWeight(),65); + assertEquals(65, person.getOriginalWeight()); } @Test void setOriginalWeight_personWithNewOriginalWeight_returnsNewOriginalWeight() { person.setOriginalWeight(70); - assertEquals(person.getOriginalWeight(),70); + assertEquals(70, person.getOriginalWeight()); } @Test void getTargetWeight_person_returnsTargetWeight() { - assertEquals(person.getTargetWeight(),55); + assertEquals(55, person.getTargetWeight()); } @Test void setTargetWeight_personWithNewTargetWeight_returnsNewTargetWeight() { person.setTargetWeight(50); - assertEquals(person.getTargetWeight(),50); + assertEquals(50, person.getTargetWeight()); } @Test void getActivityLevel_person_returnsActivityLevel() { - assertEquals(person.getActivityLevel(),ActivityLevel.LOW); + assertEquals(ActivityLevel.LOW, person.getActivityLevel()); } @Test void setActivityLevel_personWithNewActivityLevel_returnsNewActivityLevel() { person.setActivityLevel(ActivityLevel.HIGH); - assertEquals(person.getActivityLevel(),ActivityLevel.HIGH); + assertEquals(ActivityLevel.HIGH, person.getActivityLevel()); + } + + @Test + void setActivityLevel_personWithNullActivityLevel_returnsNullActivityLevel() { + person.setActivityLevel(null); + assertEquals(null, person.getActivityLevel()); } } From d90f5fa7cee02e6dae36cdd87708d4ff84ad930f Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 13:10:55 +0800 Subject: [PATCH 021/271] start implementing init the init function is very complicated --- .../java/seedu/duke/database/Canteen.java | 5 ++ .../java/seedu/duke/database/DataBase.java | 88 ++++++++++++++++++- .../duke/database/DataBaseReadState.java | 49 +++++++++++ src/main/java/seedu/duke/database/Store.java | 7 ++ src/main/java/seedu/duke/database/data | 46 ++++++++++ 5 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 src/main/java/seedu/duke/database/DataBaseReadState.java diff --git a/src/main/java/seedu/duke/database/Canteen.java b/src/main/java/seedu/duke/database/Canteen.java index aa54fff639..fd3a92deff 100644 --- a/src/main/java/seedu/duke/database/Canteen.java +++ b/src/main/java/seedu/duke/database/Canteen.java @@ -1,6 +1,7 @@ package seedu.duke.database; import java.util.ArrayList; +import java.util.List; public class Canteen { private final String name; @@ -22,4 +23,8 @@ public String getName() { public void addStore(Store store){ storeList.add(store); } + + public List getStoreList() { + return storeList; + } } diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 993baeeb08..31566a086d 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -1,19 +1,101 @@ package seedu.duke.database; +import seedu.duke.food.Food; + +import java.io.File; +import java.io.FileNotFoundException; import java.util.ArrayList; +import java.util.Scanner; public class DataBase{ + private static final String START_SYMBOL = "&%START"; + private static final String STOP_SYMBOL = "&%STOP"; + private static final String UP_SYMBOL = "&%UP"; + private final ArrayList canteenList; + public DataBase(){ this.canteenList = new ArrayList<>(); - init(); } /*** - * Reads a file from + * Reads a file from the data base and puts it into the DataBase object */ - private void init(){ + public void init() throws FileNotFoundException { + File dataFile = new File(System.getProperty("user.dir") + File.separator + "data.txt"); + Scanner fileReader = new Scanner(dataFile); + String fileLine; + String[] fileData; + boolean start = false; + boolean hasPreviousCanteen = false; + boolean hasPreviousStore = false; + DataBaseReadState readState = DataBaseReadState.CANTEEN; + Canteen currentCanteen = new Canteen("dummy"); + Store currentStore = new Store("dummy"); + Food currentFood; + while (fileReader.hasNext()){ + fileLine = fileReader.nextLine(); + fileData = fileLine.split("\\|"); + // ------ Check if the data base has started scanning ------ + if (fileLine.equals(START_SYMBOL)){ + start = true; + continue; + } + if (!(start)){ + continue; + } + if (fileLine.equals(STOP_SYMBOL)){ + break; + } + // ------ Adjust the state of the data base and end the reading at the lower level ------- + if (fileLine.equals(UP_SYMBOL)){ + if (readState == DataBaseReadState.FOOD){ + currentCanteen.addStore(currentStore); + } + readState = DataBaseReadState.raiseState(readState); + continue; + } + // ----- Start reading the file here ------ + if (readState == DataBaseReadState.CANTEEN){ + if (hasPreviousCanteen){ + canteenList.add(currentCanteen); + } + currentCanteen = new Canteen(fileData[0]); + readState = DataBaseReadState.lowerState(readState); + hasPreviousCanteen = true; + hasPreviousStore = false; + } + else if (readState == DataBaseReadState.STORE){ + if (hasPreviousStore){ + currentCanteen.addStore(currentStore); + } + currentStore = new Store(fileData[0]); + hasPreviousStore = true; + } + else{ + currentFood = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]), + Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); + currentStore.addFood(currentFood); + } + } + } + + /*** + * Debugging function prints out all contents + */ + public void printAllData(){ + System.out.println("Printing out all data"); + for (Canteen canteen : canteenList){ + System.out.println("Canteeh : " + canteen.getName()); + for (Store store : canteen.getStoreList()){ + System.out.println("Store : " + store.getName()); + for (Food food : store.getFoodList()){ + System.out.println(food); + } + } + } + System.out.println("Finished Printing out all data"); } } diff --git a/src/main/java/seedu/duke/database/DataBaseReadState.java b/src/main/java/seedu/duke/database/DataBaseReadState.java new file mode 100644 index 0000000000..eae8999750 --- /dev/null +++ b/src/main/java/seedu/duke/database/DataBaseReadState.java @@ -0,0 +1,49 @@ +package seedu.duke.database; + + +/*** + * This class is used when data base is reading the data from the file + */ +public enum DataBaseReadState { + CANTEEN, + STORE, + FOOD; + + /*** + * lowers the initial state from e.g. CANTEEN ----> STORE + * There will be at most 4 states so this can just be hard coded + * @param initialState the initial state + * @return the state lowered by 1 level, or the same state if there is no lower state + */ + public static DataBaseReadState lowerState(DataBaseReadState initialState){ + DataBaseReadState loweredState; + switch (initialState){ + case CANTEEN: + loweredState = STORE; + break; + case STORE: + loweredState = FOOD; + break; + default: + loweredState = initialState; + break; + } + return loweredState; + } + + public static DataBaseReadState raiseState(DataBaseReadState initialState){ + DataBaseReadState raisedState; + switch (initialState){ + case STORE: + raisedState = CANTEEN; + break; + case FOOD: + raisedState = STORE; + break; + default: + raisedState = initialState; + break; + } + return raisedState; + } +} diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/duke/database/Store.java index 31089e9b10..c34c7dac80 100644 --- a/src/main/java/seedu/duke/database/Store.java +++ b/src/main/java/seedu/duke/database/Store.java @@ -3,11 +3,13 @@ import seedu.duke.food.Food; import java.util.ArrayList; +import java.util.List; public class Store { private final String name; private final ArrayList foodList; + public Store(String name){ this.name = name; this.foodList = new ArrayList<>(); @@ -28,4 +30,9 @@ public String getName() { public void addFood(Food food){ foodList.add(food); } + + public List getFoodList() { + return foodList; + } + } diff --git a/src/main/java/seedu/duke/database/data b/src/main/java/seedu/duke/database/data index e69de29bb2..88b7ed720f 100644 --- a/src/main/java/seedu/duke/database/data +++ b/src/main/java/seedu/duke/database/data @@ -0,0 +1,46 @@ +##################################################################### +# 3 LEVEL DATA BASE # +# Canteen -----> Store ------> Food # +# Commands : # +# &%START : start reading data from the data base # +# &%STOP : stop reading data from the data base # +# &%UP : goes down 1 level e.g. Canteen ---> Store # +# &%DOWN : goes down 1 level e.g. Canteen ---> Store # +# &%ADD format : adds the item with the given format # +# # +# Comments : any line that starts with # is ignored # +# # +# Canteen format : {name} # +# Store format : {name} # +# Food format : {name}|{Calorie}|{Carb}|{Protein}|{Fat} # +##################################################################### + +###################################################################### +# Version 0.1 : # +# there is only UP, once a store or canteen is # +# specified we automatically go down 1 level , for this version # +# there is no going out of a store and then coming back to add more# +# Units : Calorie : kcal : Carbs : g Protein : g : Fats : g # +###################################################################### + +&%START +Science canteen +Halal Mini Wok +Prawn Mee Soup(Dry)(Large)|490|0|0|0 +Prawn Mee Soup(Dry)(Small)|390|0|0|0 +Fried Hokkien Prawn Mee(Large)|470|0|0|0 +Fried Hokkien Prawn Mee(Small)|350|0|0|0 +Clay Pot Chicken|440|0|0|0 +Black Pepper Chicken|490|0|0|0 +&%UP +Ayam Penyet +Ayam Penyet Set|699|0|0|0 +Steamed Chicken Set |475|0|0|0 +Ikan Grouper Penyet Set|669|0|0|0 +&%UP +Michelin Star Restaurant +Bouillabaisse with cock crab and poached lobster|520|45|35|56 +Chicken wings with Reblochon pomme purée|450|25|32|66 +Sea bass with prawn tortellini, fennel purée and white wine sauce|530|76|25|43 +&%STOP + From 1a2b2fa3ab55ff3080a18bd8c7ccb6628209f0d9 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 13:42:42 +0800 Subject: [PATCH 022/271] made another implementation of init() that is easier to understand --- .../java/seedu/duke/database/DataBase.java | 82 ++++++++++--------- src/main/java/seedu/duke/database/data | 2 + 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 31566a086d..0e8f89f308 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -13,6 +13,8 @@ public class DataBase{ private static final String STOP_SYMBOL = "&%STOP"; private static final String UP_SYMBOL = "&%UP"; + private static final String DATA_FILE_SEPERATOR = "\\|"; + private final ArrayList canteenList; public DataBase(){ @@ -26,17 +28,9 @@ public void init() throws FileNotFoundException { File dataFile = new File(System.getProperty("user.dir") + File.separator + "data.txt"); Scanner fileReader = new Scanner(dataFile); String fileLine; - String[] fileData; boolean start = false; - boolean hasPreviousCanteen = false; - boolean hasPreviousStore = false; - DataBaseReadState readState = DataBaseReadState.CANTEEN; - Canteen currentCanteen = new Canteen("dummy"); - Store currentStore = new Store("dummy"); - Food currentFood; while (fileReader.hasNext()){ fileLine = fileReader.nextLine(); - fileData = fileLine.split("\\|"); // ------ Check if the data base has started scanning ------ if (fileLine.equals(START_SYMBOL)){ start = true; @@ -48,38 +42,50 @@ public void init() throws FileNotFoundException { if (fileLine.equals(STOP_SYMBOL)){ break; } + canteenList.add(fillCanteen(fileLine, fileReader)); + } + } - // ------ Adjust the state of the data base and end the reading at the lower level ------- - if (fileLine.equals(UP_SYMBOL)){ - if (readState == DataBaseReadState.FOOD){ - currentCanteen.addStore(currentStore); - } - readState = DataBaseReadState.raiseState(readState); - continue; - } - // ----- Start reading the file here ------ - if (readState == DataBaseReadState.CANTEEN){ - if (hasPreviousCanteen){ - canteenList.add(currentCanteen); - } - currentCanteen = new Canteen(fileData[0]); - readState = DataBaseReadState.lowerState(readState); - hasPreviousCanteen = true; - hasPreviousStore = false; - } - else if (readState == DataBaseReadState.STORE){ - if (hasPreviousStore){ - currentCanteen.addStore(currentStore); - } - currentStore = new Store(fileData[0]); - hasPreviousStore = true; - } - else{ - currentFood = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]), - Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); - currentStore.addFood(currentFood); - } + /*** + * This function is called right after the canteen name is provided + * The very next line that the file reads is the store name + * It will turn call fillStore with that name inserted, when the function fillStore + * finishes executing, fileRead.nextLine() can either provide a new store name or UP_SYMBOL + * if the UP_SYMBOL is provided, the function ends and the final Canteen object is returned + * @param name + * @param fileSegment + * @return + */ + private Canteen fillCanteen(String name, Scanner fileSegment){ + Canteen canteen = new Canteen(name); + String fileLine = fileSegment.nextLine(); + while (!(fileLine.equals(UP_SYMBOL))){ + canteen.addStore(fillStore(name,fileSegment)); + fileLine = fileSegment.nextLine(); + } + return canteen; + } + + /*** + * This function is called right after the store name is provided + * The very next line in the file should be the first food to be added + * The function stops when it hits the line of the file that says UP_SYMBOL + * @param name name of the store + * @param fileSegment the Scanner object used for the init() function + * @return the completed store with all the food loaded + */ + private Store fillStore(String name, Scanner fileSegment){ + Store store = new Store(name); + Food food; + String fileLine = fileSegment.nextLine(); + String[] fileData = fileLine.split(DATA_FILE_SEPERATOR); + while (!(fileLine.equals(UP_SYMBOL))){ + food = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]) + ,Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); + fileLine = fileSegment.nextLine(); + fileData = fileLine.split(DATA_FILE_SEPERATOR); } + return store; } /*** diff --git a/src/main/java/seedu/duke/database/data b/src/main/java/seedu/duke/database/data index 88b7ed720f..7a211bc4e1 100644 --- a/src/main/java/seedu/duke/database/data +++ b/src/main/java/seedu/duke/database/data @@ -42,5 +42,7 @@ Michelin Star Restaurant Bouillabaisse with cock crab and poached lobster|520|45|35|56 Chicken wings with Reblochon pomme purée|450|25|32|66 Sea bass with prawn tortellini, fennel purée and white wine sauce|530|76|25|43 +&%UP +&%UP &%STOP From cdee1559ca69c1e8fa8497d3efaf6a0962820c9c Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 14:53:25 +0800 Subject: [PATCH 023/271] implement initializing of data base --- src/main/java/seedu/duke/database/DataBase.java | 8 +++++++- .../java/seedu/duke/database/{data => data.txt} | 0 .../java/seedu/duke/database/DataBaseTest.java | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) rename src/main/java/seedu/duke/database/{data => data.txt} (100%) create mode 100644 src/test/java/seedu/duke/database/DataBaseTest.java diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 0e8f89f308..42f43f720c 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -15,6 +15,10 @@ public class DataBase{ private static final String DATA_FILE_SEPERATOR = "\\|"; + private static final String rootDirectory = System.getProperty("user.dir"); + private static final String dataFileFolder = "src" + File.separator + "main" + File.separator + + "java" + File.separator + "seedu" + File.separator + "duke" + File.separator + "database"; + private final ArrayList canteenList; public DataBase(){ @@ -25,7 +29,8 @@ public DataBase(){ * Reads a file from the data base and puts it into the DataBase object */ public void init() throws FileNotFoundException { - File dataFile = new File(System.getProperty("user.dir") + File.separator + "data.txt"); + String fileFolder = rootDirectory + File.separator + dataFileFolder; + File dataFile = new File( fileFolder + File.separator + "data.txt"); Scanner fileReader = new Scanner(dataFile); String fileLine; boolean start = false; @@ -82,6 +87,7 @@ private Store fillStore(String name, Scanner fileSegment){ while (!(fileLine.equals(UP_SYMBOL))){ food = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]) ,Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); + store.addFood(food); fileLine = fileSegment.nextLine(); fileData = fileLine.split(DATA_FILE_SEPERATOR); } diff --git a/src/main/java/seedu/duke/database/data b/src/main/java/seedu/duke/database/data.txt similarity index 100% rename from src/main/java/seedu/duke/database/data rename to src/main/java/seedu/duke/database/data.txt diff --git a/src/test/java/seedu/duke/database/DataBaseTest.java b/src/test/java/seedu/duke/database/DataBaseTest.java new file mode 100644 index 0000000000..4551e8571a --- /dev/null +++ b/src/test/java/seedu/duke/database/DataBaseTest.java @@ -0,0 +1,17 @@ +package seedu.duke.database; + +import java.io.FileNotFoundException; + +import static org.junit.jupiter.api.Assertions.*; + +class DataBaseTest { + public static void main(String[] args){ + DataBase database = new DataBase(); + try { + database.init(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + database.printAllData(); + } +} \ No newline at end of file From 90a72a28d90fac81bab27b688952373be059a508 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 14:55:07 +0800 Subject: [PATCH 024/271] no message --- src/main/java/seedu/duke/database/DataBase.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 42f43f720c..2465312513 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -110,4 +110,7 @@ public void printAllData(){ } System.out.println("Finished Printing out all data"); } + + // -------- Search functions -------- + } From 00fd7a46c7bc7e226c25b7af666f2503e42fdd8b Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 14:58:33 +0800 Subject: [PATCH 025/271] implement food toString method --- src/main/java/seedu/duke/food/Food.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 3730335a01..3c0c545a28 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -34,4 +34,10 @@ public int getCarbohydrate() { public int getProtein() { return protein; } + + @Override + public String toString(){ + return name + " :: calorie : " + calorie + " :: protein : " + protein + ":: carbohydrate :" + carbohydrate + + ":: fats :" + fats; + } } From 2254fcd44ddc5f5b308613dd1e1dbd9f636ea8e5 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 15:03:32 +0800 Subject: [PATCH 026/271] fix bug with store name --- src/main/java/seedu/duke/database/DataBase.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 2465312513..9419c0386c 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -57,15 +57,15 @@ public void init() throws FileNotFoundException { * It will turn call fillStore with that name inserted, when the function fillStore * finishes executing, fileRead.nextLine() can either provide a new store name or UP_SYMBOL * if the UP_SYMBOL is provided, the function ends and the final Canteen object is returned - * @param name - * @param fileSegment + * @param name name of store + * @param fileSegment the file reader with the next line being a food item or UP_SYMBOL * @return */ private Canteen fillCanteen(String name, Scanner fileSegment){ Canteen canteen = new Canteen(name); String fileLine = fileSegment.nextLine(); while (!(fileLine.equals(UP_SYMBOL))){ - canteen.addStore(fillStore(name,fileSegment)); + canteen.addStore(fillStore(fileLine,fileSegment)); fileLine = fileSegment.nextLine(); } return canteen; From 8bda40256a89bbb727ac7f19ce01f5849fc9bb42 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 15:04:58 +0800 Subject: [PATCH 027/271] update toString --- src/main/java/seedu/duke/food/Food.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 3c0c545a28..a4537525f5 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -37,7 +37,7 @@ public int getProtein() { @Override public String toString(){ - return name + " :: calorie : " + calorie + " :: protein : " + protein + ":: carbohydrate :" + carbohydrate - + ":: fats :" + fats; + return name + "\\| calorie : " + calorie + "\\| protein : " + protein + "\\| carbohydrate : " + carbohydrate + + "\\| fats : " + fats; } } From 3b788d61c15cc9a54ef7331a2732dc9bc93fae47 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 15:10:16 +0800 Subject: [PATCH 028/271] adjust toString method Add FoodTest --- src/main/java/seedu/duke/food/Food.java | 4 ++-- src/test/java/seedu/duke/food/FoodTest.java | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/test/java/seedu/duke/food/FoodTest.java diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index a4537525f5..941e8e3944 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -37,7 +37,7 @@ public int getProtein() { @Override public String toString(){ - return name + "\\| calorie : " + calorie + "\\| protein : " + protein + "\\| carbohydrate : " + carbohydrate - + "\\| fats : " + fats; + return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate + + " | fats : " + fats; } } diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java new file mode 100644 index 0000000000..70c30be1ca --- /dev/null +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -0,0 +1,12 @@ +package seedu.duke.food; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class FoodTest { + public static void main(String[] args){ + Food food = new Food("Kobe Beef", 480,50,40,30); + System.out.println(food); + } +} \ No newline at end of file From 6e225ef145d9cc5d514a1159251c5d8ea44528f5 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 15:12:23 +0800 Subject: [PATCH 029/271] removed deadcode DataBaseReadState --- .../duke/database/DataBaseReadState.java | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 src/main/java/seedu/duke/database/DataBaseReadState.java diff --git a/src/main/java/seedu/duke/database/DataBaseReadState.java b/src/main/java/seedu/duke/database/DataBaseReadState.java deleted file mode 100644 index eae8999750..0000000000 --- a/src/main/java/seedu/duke/database/DataBaseReadState.java +++ /dev/null @@ -1,49 +0,0 @@ -package seedu.duke.database; - - -/*** - * This class is used when data base is reading the data from the file - */ -public enum DataBaseReadState { - CANTEEN, - STORE, - FOOD; - - /*** - * lowers the initial state from e.g. CANTEEN ----> STORE - * There will be at most 4 states so this can just be hard coded - * @param initialState the initial state - * @return the state lowered by 1 level, or the same state if there is no lower state - */ - public static DataBaseReadState lowerState(DataBaseReadState initialState){ - DataBaseReadState loweredState; - switch (initialState){ - case CANTEEN: - loweredState = STORE; - break; - case STORE: - loweredState = FOOD; - break; - default: - loweredState = initialState; - break; - } - return loweredState; - } - - public static DataBaseReadState raiseState(DataBaseReadState initialState){ - DataBaseReadState raisedState; - switch (initialState){ - case STORE: - raisedState = CANTEEN; - break; - case FOOD: - raisedState = STORE; - break; - default: - raisedState = initialState; - break; - } - return raisedState; - } -} From d9bec8445c623b4024094909d5afbd5bdf74a734 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:14:03 +0800 Subject: [PATCH 030/271] implement database query functions search by food name, list first, list all search by store, list first store, list all store search by food and store --- .../java/seedu/duke/database/DataBase.java | 106 +++++++++++++++--- src/main/java/seedu/duke/database/Store.java | 1 + src/main/java/seedu/duke/food/Food.java | 2 +- 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 9419c0386c..593ba6ff8a 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -6,9 +6,12 @@ import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; import java.util.Scanner; +import java.util.stream.Stream; -public class DataBase{ +public class DataBase { private static final String START_SYMBOL = "&%START"; private static final String STOP_SYMBOL = "&%STOP"; private static final String UP_SYMBOL = "&%UP"; @@ -19,9 +22,9 @@ public class DataBase{ private static final String dataFileFolder = "src" + File.separator + "main" + File.separator + "java" + File.separator + "seedu" + File.separator + "duke" + File.separator + "database"; - private final ArrayList canteenList; + private final List canteenList; - public DataBase(){ + public DataBase() { this.canteenList = new ArrayList<>(); } @@ -30,21 +33,21 @@ public DataBase(){ */ public void init() throws FileNotFoundException { String fileFolder = rootDirectory + File.separator + dataFileFolder; - File dataFile = new File( fileFolder + File.separator + "data.txt"); + File dataFile = new File(fileFolder + File.separator + "data.txt"); Scanner fileReader = new Scanner(dataFile); String fileLine; boolean start = false; - while (fileReader.hasNext()){ + while (fileReader.hasNext()) { fileLine = fileReader.nextLine(); // ------ Check if the data base has started scanning ------ - if (fileLine.equals(START_SYMBOL)){ + if (fileLine.equals(START_SYMBOL)) { start = true; continue; } if (!(start)){ continue; } - if (fileLine.equals(STOP_SYMBOL)){ + if (fileLine.equals(STOP_SYMBOL)) { break; } canteenList.add(fillCanteen(fileLine, fileReader)); @@ -61,10 +64,10 @@ public void init() throws FileNotFoundException { * @param fileSegment the file reader with the next line being a food item or UP_SYMBOL * @return */ - private Canteen fillCanteen(String name, Scanner fileSegment){ + private Canteen fillCanteen(String name, Scanner fileSegment) { Canteen canteen = new Canteen(name); String fileLine = fileSegment.nextLine(); - while (!(fileLine.equals(UP_SYMBOL))){ + while (!(fileLine.equals(UP_SYMBOL))) { canteen.addStore(fillStore(fileLine,fileSegment)); fileLine = fileSegment.nextLine(); } @@ -79,12 +82,12 @@ private Canteen fillCanteen(String name, Scanner fileSegment){ * @param fileSegment the Scanner object used for the init() function * @return the completed store with all the food loaded */ - private Store fillStore(String name, Scanner fileSegment){ + private Store fillStore(String name, Scanner fileSegment) { Store store = new Store(name); Food food; String fileLine = fileSegment.nextLine(); String[] fileData = fileLine.split(DATA_FILE_SEPERATOR); - while (!(fileLine.equals(UP_SYMBOL))){ + while (!(fileLine.equals(UP_SYMBOL))) { food = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]) ,Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); store.addFood(food); @@ -97,7 +100,7 @@ private Store fillStore(String name, Scanner fileSegment){ /*** * Debugging function prints out all contents */ - public void printAllData(){ + public void printAllData() { System.out.println("Printing out all data"); for (Canteen canteen : canteenList){ System.out.println("Canteeh : " + canteen.getName()); @@ -112,5 +115,82 @@ public void printAllData(){ } // -------- Search functions -------- - + + /*** + * this method searchs the whole data base and returns the first food item whose name contains the provided string + * @param food part of the name of the food + * @return Food + * @throws NoSuchElementException if no food contains the name provided + */ + public Food searchFoodByName(String food) { + return foodStream().filter( x -> x.getName().contains(food)).findFirst().orElseThrow(); + } + + /*** + * this method searchs the whole data base and returns all of the food whose name contains the provided string + * @param food part of the name of the food e.g. chicken + * @return data stream of all food items + */ + public Stream searchAllFoodContainingName(String food) { + return foodStream().filter( x -> x.getName().contains(food)); + } + + /*** + * search for the first food that contains the string provided in the first store which matchs the store + * string provided + * @param food partial name of the food + * @param store partial name of the store + * @return Food object + */ + public Food searchFoodByNameByStore(String food, String store){ + return canteenList.stream() + .flatMap( x -> x.getStoreList().stream()) + .filter( x -> x.getName().contains(store)) + .findFirst() + .orElseThrow() + .getFoodList() + .stream() + .filter( x -> x.getName().contains(food)) + .findFirst() + .orElseThrow(); + } + + /*** + * This method returns a stream of all the food in the first store that contains the given string + * @param store partial name of the store + * @return food stream + */ + public Stream searchAllFoodOfStore(String store) { + return canteenList.stream() + .flatMap( x -> x.getStoreList().stream()) + .filter( x -> x.getName().contains(store)) + .findFirst() + .orElseThrow() + .getFoodList() + .stream(); + } + + /*** + * this method returns a stream of all the food in all stores that contains the given string + * @param store partial name of the store + * @return food stream + */ + public Stream searchAllFoodOfAllStores(String store){ + return canteenList.stream() + .flatMap( x -> x.getStoreList().stream()) + .filter( x -> x.getName().contains(store)) + .flatMap( x -> x.getFoodList().stream()); + } + + /*** + * Provides a data stream of all the food in the data base + * @return a food stream + */ + private Stream foodStream() { + return canteenList.stream() + .flatMap( x -> x.getStoreList().stream()) + .flatMap( x -> x.getFoodList().stream()); + } + + } diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/duke/database/Store.java index c34c7dac80..5d1727d67b 100644 --- a/src/main/java/seedu/duke/database/Store.java +++ b/src/main/java/seedu/duke/database/Store.java @@ -3,6 +3,7 @@ import seedu.duke.food.Food; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class Store { diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 941e8e3944..2572c66aff 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -36,7 +36,7 @@ public int getProtein() { } @Override - public String toString(){ + public String toString() { return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate + " | fats : " + fats; } From 04c9ad22815c14990a4d30969c3d64b3aabebe6c Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:28:27 +0800 Subject: [PATCH 031/271] implement searchFoodByNameByCanteen searchAllFoodByNameByCanteen searchAllFoodBetweenCalorie --- .../java/seedu/duke/database/DataBase.java | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 593ba6ff8a..8dbdb772b5 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -143,13 +143,7 @@ public Stream searchAllFoodContainingName(String food) { * @return Food object */ public Food searchFoodByNameByStore(String food, String store){ - return canteenList.stream() - .flatMap( x -> x.getStoreList().stream()) - .filter( x -> x.getName().contains(store)) - .findFirst() - .orElseThrow() - .getFoodList() - .stream() + return searchAllFoodByStore(store) .filter( x -> x.getName().contains(food)) .findFirst() .orElseThrow(); @@ -160,7 +154,7 @@ public Food searchFoodByNameByStore(String food, String store){ * @param store partial name of the store * @return food stream */ - public Stream searchAllFoodOfStore(String store) { + public Stream searchAllFoodByStore(String store) { return canteenList.stream() .flatMap( x -> x.getStoreList().stream()) .filter( x -> x.getName().contains(store)) @@ -182,15 +176,48 @@ public Stream searchAllFoodOfAllStores(String store){ .flatMap( x -> x.getFoodList().stream()); } + + /*** + * this method returns the first food that matchs the + * @param food partial name of the food + * @param canteen partial name of the canteen + * @return Food object + */ + public Food searchFoodByNameByCanteen(String food, String canteen){ + return searchAllFoodByNameByCanteen(food, canteen) + .findFirst() + .orElseThrow(); + } + + public Stream searchAllFoodByNameByCanteen(String food, String canteen){ + return canteenList.stream() + .filter(x -> x.getName().contains(canteen)) + .findFirst() + .orElseThrow() + .getStoreList() + .stream() + .flatMap( x -> x.getFoodList().stream()) + .filter(x -> x.getName().contains(food)); + } + + /*** + * returns a stream of food whose calorie is below the provided amount + * @param calorie the maximum calorie of the food + * @return a stream + */ + public Stream searchAllFoodBelowCalorie( int calorie){ + return foodStream() + .filter( x -> x.getCalorie() < calorie); + } + + /*** * Provides a data stream of all the food in the data base * @return a food stream */ private Stream foodStream() { - return canteenList.stream() - .flatMap( x -> x.getStoreList().stream()) - .flatMap( x -> x.getFoodList().stream()); + return canteenList.stream() + .flatMap( x -> x.getStoreList().stream()) + .flatMap( x -> x.getFoodList().stream()); } - - } From 7ab189e51855dfe58fcaefa523e999681ca48510 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:31:09 +0800 Subject: [PATCH 032/271] fix checkstyle errors --- src/main/java/seedu/duke/food/Food.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 941e8e3944..c1e03882ce 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -7,7 +7,7 @@ public class Food { private final int protein; private final int fats; - public Food(String name, int calorie, int carbohydrate, int protein, int fats){ + public Food(String name, int calorie, int carbohydrate, int protein, int fats) { this.name = name; this.calorie = calorie; this.carbohydrate = carbohydrate; @@ -36,7 +36,7 @@ public int getProtein() { } @Override - public String toString(){ + public String toString() { return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate + " | fats : " + fats; } From eb954f86f6e0c99424e377e7253d9410cf9a44a1 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:36:08 +0800 Subject: [PATCH 033/271] implement filter by calorie ranges --- .../java/seedu/duke/database/DataBase.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 8dbdb772b5..b59b503f87 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -142,7 +142,7 @@ public Stream searchAllFoodContainingName(String food) { * @param store partial name of the store * @return Food object */ - public Food searchFoodByNameByStore(String food, String store){ + public Food searchFoodByNameByStore(String food, String store) { return searchAllFoodByStore(store) .filter( x -> x.getName().contains(food)) .findFirst() @@ -169,7 +169,7 @@ public Stream searchAllFoodByStore(String store) { * @param store partial name of the store * @return food stream */ - public Stream searchAllFoodOfAllStores(String store){ + public Stream searchAllFoodOfAllStores(String store) { return canteenList.stream() .flatMap( x -> x.getStoreList().stream()) .filter( x -> x.getName().contains(store)) @@ -183,13 +183,13 @@ public Stream searchAllFoodOfAllStores(String store){ * @param canteen partial name of the canteen * @return Food object */ - public Food searchFoodByNameByCanteen(String food, String canteen){ + public Food searchFoodByNameByCanteen(String food, String canteen) { return searchAllFoodByNameByCanteen(food, canteen) .findFirst() .orElseThrow(); } - public Stream searchAllFoodByNameByCanteen(String food, String canteen){ + public Stream searchAllFoodByNameByCanteen(String food, String canteen) { return canteenList.stream() .filter(x -> x.getName().contains(canteen)) .findFirst() @@ -205,11 +205,19 @@ public Stream searchAllFoodByNameByCanteen(String food, String canteen){ * @param calorie the maximum calorie of the food * @return a stream */ - public Stream searchAllFoodBelowCalorie( int calorie){ - return foodStream() - .filter( x -> x.getCalorie() < calorie); + public Stream searchAllFoodBelowCalorie( int calorie) { + return foodStream().filter( x -> x.getCalorie() < calorie); } + /*** + * returns all food within the calorie range + * @param minCalorie minimum calories + * @param maxCalorie maxinum calories + * @return + */ + public Stream searchAllFoodInCalorieRange( int minCalorie, int maxCalorie){ + return foodStream().filter( x -> x.getCalorie() <= maxCalorie && x.getCalorie() >= minCalorie ); + } /*** * Provides a data stream of all the food in the data base From 6f691a16378ced3f1164a34fadac91e982df5fdb Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:47:28 +0800 Subject: [PATCH 034/271] add docs --- src/main/java/seedu/duke/database/DataBase.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index b59b503f87..68077d710b 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -62,7 +62,7 @@ public void init() throws FileNotFoundException { * if the UP_SYMBOL is provided, the function ends and the final Canteen object is returned * @param name name of store * @param fileSegment the file reader with the next line being a food item or UP_SYMBOL - * @return + * @return Canteen objected with all it's stores loaded */ private Canteen fillCanteen(String name, Scanner fileSegment) { Canteen canteen = new Canteen(name); @@ -189,6 +189,12 @@ public Food searchFoodByNameByCanteen(String food, String canteen) { .orElseThrow(); } + /*** + * returns all food that contains the provided food name in the first canteen that matchs the canteen name + * @param food partial name of the food + * @param canteen partial name of the canteen + * @return Food Stream + */ public Stream searchAllFoodByNameByCanteen(String food, String canteen) { return canteenList.stream() .filter(x -> x.getName().contains(canteen)) From d780ab24b15ac6c00581a792789603e49a40c75a Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 9 Oct 2020 16:48:55 +0800 Subject: [PATCH 035/271] correct checkstyle --- src/test/java/seedu/duke/food/FoodTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java index 70c30be1ca..e2b03edb10 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -2,10 +2,9 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; class FoodTest { - public static void main(String[] args){ + public static void main(String[] args) { Food food = new Food("Kobe Beef", 480,50,40,30); System.out.println(food); } From 7de762ada6d5811b328e8826176c1fc21ca27612 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Sat, 10 Oct 2020 10:01:46 +0800 Subject: [PATCH 036/271] Calculator class --- .../java/seedu/calculator/calculator.java | 66 +++++++++++++++++++ src/main/java/seedu/duke/Duke.java | 3 +- 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/main/java/seedu/calculator/calculator.java diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/calculator.java new file mode 100644 index 0000000000..2d798147e9 --- /dev/null +++ b/src/main/java/seedu/calculator/calculator.java @@ -0,0 +1,66 @@ +package seedu.calculator; + +import java.util.ArrayList; +import seedu.foodList; + +/** + * Represents a calculator of food items in foodList. + */ +public class calculator { + private static Food total = new Food (total, 0, 0, 0, 0); + + /** + * Construct a calculator taking in a foodList. Add up calories, + * carbs, protein, and fats in each food item. + * + * @param foodList foodList containing food items to calculate + */ + public calculator(ArrayList foodList){ + try { + for(int i=0; i< foodList.size(); i++){ + total.calorie += foodList.getCalorie(i); + total.carbs += foodList.getCarbs(i); + total.protein += foodList.getProtein(i); + total.fats += foodList.getFats(i); + } + } catch (NullPointerException e) { + System.out.println("Ops, This foodList is null!"); + } + } + + /** + * Returns an int type variable containing the value of total calorie. + * + * @return the value of total calorie of food items in foodList. + */ + public int calculateCalorie(){ + return total.calorie; + } + + /** + * Returns an int type variable containing the value of total carbs. + * + * @return the value of total carbs of food items in foodList. + */ + public int calculateCarbs(){ + return total.carbs; + } + + /** + * Returns an int type variable containing the value of total protein. + * + * @return the value of total protein of food items in foodList. + */ + public int calculateProtein(){ + return total.protein; + } + + /** + * Returns an int type variable containing the value of total fats. + * + * @return the value of total fats of food items in foodList. + */ + public int calculateFats(){ + return total.fats; + } +} diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 5c74e68d59..74e5175952 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -6,8 +6,7 @@ public class Duke { /** * Main entry-point for the java.duke.Duke application. */ - public static void main(String[] args) { - String logo = " ____ _ \n" + public static void main(String[] args) { String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n" + "| |_| | |_| | < __/\n" From 610bd46a2c73f3057d8a88d0f735f229a0cc6cc6 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Sat, 10 Oct 2020 10:59:31 +0800 Subject: [PATCH 037/271] calculator version0.2 issues7 --- src/main/java/seedu/calculator/calculator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/calculator.java index 2d798147e9..3fa67153fd 100644 --- a/src/main/java/seedu/calculator/calculator.java +++ b/src/main/java/seedu/calculator/calculator.java @@ -13,7 +13,7 @@ public class calculator { * Construct a calculator taking in a foodList. Add up calories, * carbs, protein, and fats in each food item. * - * @param foodList foodList containing food items to calculate + * @param foodList foodList containing food items to calculate. */ public calculator(ArrayList foodList){ try { @@ -63,4 +63,4 @@ public int calculateProtein(){ public int calculateFats(){ return total.fats; } -} +} \ No newline at end of file From a9af8694e4f36f229a70874cbe091b831ae90daa Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Sat, 10 Oct 2020 11:22:22 +0800 Subject: [PATCH 038/271] calculator version0.3 issue7 --- src/main/java/seedu/calculator/calculator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/calculator.java index 3fa67153fd..017bd4cf77 100644 --- a/src/main/java/seedu/calculator/calculator.java +++ b/src/main/java/seedu/calculator/calculator.java @@ -7,7 +7,7 @@ * Represents a calculator of food items in foodList. */ public class calculator { - private static Food total = new Food (total, 0, 0, 0, 0); + private static Food total = new Food (total, 1, 0, 0, 0, 0); /** * Construct a calculator taking in a foodList. Add up calories, @@ -18,10 +18,10 @@ public class calculator { public calculator(ArrayList foodList){ try { for(int i=0; i< foodList.size(); i++){ - total.calorie += foodList.getCalorie(i); - total.carbs += foodList.getCarbs(i); - total.protein += foodList.getProtein(i); - total.fats += foodList.getFats(i); + total.calorie += foodList.getPortionSize(i)*foodList.getCalorie(i); + total.carbs += foodList.getPortionSize(i)*foodList.getCarbs(i); + total.protein += foodList.getPortionSize(i)*foodList.getProtein(i); + total.fats += foodList.getPortionSize(i)*foodList.getFats(i); } } catch (NullPointerException e) { System.out.println("Ops, This foodList is null!"); From 75b21beee10276ae22d7371dc94c1e521ebc611a Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 10 Oct 2020 15:05:43 +0800 Subject: [PATCH 039/271] Add Gender.java --- src/main/java/seedu/duke/person/Gender.java | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/seedu/duke/person/Gender.java diff --git a/src/main/java/seedu/duke/person/Gender.java b/src/main/java/seedu/duke/person/Gender.java new file mode 100644 index 0000000000..52b13a5a4b --- /dev/null +++ b/src/main/java/seedu/duke/person/Gender.java @@ -0,0 +1,31 @@ +package seedu.duke.person; + +/** + * Represents the gender of a person. + * A Gender has a description. + */ +public enum Gender { + FEMALE("female"), + MALE("male"); + + private final String description; + + /** + * Constructs a Gender given the description. + * + * @param description The description of the gender. + */ + Gender(String description) { + this.description = description; + } + + /** + * Returns the description of the gender. + * + * @return The description of the gender. + */ + public String getDescription() { + return description; + } + +} From 4c6fdcc3e3e0fa492351585df4d87f0cf45f5b15 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 10 Oct 2020 15:14:24 +0800 Subject: [PATCH 040/271] Person class: add name and gender attributes --- src/main/java/seedu/duke/person/Person.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java index d29131135f..5adce5e9a7 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/duke/person/Person.java @@ -2,7 +2,7 @@ /** * Represents a Person. - * A Person has an age, height, certain activity level, original and desired weight. + * A Person has a name, gender, age, height, certain activity level, original and desired weight. */ public class Person { @@ -14,11 +14,15 @@ public class Person { private int targetWeight; private int age; private ActivityLevel activityLevel; + private Gender gender; + private String name; /** - * Constructs a Person with the given age, height, original weight, target weight and - * activity level. + * Constructs a Person with the given name, gender, age, height, original weight, target + * weight and activity level. * + * @param name The name of the person. + * @param gender The gender of the person. * @param age The age of the person. * @param height The height of the person. * @param originalWeight The original weight of the person. @@ -26,7 +30,10 @@ public class Person { * @param activityLevel The activity level of the person or in other words, the amount of exercise the * person engages in. */ - public Person(int age, int height, int originalWeight, int targetWeight, ActivityLevel activityLevel) { + public Person(String name, Gender gender, int age, int height, int originalWeight, int targetWeight, + ActivityLevel activityLevel) { + this.name = name; + this.gender = gender; this.age = age; this.height = height; this.originalWeight = originalWeight; From dabb6c50f23238988d7394af6613ed4a2f2693a2 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 10 Oct 2020 15:17:15 +0800 Subject: [PATCH 041/271] Person class: add getter and setter for name --- src/main/java/seedu/duke/person/Person.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java index 5adce5e9a7..5b86b1b307 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/duke/person/Person.java @@ -41,6 +41,24 @@ public Person(String name, Gender gender, int age, int height, int originalWeigh this.activityLevel = activityLevel; } + /** + * Returns the name of the person. + * + * @return The name of the person. + */ + public String getName() { + return name; + } + + /** + * Sets the name of the person to the new name given. + * + * @param newName The new/revised name of the person. + */ + public void setName(String newName) { + name = newName; + } + /** * Returns the age of the person. * From f2f58c4739e42558c49b4e4b98e68112206ea329 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 10 Oct 2020 15:17:36 +0800 Subject: [PATCH 042/271] Person class: add getter and setter for gender --- src/main/java/seedu/duke/person/Person.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java index 5b86b1b307..2afc0bb38a 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/duke/person/Person.java @@ -59,6 +59,24 @@ public void setName(String newName) { name = newName; } + /** + * Returns the gender of the person. + * + * @return The gender of the person. + */ + public Gender getGender() { + return gender; + } + + /** + * Sets the gender of the person to the new gender given. + * + * @param newGender The new/revised gender of the person. + */ + public void setGender(Gender newGender) { + gender = newGender; + } + /** * Returns the age of the person. * From 79328f8c22651134623d12c38a80997201c6c1c9 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 10 Oct 2020 15:18:19 +0800 Subject: [PATCH 043/271] Person class: add toString method --- src/main/java/seedu/duke/person/Person.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java index 2afc0bb38a..1cd7b3b825 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/duke/person/Person.java @@ -166,4 +166,25 @@ public ActivityLevel getActivityLevel() { public void setActivityLevel(ActivityLevel newActivityLevel) { activityLevel = newActivityLevel; } + + /** + * Returns a string representation of all information related to the user. + * Information includes name, gender, age, height, original weight, target weight and activity level. + * + * @return A string representation of all information related to the user. + */ + @Override + public String toString() { + String userInformation = "Hi " + name + "! " + + "Here is your information:" + System.lineSeparator() + + System.lineSeparator() + + "Name: " + name + System.lineSeparator() + + "Gender: " + gender.getDescription() + System.lineSeparator() + + "Age: " + age + System.lineSeparator() + + "Height: " + height + "cm" + System.lineSeparator() + + "Original weight: " + originalWeight + "kg" + System.lineSeparator() + + "Target weight: " + targetWeight + "kg" + System.lineSeparator() + + "Activity level: " + activityLevel.getDescription(); + return userInformation; + } } From 4b18e5a769ade8bb6b14ebf0a4af6bb8c51e0157 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 10 Oct 2020 15:37:32 +0800 Subject: [PATCH 044/271] Add JUnit tests for setters, getters and toString Setters and getters include those for name and gender attributes of a Person. --- .../java/seedu/duke/person/PersonTest.java | 56 +++++++++++++++++-- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/test/java/seedu/duke/person/PersonTest.java b/src/test/java/seedu/duke/person/PersonTest.java index b599cdce68..a9f20dbe5f 100644 --- a/src/test/java/seedu/duke/person/PersonTest.java +++ b/src/test/java/seedu/duke/person/PersonTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; class PersonTest { @@ -11,7 +12,36 @@ class PersonTest { @BeforeEach public void setUp() { - person = new Person(21,165,65,55,ActivityLevel.LOW); + person = new Person("Jack", Gender.MALE,21,165,75,65, + ActivityLevel.LOW); + } + + @Test + void getName_person_returnsName() { + assertEquals("Jack", person.getName()); + } + + @Test + void setName_personWithNewName_returnNewName() { + person.setName("Jackie"); + assertEquals("Jackie", person.getName()); + } + + @Test + void gender_person_returnsGender() { + assertEquals(Gender.MALE, person.getGender()); + } + + @Test + void gender_personWithNewGender_returnsNewGender() { + person.setGender(Gender.FEMALE); + assertEquals(Gender.FEMALE, person.getGender()); + } + + @Test + void gender_personWithNullGender_returnsNullGender() { + person.setGender(null); + assertNull(person.getGender()); } @Test @@ -38,7 +68,7 @@ void setHeight_personWithNewHeight_returnsNewHeight() { @Test void getOriginalWeight_person_returnsOriginalWeight() { - assertEquals(65, person.getOriginalWeight()); + assertEquals(75, person.getOriginalWeight()); } @Test @@ -49,13 +79,13 @@ void setOriginalWeight_personWithNewOriginalWeight_returnsNewOriginalWeight() { @Test void getTargetWeight_person_returnsTargetWeight() { - assertEquals(55, person.getTargetWeight()); + assertEquals(65, person.getTargetWeight()); } @Test void setTargetWeight_personWithNewTargetWeight_returnsNewTargetWeight() { - person.setTargetWeight(50); - assertEquals(50, person.getTargetWeight()); + person.setTargetWeight(68); + assertEquals(68, person.getTargetWeight()); } @Test @@ -72,6 +102,20 @@ void setActivityLevel_personWithNewActivityLevel_returnsNewActivityLevel() { @Test void setActivityLevel_personWithNullActivityLevel_returnsNullActivityLevel() { person.setActivityLevel(null); - assertEquals(null, person.getActivityLevel()); + assertNull(person.getActivityLevel()); + } + + @Test + void toString_person_returnsStringRepresentationOfPersonInformation() { + assertEquals("Hi Jack! Here is your information:" + System.lineSeparator() + + System.lineSeparator() + + "Name: Jack" + System.lineSeparator() + + "Gender: male" + System.lineSeparator() + + "Age: 21" + System.lineSeparator() + + "Height: 165cm" + System.lineSeparator() + + "Original weight: 75kg" + System.lineSeparator() + + "Target weight: 65kg" + System.lineSeparator() + + "Activity level: You engage in some form of light exercise or have a job that requires " + + "some physical activity.", person.toString()); } } From f8ab2838ed92e72ac371f66c7ed3163ad4dbdd04 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sat, 10 Oct 2020 17:40:11 +0800 Subject: [PATCH 045/271] no message --- .../java/seedu/duke/database/DataBase.java | 31 +++++++++++++------ src/main/java/seedu/duke/food/Food.java | 1 + src/test/java/seedu/duke/food/FoodTest.java | 2 ++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 68077d710b..98c224e836 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Scanner; +import java.util.stream.Collectors; import java.util.stream.Stream; public class DataBase { @@ -136,8 +137,9 @@ public Stream searchAllFoodContainingName(String food) { } /*** - * search for the first food that contains the string provided in the first store which matchs the store - * string provided + * Search for the first food that contains the string provided in the first store which matchs the store + * string provided. + * * @param food partial name of the food * @param store partial name of the store * @return Food object @@ -150,7 +152,8 @@ public Food searchFoodByNameByStore(String food, String store) { } /*** - * This method returns a stream of all the food in the first store that contains the given string + * This method returns a stream of all the food in the first store that contains the given string. + * * @param store partial name of the store * @return food stream */ @@ -165,7 +168,8 @@ public Stream searchAllFoodByStore(String store) { } /*** - * this method returns a stream of all the food in all stores that contains the given string + * This method returns a stream of all the food in all stores that contains the given string. + * * @param store partial name of the store * @return food stream */ @@ -178,7 +182,8 @@ public Stream searchAllFoodOfAllStores(String store) { /*** - * this method returns the first food that matchs the + * This method returns the first food that matchs the. + * * @param food partial name of the food * @param canteen partial name of the canteen * @return Food object @@ -190,7 +195,8 @@ public Food searchFoodByNameByCanteen(String food, String canteen) { } /*** - * returns all food that contains the provided food name in the first canteen that matchs the canteen name + * Returns all food that contains the provided food name in the first canteen that matchs the canteen name. + * * @param food partial name of the food * @param canteen partial name of the canteen * @return Food Stream @@ -207,7 +213,8 @@ public Stream searchAllFoodByNameByCanteen(String food, String canteen) { } /*** - * returns a stream of food whose calorie is below the provided amount + * Returns a stream of food whose calorie is below the provided amount. + * * @param calorie the maximum calorie of the food * @return a stream */ @@ -216,7 +223,8 @@ public Stream searchAllFoodBelowCalorie( int calorie) { } /*** - * returns all food within the calorie range + * Returns all food within the calorie range. + * * @param minCalorie minimum calories * @param maxCalorie maxinum calories * @return @@ -226,7 +234,8 @@ public Stream searchAllFoodInCalorieRange( int minCalorie, int maxCalorie) } /*** - * Provides a data stream of all the food in the data base + * Provides a data stream of all the food in the data base. + * * @return a food stream */ private Stream foodStream() { @@ -234,4 +243,8 @@ private Stream foodStream() { .flatMap( x -> x.getStoreList().stream()) .flatMap( x -> x.getFoodList().stream()); } + + public List foodList() { + return foodStream().collect(Collectors.toList()); + } } diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 2572c66aff..48e2738fe6 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -1,5 +1,6 @@ package seedu.duke.food; + public class Food { private final String name; private final int calorie; diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java index 70c30be1ca..1168a32770 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.*; class FoodTest { + private Food testFood; + public static void main(String[] args){ Food food = new Food("Kobe Beef", 480,50,40,30); System.out.println(food); From 1b3467483fd555a416f68460799868a5d29b5954 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 10 Oct 2020 20:51:41 +0800 Subject: [PATCH 046/271] Update Person class toString and its JUnit test --- src/main/java/seedu/duke/person/Person.java | 17 +++++++---------- src/test/java/seedu/duke/person/PersonTest.java | 16 +++++++--------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java index 1cd7b3b825..91e0c32c2f 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/duke/person/Person.java @@ -175,16 +175,13 @@ public void setActivityLevel(ActivityLevel newActivityLevel) { */ @Override public String toString() { - String userInformation = "Hi " + name + "! " - + "Here is your information:" + System.lineSeparator() - + System.lineSeparator() - + "Name: " + name + System.lineSeparator() - + "Gender: " + gender.getDescription() + System.lineSeparator() - + "Age: " + age + System.lineSeparator() - + "Height: " + height + "cm" + System.lineSeparator() - + "Original weight: " + originalWeight + "kg" + System.lineSeparator() - + "Target weight: " + targetWeight + "kg" + System.lineSeparator() - + "Activity level: " + activityLevel.getDescription(); + String userInformation = " Name: " + name + System.lineSeparator() + + " Gender: " + gender.getDescription() + System.lineSeparator() + + " Age: " + age + System.lineSeparator() + + " Height: " + height + "cm" + System.lineSeparator() + + " Original weight: " + originalWeight + "kg" + System.lineSeparator() + + " Target weight: " + targetWeight + "kg" + System.lineSeparator() + + " Activity level: " + activityLevel.getDescription(); return userInformation; } } diff --git a/src/test/java/seedu/duke/person/PersonTest.java b/src/test/java/seedu/duke/person/PersonTest.java index a9f20dbe5f..415fd43134 100644 --- a/src/test/java/seedu/duke/person/PersonTest.java +++ b/src/test/java/seedu/duke/person/PersonTest.java @@ -107,15 +107,13 @@ void setActivityLevel_personWithNullActivityLevel_returnsNullActivityLevel() { @Test void toString_person_returnsStringRepresentationOfPersonInformation() { - assertEquals("Hi Jack! Here is your information:" + System.lineSeparator() - + System.lineSeparator() - + "Name: Jack" + System.lineSeparator() - + "Gender: male" + System.lineSeparator() - + "Age: 21" + System.lineSeparator() - + "Height: 165cm" + System.lineSeparator() - + "Original weight: 75kg" + System.lineSeparator() - + "Target weight: 65kg" + System.lineSeparator() - + "Activity level: You engage in some form of light exercise or have a job that requires " + assertEquals(" Name: Jack" + System.lineSeparator() + + " Gender: male" + System.lineSeparator() + + " Age: 21" + System.lineSeparator() + + " Height: 165cm" + System.lineSeparator() + + " Original weight: 75kg" + System.lineSeparator() + + " Target weight: 65kg" + System.lineSeparator() + + " Activity level: You engage in some form of light exercise or have a job that requires " + "some physical activity.", person.toString()); } } From 123d10daa5e1ec7a2d6a20745c622cc184c149b4 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Sat, 10 Oct 2020 22:11:23 +0800 Subject: [PATCH 047/271] calculator version0.4 Fixes #7 --- src/main/java/seedu/calculator/calculator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/calculator.java index 017bd4cf77..e6fd57fae0 100644 --- a/src/main/java/seedu/calculator/calculator.java +++ b/src/main/java/seedu/calculator/calculator.java @@ -18,10 +18,10 @@ public class calculator { public calculator(ArrayList foodList){ try { for(int i=0; i< foodList.size(); i++){ - total.calorie += foodList.getPortionSize(i)*foodList.getCalorie(i); - total.carbs += foodList.getPortionSize(i)*foodList.getCarbs(i); - total.protein += foodList.getPortionSize(i)*foodList.getProtein(i); - total.fats += foodList.getPortionSize(i)*foodList.getFats(i); + total.calorie += foodList.get(i).portionSize * foodList.get(i).calorie; + total.carbs += foodList.get(i).portionSize * foodList.get(i).carbs(i); + total.protein += foodList.get(i).portionSize * foodList.get(i).protein(i); + total.fats += foodList.get(i).portionSize * foodList.get(i).fats(i); } } catch (NullPointerException e) { System.out.println("Ops, This foodList is null!"); From 1468c3db55c67f3399df6597c0ea9b8464ef920f Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 11 Oct 2020 02:32:00 +0800 Subject: [PATCH 048/271] Add Ui.java --- src/main/java/seedu/duke/Ui.java | 295 +++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 src/main/java/seedu/duke/Ui.java diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java new file mode 100644 index 0000000000..55c0ee3ebb --- /dev/null +++ b/src/main/java/seedu/duke/Ui.java @@ -0,0 +1,295 @@ +package seedu.duke; + +/** + * Represents a text user interface. + * A Ui objects deals with user interaction by showing users the appropriate messages after a + * valid command is executed or when an error occurs. + */ +public class Ui { + + private static final String LINE_SEPARATOR = System.lineSeparator(); + + /** + * Constructs a Ui object. + */ + public Ui() { + } + + /** + * Prints the welcome message from DietBook when it is fist booted up. + */ + public void printWelcomeMessage() { + String logo = " _______ __ ______ ________ _______ ______ ______ __ __" + LINE_SEPARATOR + + "| __ \\| | ___|__ __| __ \\ / __ \\ / __ \\| | / /" + LINE_SEPARATOR + + "| | | | | |___ | | | |__| | | | | | | | |/ /" + LINE_SEPARATOR + + "| | | | | ___| | | | __ <| | | | | | | /" + LINE_SEPARATOR + + "| |__| | | |___ | | | |__| | |__| | | | | |\\ \\" + LINE_SEPARATOR + + "|_______/|__|______| |__| |_______/ \\______/ \\______/|__| \\__\" + LINE_SEPARATOR"; + print(logo + LINE_SEPARATOR + + "Hello! Welcome to DietBook!" + LINE_SEPARATOR + + "I am Diet, your guide to using DietBook. What is your name?" + LINE_SEPARATOR + + "Please input in the following format:" + LINE_SEPARATOR + + " name YOUR_NAME"); + } + + /** + * Prints a message asking the user to input their personal information related to dieting and health + * which includes gender, age, height, activity level, original weight and target weight. + * + * @param name The name of the user. + */ + public void printAskUserForPersonalInformationMessage(String name) { + print("Hi " + name + "!" + LINE_SEPARATOR + + "Before we get started, I would like to know about about you so that I can make more " + + "accurate calculations for you :)" + LINE_SEPARATOR + + "Therefore, could you please share with me the following:" + LINE_SEPARATOR + + "1. Your gender either F for female or M for male." + LINE_SEPARATOR + + "2. Your age which is a positive integer." + LINE_SEPARATOR + + "3. Your height in cm." + LINE_SEPARATOR + + "4. Your original weight in kg." + LINE_SEPARATOR + + "5. Your target weight in kg, or your original weight if your original weight is also " + + "your target weight." + LINE_SEPARATOR + + "6. Activity level from 1 to 5." + LINE_SEPARATOR + + " 1. " + ActvityLevel.NONE.getDescription() + LINE_SEPARATOR + + " 2. " + ActvityLevel.LOW.getDescription() + LINE_SEPARATOR + + " 3. " + ActvityLevel.MEDIUM.getDescription() + LINE_SEPARATOR + + " 4. " + ActvityLevel.HIGH.getDescription() + LINE_SEPARATOR + + " 5. " + ActvityLevel.EXTEREME.getDescription() + LINE_SEPARATOR + LINE_SEPARATOR + + "Please input your details in the following format:" + LINE_SEPARATOR + + " info g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL o/ORIGINAL_WEIGHT t/TARGET_WEIGHT" + + LINE_SEPARATOR + + " Example: info g/F a/21 h/165 l/2 o/65 t/55"); + //"4. Your current weight in kg." + //"5. Your target weight in kg, or your current weight if your current weight is also your target + // weight."; + //" info g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL c/CURRENT_WEIGHT t/TARGET_WEIGHT"); + //" Example: info g/F a/21 h/165 l/2 c/65 t/55"; + } + +// public void printWelcomeMessage() { +// String logo = " _______ __ ______ ________ _______ ______ ______ __ __" + LINE_SEPARATOR +// + "| __ \\| | ___|__ __| __ \\ / __ \\ / __ \\| | / /" + LINE_SEPARATOR +// + "| | | | | |___ | | | |__| | | | | | | | |/ /" + LINE_SEPARATOR +// + "| | | | | ___| | | | __ <| | | | | | | /" + LINE_SEPARATOR +// + "| |__| | | |___ | | | |__| | |__| | | | | |\\ \\" + LINE_SEPARATOR +// + "|_______/|__|______| |__| |_______/ \\______/ \\______/|__| \\__\" + LINE_SEPARATOR"; +// System.out.println(DIVIDER); +// System.out.println(logo); +// System.out.println("Hello! Welcome to DietBook!"); +// System.out.println("I am Diet, your guide to using DietBook."); +// System.out.println("Before we get started, I would like to know about about you so that I can make " +// + "more accurate calculations for you :)"); +// System.out.println("Therefore, could you please share with me the following:"); +// System.out.println("1. Your name."); +// System.out.println("2. Your gender either F for female or M for male".); +// System.out.println("3. Your age which is a positive integer."); +// System.out.println("4. Your height in cm."); +// System.out.println("5. Your current weight in kg."); +// System.out.println("5. Your original weight in kg."); +// System.out.println("6. Your target weight in kg, or your original weight if your " +// + "original weight is also your target weight."); +// System.out.println("6. Your target weight in kg, or your current weight if your " +// + "current weight is also your target weight."); +// System.out.println("7. Activity level from 1 to 5."); +// System.out.println(" 1. " + ActvityLevel.NONE.getDescription()); +// System.out.println(" 2. " + ActvityLevel.LOW.getDescription()); +// System.out.println(" 3. " + ActvityLevel.MEDIUM.getDescription()); +// System.out.println(" 4. " + ActvityLevel.HIGH.getDescription()); +// System.out.println(" 5. " + ActvityLevel.EXTEREME.getDescription()); +// System.out.println(LINE_SEPARATOR); +// System.out.println("Please input your details in the following format:"); +// System.out.println(" info n/NAME g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL o/ORIGINAL_WEIGHT " +// + "t/TARGET_WEIGHT"); +// System.out.println(" info n/name g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL c/CURRENT_WEIGHT " +// + "t/TARGET_WEIGHT"); +// System.out.println(" Example: info n/Suzy g/F a/21 h/165 l/2 o/65 t/55"); +// System.out.println(" Example: info n/Suzy g/F a/21 h/165 l/2 c/65 t/55"); +// System.out.println(DIVIDER); +// } + + /** + * Prints a message that notifies the user that DietBook has been initialised and shows a list of user + * commands that the user can input. + */ + public void printTutorialMessage() { + print("Thank you! DietBook has been initialised and you may start by entering any of the commands " + + "listed below." + LINE_SEPARATOR + LINE_SEPARATOR + + "To add you own food: add n/FOOD_NAME x/PORTION_SIZE k/CALORIE [c/CARB] [p/PROTEIN] " + + "[f/FAT]" + LINE_SEPARATOR + + "To view all food in DietBook: list" + LINE_SEPARATOR + + "To delete a food from DietBook: delete INDEX" + LINE_SEPARATOR + + "To delete all food items from the DietBook: clear" + LINE_SEPARATOR + + "To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE\n" + LINE_SEPARATOR + + "To view all food in the database: data" + LINE_SEPARATOR + + "To show user information: userinfo" + LINE_SEPARATOR + + "To calculate carbohydrate intake: calculate carbohydrate" + LINE_SEPARATOR + + "To calculate calorie intake: calculate calorie" + LINE_SEPARATOR + + "To calculate protein intake: calculate protein" + LINE_SEPARATOR + + "To calculate fat intake: calculate fat" + LINE_SEPARATOR + + "To calculate all nutritional intake: calculate all" + LINE_SEPARATOR + + "To exit DietBook: exit"); + } + + /** + * Prints a message to show that the food specified has been added to the food list. + * + * @param newFood The new food item that was added to the food list. + */ + public void printNewFood(Food newFood) { + print("Got it! I've added this food item:" + LINE_SEPARATOR + + " " + newFood); + } + + /** + * Prints all the food items in the food list in the order that they were added or a message stating + * that the food list is empty if there are no food items. + * + * @param foodList The food list containing all the food items. + */ + public void printFoodList(FoodList foodList) { + if (foodList.getFoods().isEmpty()) { + print("DietBook is currently empty."); + } else { + String allFood = ""; + int foodItemNumber = 1; + for (Food food : foodList.getFoods()) { + allFood += LINE_SEPARATOR + " " + foodItemNumber + "." + food; + foodItemNumber++; + } + print("Here are the food items in DietBook:" + allFood); + } + } + + /** + * Prints all the food in the database sorted by the canteen and then the store it is found. + * + * @param foodDatabase The list containing all the food items stored in the database. + */ + public void printDatabase(List foodDatabase) { + String allFood = ""; + int foodItemNumber = 1; + for (Food food: foodDatabase) { + allFood += LINE_SEPARATOR + " " + foodItemNumber + "." + food; + foodItemNumber++; + } + print("Here are the food items in the database:" + allFood); + } + + /** + * Prints all the information related to the user. + * + * @param person The user. + */ + public void printPersonInformation(Person person) { + print("Here is your information:" + LINE_SEPARATOR + + person); + } + + /** + * Prints the total amount of carbohydrates consumed by the user. + * + * @param carbohydrateIntake The total amount of carbohydrates of all the food in the food list. + */ + public void printCarbohydrateIntake(int carbohydrateIntake) { + print("Total carbohydrate intake: " + carbohydrateIntake + "g"); + } + + /** + * Prints the total amount of calories consumed by the user. + * + * @param calorieIntake The total amount of calories of all the food in the food list. + */ + public void printCalorieIntake(int calorieIntake) { + print("Total calorie intake: " + calorieIntake + "kcal"); + } + + /** + * Prints the total amount of proteins consumed by the user. + * + * @param proteinIntake The total amount of proteins of all the food in the food list. + */ + public void printProteinIntake(int proteinIntake) { + print("Total protein intake: " + proteinIntake + "g"); + } + + /** + * Prints the total amount of fats consumed by the user. + * + * @param fatIntake The total amount of fats of all the food in the food list. + */ + public void printFatIntake(int fatIntake) { + print("Total fat intake: " + fatIntake + "g"); + } + + /** + * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user. + * + * @param calorieIntake The total amount of calories of all the food in the food list. + * @param carbohydrateIntake The total amount of carbohydrates of all the food in the food list. + * @param proteinIntake The total amount of proteins of all the food in the food list. + * @param fatIntake The total amount of fats of all the food in the food list. + */ + public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, int proteinIntake, + int fatIntake) { + print("Total calorie intake: " + calorieIntake + "kcal" + LINE_SEPARATOR + + "Total carbohydrate intake: " + carbohydrateIntake + "g" + LINE_SEPARATOR + + "Total protein intake: " + proteinIntake + "g" + LINE_SEPARATOR + + "Total fat intake: " + fatIntake + "g"); + } + +// public void printNutrientIntake(String nutritionalIntake) { +// print(nutritionalIntake); +// } + + /** + * Prints a message to show that the food specified has been deleted from the food list. + * + * @param deletedFood The food that was deleted from the food list. + */ + public void printDeletedFood(Food deletedFood) { + print("Noted. I've removed this food item:" + LINE_SEPARATOR + + " " + deletedFood); + } + + /** + * Prints a message to show that the food list has been successfully cleared and is now empty. + */ + public void printClearFoodListMessage() { + print("All previous data has been deleted..." + LINE_SEPARATOR + + "DietBook is now empty."); + } + + /** + * Prints an exit message when DietBook is closed. + * + * @param name The name of the user. + */ + public void printExitMessage(String name) { + print("Bye " + name + "! Hope to see you again soon!"); + } + + /** + * Prints an error message given what or where the error is. + * + * @param errorMessage Message detailing what or where the error is. + */ + public void printErrorMessage(String errorMessage) { + print(":( Oh no..." + errorMessage); + } + + /** + * Prints the given message to the user. + * + * @param message The message to show the user. + */ + public void print(String message) { + String divider = + "__________________________________________________________________________________________" + + "__________"; + + System.out.println(divider + LINE_SEPARATOR + + message + LINE_SEPARATOR + + divider); + + } +} From 4ce010a6256df4e161e47787faa48cbf831d36af Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 11 Oct 2020 02:33:32 +0800 Subject: [PATCH 049/271] Correct spelling errors --- src/main/java/seedu/duke/Ui.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 55c0ee3ebb..5bae580485 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -50,11 +50,11 @@ public void printAskUserForPersonalInformationMessage(String name) { + "5. Your target weight in kg, or your original weight if your original weight is also " + "your target weight." + LINE_SEPARATOR + "6. Activity level from 1 to 5." + LINE_SEPARATOR - + " 1. " + ActvityLevel.NONE.getDescription() + LINE_SEPARATOR - + " 2. " + ActvityLevel.LOW.getDescription() + LINE_SEPARATOR - + " 3. " + ActvityLevel.MEDIUM.getDescription() + LINE_SEPARATOR - + " 4. " + ActvityLevel.HIGH.getDescription() + LINE_SEPARATOR - + " 5. " + ActvityLevel.EXTEREME.getDescription() + LINE_SEPARATOR + LINE_SEPARATOR + + " 1. " + ActivityLevel.NONE.getDescription() + LINE_SEPARATOR + + " 2. " + ActivityLevel.LOW.getDescription() + LINE_SEPARATOR + + " 3. " + ActivityLevel.MEDIUM.getDescription() + LINE_SEPARATOR + + " 4. " + ActivityLevel.HIGH.getDescription() + LINE_SEPARATOR + + " 5. " + ActivityLevel.EXTREME.getDescription() + LINE_SEPARATOR + LINE_SEPARATOR + "Please input your details in the following format:" + LINE_SEPARATOR + " info g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL o/ORIGINAL_WEIGHT t/TARGET_WEIGHT" + LINE_SEPARATOR From 99176291093d919f13af865e1bf9646e724686f8 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Sun, 11 Oct 2020 11:22:55 +0800 Subject: [PATCH 050/271] add FoodList Wrapper class around the food object and its necessary details. Uses FoodEntry which is an internal data class to support storage of more details beyond food. Has FoodListManager to streamline and abstract FoodList, while allowing for portential FP implementation later on. --- src/main/java/seedu/duke/list/FoodEntry.java | 36 +++++++++ src/main/java/seedu/duke/list/FoodList.java | 78 +++++++++++++++++++ .../java/seedu/duke/list/FoodListManager.java | 42 ++++++++++ .../duke/list/FoodNotFoundException.java | 4 + src/test/java/seedu/duke/FoodListTest.java | 19 +++++ 5 files changed, 179 insertions(+) create mode 100644 src/main/java/seedu/duke/list/FoodEntry.java create mode 100644 src/main/java/seedu/duke/list/FoodList.java create mode 100644 src/main/java/seedu/duke/list/FoodListManager.java create mode 100644 src/main/java/seedu/duke/list/FoodNotFoundException.java create mode 100644 src/test/java/seedu/duke/FoodListTest.java diff --git a/src/main/java/seedu/duke/list/FoodEntry.java b/src/main/java/seedu/duke/list/FoodEntry.java new file mode 100644 index 0000000000..94d31091d9 --- /dev/null +++ b/src/main/java/seedu/duke/list/FoodEntry.java @@ -0,0 +1,36 @@ +package seedu.duke.list; +import seedu.duke.food.Food; + + +/** + * Data class to story both serving sizes and a food object as a single object + */ +public class FoodEntry { + private int portionSize; + private Food food; + + public FoodEntry(int portionSize, Food food) { + this.portionSize = portionSize; + this.food = food; + } + + public FoodEntry(int portionSize, String name, int calorie, + int carbohydrate, int protein, int fat) { + this.portionSize = portionSize; + this.food = new Food (name, calorie, carbohydrate, protein, fat); + } + + public Food getFood() { + return food; + } + + public int portionSize() { + return portionSize; + } + + @Override + public String toString() { + return String.format("%s -- (%s)", food.toString(), portionSize); + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java new file mode 100644 index 0000000000..d4268dc984 --- /dev/null +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -0,0 +1,78 @@ +package seedu.duke.list; +import java.util.ArrayList; +import seedu.duke.food.Food; + + +/** + * Wrapper class for the implementation of foodlist as an arraylist of foodEntry objects + * Foodlist does not return its ArrayList nor foodEntry objects. + * This is a stateful object. + */ +public class FoodList { + private ArrayList foodEntries; + + public FoodList() { + this.foodEntries = new ArrayList<>(); + } + + protected FoodList(ArrayList entries) { + this.foodEntries = entries; + } + + /** + * Adds food of portion size directly into the foodlist as an entry. + * When date functionality is added, this method will need to be overhauled. + * The adding feature will be largely pushed to FoodListManager (to figure out dates) + * @param portionSize + * @param food + * @return + */ + public String addFood(int portionSize, Food food) { + FoodEntry toAdd = new FoodEntry(portionSize, food); + foodEntries.add(toAdd); + return toAdd.toString(); + } + + public String addFood (int portionSize, String name, int calorie, + int carbohydrate, int protein, int fat) { + FoodEntry toAdd = new FoodEntry(portionSize, name, calorie, carbohydrate, protein, fat); + foodEntries.add(toAdd); + return toAdd.toString(); + } + + /** + * Food database search functionality support. + * Currently just throws a not found exception when called in this manner. + * @param portionSize + * @param name + * @return + * @throws FoodNotFoundException + */ + public String addFood (int portionSize, String name) throws FoodNotFoundException{ + throw new FoodNotFoundException(); + } + + + public String delete (int index) throws IndexOutOfBoundsException { + try{ + return FoodListManager.deleteEntry(foodEntries, index).toString(); + } catch (IndexOutOfBoundsException e) { + throw e; + } + } + + public boolean clear() { + this.foodEntries = new ArrayList<>(); + return true; + } + + public ArrayList getFoods() { + return FoodListManager.listToFoods(foodEntries); + } + + @Override + public String toString() { + return FoodListManager.listToString(foodEntries); + } + +} diff --git a/src/main/java/seedu/duke/list/FoodListManager.java b/src/main/java/seedu/duke/list/FoodListManager.java new file mode 100644 index 0000000000..a6545591d1 --- /dev/null +++ b/src/main/java/seedu/duke/list/FoodListManager.java @@ -0,0 +1,42 @@ +package seedu.duke.list; + +import seedu.duke.food.Food; +import java.util.ArrayList; + +/** + * Class with static methods to execute "complex commands" on FoodList. + * This class handles methods that extend beyond the simple function of an arraylist + * Class contains static methods with logic beyond adding, removing, and instantiating new lists + * This class may be used to support functional programming by merging these function into functors + */ +public class FoodListManager { + + protected static String listToString(ArrayList list) { + String listString = ""; + + for (int i = 1; i <= list.size(); i++) { + FoodEntry task = list.get(i - 1); + listString += i + ". " + + task.toString() + "\n"; + } + return listString; + } + + protected static ArrayList listToFoods(ArrayList list) { + ArrayList foods = new ArrayList<>(); + list.forEach( x -> { + foods.add(x.getFood()); + }); + return foods; + } + + protected static Food deleteEntry(ArrayList list, int index) throws IndexOutOfBoundsException { + int indexToDelete = index - 1; + try { + return list.remove(indexToDelete).getFood(); + } + catch (IndexOutOfBoundsException e) { + throw e; + } + } +} diff --git a/src/main/java/seedu/duke/list/FoodNotFoundException.java b/src/main/java/seedu/duke/list/FoodNotFoundException.java new file mode 100644 index 0000000000..ca99d41a3e --- /dev/null +++ b/src/main/java/seedu/duke/list/FoodNotFoundException.java @@ -0,0 +1,4 @@ +package seedu.duke.list; + +public class FoodNotFoundException extends Exception{ +} diff --git a/src/test/java/seedu/duke/FoodListTest.java b/src/test/java/seedu/duke/FoodListTest.java new file mode 100644 index 0000000000..96b31d9647 --- /dev/null +++ b/src/test/java/seedu/duke/FoodListTest.java @@ -0,0 +1,19 @@ +package seedu.duke; + +import seedu.duke.list.FoodList; +import seedu.duke.food.Food; +import org.junit.jupiter.api.Test; + + +class FoodListTest { + public static void main(String[] args) { + Food food = new Food("Kobe Beef", 480,50,40,30); + FoodList foodList = new FoodList(); + + System.out.println(foodList.addFood(3, food)); + System.out.println(foodList.addFood(2, "Sashimi", 100, 0, 30, 10)); + System.out.println(foodList); + System.out.println(foodList.delete(1)); + System.out.println(foodList); + } +} \ No newline at end of file From 09bcfee2245f519dda2e5b22a204cebdf5901e3b Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sun, 11 Oct 2020 11:35:33 +0800 Subject: [PATCH 051/271] add JUNIT tests --- src/test/java/seedu/duke/food/FoodTest.java | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java index e2b03edb10..7a45d44cd0 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -1,11 +1,27 @@ package seedu.duke.food; +import seedu.duke.food.Food; + +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.fail; + class FoodTest { - public static void main(String[] args) { - Food food = new Food("Kobe Beef", 480,50,40,30); - System.out.println(food); + private Food testFood; + + @BeforeEach + public void setUp(){ + testFood = new Food("Kobe Beef", 480,50,40,30); + } + + @Test + public void footTest(){ + assertEquals(testFood.getCalorie(), 480); + assertEquals(testFood.getCarbohydrate(), 50); + assertEquals(testFood.getProtein(), 40); + assertEquals(testFood.getFats(),30); } } \ No newline at end of file From 4ad0aefa0ed40ebac1c95fb546e0321845556fa8 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Sun, 11 Oct 2020 12:16:55 +0800 Subject: [PATCH 052/271] style changes tweaks to adhere to checkstyle format specified by project --- src/main/java/seedu/duke/list/FoodEntry.java | 5 ++-- src/main/java/seedu/duke/list/FoodList.java | 23 ++++++++++--------- .../java/seedu/duke/list/FoodListManager.java | 5 ++-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/java/seedu/duke/list/FoodEntry.java b/src/main/java/seedu/duke/list/FoodEntry.java index 94d31091d9..8016d6bf32 100644 --- a/src/main/java/seedu/duke/list/FoodEntry.java +++ b/src/main/java/seedu/duke/list/FoodEntry.java @@ -1,9 +1,10 @@ package seedu.duke.list; + import seedu.duke.food.Food; /** - * Data class to story both serving sizes and a food object as a single object + * Data class to story both serving sizes and a food object as a single object. */ public class FoodEntry { private int portionSize; @@ -17,7 +18,7 @@ public FoodEntry(int portionSize, Food food) { public FoodEntry(int portionSize, String name, int calorie, int carbohydrate, int protein, int fat) { this.portionSize = portionSize; - this.food = new Food (name, calorie, carbohydrate, protein, fat); + this.food = new Food(name, calorie, carbohydrate, protein, fat); } public Food getFood() { diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java index d4268dc984..8e4c67d36e 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -1,10 +1,11 @@ package seedu.duke.list; + import java.util.ArrayList; import seedu.duke.food.Food; /** - * Wrapper class for the implementation of foodlist as an arraylist of foodEntry objects + * Wrapper class for the implementation of foodlist as an arraylist of foodEntry objects. * Foodlist does not return its ArrayList nor foodEntry objects. * This is a stateful object. */ @@ -23,9 +24,9 @@ protected FoodList(ArrayList entries) { * Adds food of portion size directly into the foodlist as an entry. * When date functionality is added, this method will need to be overhauled. * The adding feature will be largely pushed to FoodListManager (to figure out dates) - * @param portionSize - * @param food - * @return + * @param portionSize integer to designate number of servings + * @param food food object to be added + * @return string representation of the food object added */ public String addFood(int portionSize, Food food) { FoodEntry toAdd = new FoodEntry(portionSize, food); @@ -33,7 +34,7 @@ public String addFood(int portionSize, Food food) { return toAdd.toString(); } - public String addFood (int portionSize, String name, int calorie, + public String addFood(int portionSize, String name, int calorie, int carbohydrate, int protein, int fat) { FoodEntry toAdd = new FoodEntry(portionSize, name, calorie, carbohydrate, protein, fat); foodEntries.add(toAdd); @@ -43,17 +44,17 @@ public String addFood (int portionSize, String name, int calorie, /** * Food database search functionality support. * Currently just throws a not found exception when called in this manner. - * @param portionSize - * @param name - * @return - * @throws FoodNotFoundException + * @param portionSize integer to designate number of servings + * @param name food object to be added + * @return string representation of the food object added + * @throws FoodNotFoundException custom exception to indicate search for food in database failed. */ - public String addFood (int portionSize, String name) throws FoodNotFoundException{ + public String addFood(int portionSize, String name) throws FoodNotFoundException { throw new FoodNotFoundException(); } - public String delete (int index) throws IndexOutOfBoundsException { + public String delete(int index) throws IndexOutOfBoundsException { try{ return FoodListManager.deleteEntry(foodEntries, index).toString(); } catch (IndexOutOfBoundsException e) { diff --git a/src/main/java/seedu/duke/list/FoodListManager.java b/src/main/java/seedu/duke/list/FoodListManager.java index a6545591d1..cff588f01b 100644 --- a/src/main/java/seedu/duke/list/FoodListManager.java +++ b/src/main/java/seedu/duke/list/FoodListManager.java @@ -24,7 +24,7 @@ protected static String listToString(ArrayList list) { protected static ArrayList listToFoods(ArrayList list) { ArrayList foods = new ArrayList<>(); - list.forEach( x -> { + list.forEach(x -> { foods.add(x.getFood()); }); return foods; @@ -34,8 +34,7 @@ protected static Food deleteEntry(ArrayList list, int index) throws I int indexToDelete = index - 1; try { return list.remove(indexToDelete).getFood(); - } - catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException e) { throw e; } } From 71b58f075d93d0cc082b4ec597179a159747b57e Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Sun, 11 Oct 2020 12:26:33 +0800 Subject: [PATCH 053/271] style changes --- src/main/java/seedu/duke/list/FoodList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java index 8e4c67d36e..4d862540a1 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -55,7 +55,7 @@ public String addFood(int portionSize, String name) throws FoodNotFoundException public String delete(int index) throws IndexOutOfBoundsException { - try{ + try { return FoodListManager.deleteEntry(foodEntries, index).toString(); } catch (IndexOutOfBoundsException e) { throw e; From c436e5207223903f737e04c199e9d40b65d9c8ff Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sun, 11 Oct 2020 13:14:07 +0800 Subject: [PATCH 054/271] fixed style to pass gradle checkstyle tests add database tests add getFoodList function to return a list of All Food in the data base --- .../java/seedu/duke/database/Canteen.java | 9 +- .../java/seedu/duke/database/DataBase.java | 113 ++++++++++-------- src/main/java/seedu/duke/database/Store.java | 13 +- src/main/java/seedu/duke/food/Food.java | 2 +- .../seedu/duke/database/DataBaseTest.java | 75 ++++++++++++ 5 files changed, 149 insertions(+), 63 deletions(-) diff --git a/src/main/java/seedu/duke/database/Canteen.java b/src/main/java/seedu/duke/database/Canteen.java index fd3a92deff..1243b0d9be 100644 --- a/src/main/java/seedu/duke/database/Canteen.java +++ b/src/main/java/seedu/duke/database/Canteen.java @@ -7,20 +7,21 @@ public class Canteen { private final String name; private final ArrayList storeList; - public Canteen(String name){ + public Canteen(String name) { this.name = name; this.storeList = new ArrayList<>(); } - /*** - * name of the canteen is for filtering purposes + /** + * Name of the canteen is for filtering purposes. + * * @return name of canteen */ public String getName() { return name; } - public void addStore(Store store){ + public void addStore(Store store) { storeList.add(store); } diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 98c224e836..74672a54ef 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -20,8 +20,8 @@ public class DataBase { private static final String DATA_FILE_SEPERATOR = "\\|"; private static final String rootDirectory = System.getProperty("user.dir"); - private static final String dataFileFolder = "src" + File.separator + "main" + File.separator + - "java" + File.separator + "seedu" + File.separator + "duke" + File.separator + "database"; + private static final String dataFileFolder = "src" + File.separator + "main" + File.separator + + "java" + File.separator + "seedu" + File.separator + "duke" + File.separator + "database"; private final List canteenList; @@ -29,8 +29,8 @@ public DataBase() { this.canteenList = new ArrayList<>(); } - /*** - * Reads a file from the data base and puts it into the DataBase object + /** + * Reads a file from the data base and puts it into the DataBase object. */ public void init() throws FileNotFoundException { String fileFolder = rootDirectory + File.separator + dataFileFolder; @@ -45,7 +45,7 @@ public void init() throws FileNotFoundException { start = true; continue; } - if (!(start)){ + if (!(start)) { continue; } if (fileLine.equals(STOP_SYMBOL)) { @@ -55,12 +55,13 @@ public void init() throws FileNotFoundException { } } - /*** + /** * This function is called right after the canteen name is provided * The very next line that the file reads is the store name * It will turn call fillStore with that name inserted, when the function fillStore * finishes executing, fileRead.nextLine() can either provide a new store name or UP_SYMBOL - * if the UP_SYMBOL is provided, the function ends and the final Canteen object is returned + * if the UP_SYMBOL is provided, the function ends and the final Canteen object is returned. + * * @param name name of store * @param fileSegment the file reader with the next line being a food item or UP_SYMBOL * @return Canteen objected with all it's stores loaded @@ -75,10 +76,11 @@ private Canteen fillCanteen(String name, Scanner fileSegment) { return canteen; } - /*** - * This function is called right after the store name is provided - * The very next line in the file should be the first food to be added - * The function stops when it hits the line of the file that says UP_SYMBOL + /** + * This function is called right after the store name is provided. + * The very next line in the file should be the first food to be added. + * The function stops when it hits the line of the file that says UP_SYMBOL. + * * @param name name of the store * @param fileSegment the Scanner object used for the init() function * @return the completed store with all the food loaded @@ -89,8 +91,8 @@ private Store fillStore(String name, Scanner fileSegment) { String fileLine = fileSegment.nextLine(); String[] fileData = fileLine.split(DATA_FILE_SEPERATOR); while (!(fileLine.equals(UP_SYMBOL))) { - food = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]) - ,Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); + food = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]), + Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); store.addFood(food); fileLine = fileSegment.nextLine(); fileData = fileLine.split(DATA_FILE_SEPERATOR); @@ -98,16 +100,16 @@ private Store fillStore(String name, Scanner fileSegment) { return store; } - /*** - * Debugging function prints out all contents + /** + * Debugging function prints out all contents. */ public void printAllData() { System.out.println("Printing out all data"); - for (Canteen canteen : canteenList){ + for (Canteen canteen : canteenList) { System.out.println("Canteeh : " + canteen.getName()); - for (Store store : canteen.getStoreList()){ + for (Store store : canteen.getStoreList()) { System.out.println("Store : " + store.getName()); - for (Food food : store.getFoodList()){ + for (Food food : store.getFoodList()) { System.out.println(food); } } @@ -117,76 +119,83 @@ public void printAllData() { // -------- Search functions -------- - /*** - * this method searchs the whole data base and returns the first food item whose name contains the provided string + /** + * This method searchs the whole data base and returns the first food item whose name contains the provided string. + * ( CASE SENSITIVE ! ) + * * @param food part of the name of the food * @return Food * @throws NoSuchElementException if no food contains the name provided */ public Food searchFoodByName(String food) { - return foodStream().filter( x -> x.getName().contains(food)).findFirst().orElseThrow(); + return foodStream().filter(x -> x.getName().contains(food)).findFirst().orElseThrow(); } - /*** - * this method searchs the whole data base and returns all of the food whose name contains the provided string + /** + * This method searchs the whole data base and returns all of the food whose name contains the provided string. * @param food part of the name of the food e.g. chicken * @return data stream of all food items */ public Stream searchAllFoodContainingName(String food) { - return foodStream().filter( x -> x.getName().contains(food)); + return foodStream().filter(x -> x.getName().contains(food)); } - /*** + /** * Search for the first food that contains the string provided in the first store which matchs the store * string provided. * * @param food partial name of the food * @param store partial name of the store * @return Food object + * @throws NoSuchElementException if no food contains the name provided */ public Food searchFoodByNameByStore(String food, String store) { return searchAllFoodByStore(store) - .filter( x -> x.getName().contains(food)) + .filter(x -> x.getName().contains(food)) .findFirst() .orElseThrow(); } - /*** - * This method returns a stream of all the food in the first store that contains the given string. + /** + * Returns a stream of all the food in the first store that contains the given string. * * @param store partial name of the store * @return food stream + * @throws NoSuchElementException if no there is no store */ public Stream searchAllFoodByStore(String store) { return canteenList.stream() - .flatMap( x -> x.getStoreList().stream()) - .filter( x -> x.getName().contains(store)) + .flatMap(x -> x.getStoreList().stream()) + .filter(x -> x.getName().contains(store)) .findFirst() .orElseThrow() .getFoodList() .stream(); } - /*** - * This method returns a stream of all the food in all stores that contains the given string. + /** + * Returns a stream of all the food in all stores that contains the given string. * * @param store partial name of the store * @return food stream */ public Stream searchAllFoodOfAllStores(String store) { return canteenList.stream() - .flatMap( x -> x.getStoreList().stream()) - .filter( x -> x.getName().contains(store)) - .flatMap( x -> x.getFoodList().stream()); + .flatMap(x -> x.getStoreList().stream()) + .filter(x -> x.getName().contains(store)) + .flatMap(x -> x.getFoodList().stream()); } - /*** - * This method returns the first food that matchs the. + /** + * Returns the first food that contains the food String provided that is in the first canteen that contains the + * canteen String provided. * * @param food partial name of the food * @param canteen partial name of the canteen * @return Food object + * + * @throws NoSuchElementException if no food contains the name provided */ public Food searchFoodByNameByCanteen(String food, String canteen) { return searchAllFoodByNameByCanteen(food, canteen) @@ -194,7 +203,7 @@ public Food searchFoodByNameByCanteen(String food, String canteen) { .orElseThrow(); } - /*** + /** * Returns all food that contains the provided food name in the first canteen that matchs the canteen name. * * @param food partial name of the food @@ -208,43 +217,43 @@ public Stream searchAllFoodByNameByCanteen(String food, String canteen) { .orElseThrow() .getStoreList() .stream() - .flatMap( x -> x.getFoodList().stream()) + .flatMap(x -> x.getFoodList().stream()) .filter(x -> x.getName().contains(food)); } - /*** + /** * Returns a stream of food whose calorie is below the provided amount. * * @param calorie the maximum calorie of the food - * @return a stream + * @return food stream */ - public Stream searchAllFoodBelowCalorie( int calorie) { - return foodStream().filter( x -> x.getCalorie() < calorie); + public Stream searchAllFoodBelowCalorie(int calorie) { + return foodStream().filter(x -> x.getCalorie() < calorie); } - /*** + /** * Returns all food within the calorie range. * * @param minCalorie minimum calories * @param maxCalorie maxinum calories - * @return + * @return food stream */ - public Stream searchAllFoodInCalorieRange( int minCalorie, int maxCalorie){ - return foodStream().filter( x -> x.getCalorie() <= maxCalorie && x.getCalorie() >= minCalorie ); + public Stream searchAllFoodInCalorieRange(int minCalorie, int maxCalorie) { + return foodStream().filter(x -> x.getCalorie() <= maxCalorie && x.getCalorie() >= minCalorie); } - /*** + /** * Provides a data stream of all the food in the data base. * * @return a food stream */ - private Stream foodStream() { + public Stream foodStream() { return canteenList.stream() - .flatMap( x -> x.getStoreList().stream()) - .flatMap( x -> x.getFoodList().stream()); + .flatMap(x -> x.getStoreList().stream()) + .flatMap(x -> x.getFoodList().stream()); } - public List foodList() { + public List getFoodList() { return foodStream().collect(Collectors.toList()); } } diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/duke/database/Store.java index 5d1727d67b..af311ae856 100644 --- a/src/main/java/seedu/duke/database/Store.java +++ b/src/main/java/seedu/duke/database/Store.java @@ -11,14 +11,15 @@ public class Store { private final ArrayList foodList; - public Store(String name){ + public Store(String name) { this.name = name; this.foodList = new ArrayList<>(); } - /*** - * the name of the store will be used for filtering purposes - * @return + /** + * The name of the store will be used for filtering purposes. + * + * @return store name */ public String getName() { @@ -26,9 +27,9 @@ public String getName() { } /** - * This function should only be called when we initialize the data base from the text file + * This function should only be called when we initialize the data base from the text file. */ - public void addFood(Food food){ + public void addFood(Food food) { foodList.add(food); } diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 48e2738fe6..c43d8f0384 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -8,7 +8,7 @@ public class Food { private final int protein; private final int fats; - public Food(String name, int calorie, int carbohydrate, int protein, int fats){ + public Food(String name, int calorie, int carbohydrate, int protein, int fats) { this.name = name; this.calorie = calorie; this.carbohydrate = carbohydrate; diff --git a/src/test/java/seedu/duke/database/DataBaseTest.java b/src/test/java/seedu/duke/database/DataBaseTest.java index 4551e8571a..a060a3ea2c 100644 --- a/src/test/java/seedu/duke/database/DataBaseTest.java +++ b/src/test/java/seedu/duke/database/DataBaseTest.java @@ -1,6 +1,7 @@ package seedu.duke.database; import java.io.FileNotFoundException; +import java.util.NoSuchElementException; import static org.junit.jupiter.api.Assertions.*; @@ -12,6 +13,80 @@ public static void main(String[] args){ } catch (FileNotFoundException e) { e.printStackTrace(); } + // ----- Print everything in the data base ----- database.printAllData(); + + // ---- Using stream version to print ----- + System.out.println("------------ printing using food stream ------------"); + database.foodStream().forEach(System.out::println); + + // ---- Printing out as list ----- + System.out.println("---------- printing food using list --------------"); + database.getFoodList().forEach(System.out::println); + + // ---- search food by name test ----- + try { + System.out.println("------- testing the searchFoodByName function -------"); + System.out.println("Input: Prawn ## OutPut: " + database.searchFoodByName("Prawn")); + System.out.println("Input: Mee ## OutPut: " + database.searchFoodByName("Mee")); + System.out.println("Input: lobster ## OutPut: " + database.searchFoodByName("lobster")); + + System.out.println("Input: Prawn ## OutPut: " + database.searchFoodByName("koala bears")); + } + catch (NoSuchElementException e){ + System.out.println("No such food found! " + e); + } + + // ---- search food by store name test ---- + System.out.println("------- testing the search food by store and by name function --------"); + try { + System.out.println("Input: Fried , Halal Mini Wok ## OutPut: " + database.searchFoodByNameByStore("Fried", "Halal Mini Wok")); + System.out.println("Input: Chicken , Halal Mini Wok ## OutPut: " + database.searchFoodByNameByStore("Chicken", "Halal Mini Wok")); + System.out.println("Input: Chicken , Ayam Penyet ## OutPut: " + database.searchFoodByNameByStore("Chicken", "Ayam Penyet")); + System.out.println("Input: lobster , Michelin ## OutPut: " + database.searchFoodByNameByStore("lobster", "Michelin")); + System.out.println("Input: fish , Halal Mini Wok ## OutPut: " + database.searchFoodByNameByStore("fish", "Halal Mini Wok")); + } + catch (NoSuchElementException e){ + System.out.println("No such food found! " + e); + } + + // ---- search all food by store ----- + try { + System.out.println("------- testing the search ALL food by store and by name function --------"); + System.out.println("------- Input: Halal Mini Wok -------- "); + database.searchAllFoodByStore("Halal Mini Wok").forEach(System.out::println); + System.out.println("------- Input: Ayam Penyet -------- "); + database.searchAllFoodByStore("Ayam Penyet").forEach(System.out::println); + System.out.println("------- Input: Michelin -------- "); + database.searchAllFoodByStore("Michelin").forEach(System.out::println); + System.out.println("------- Input: Gordan Ramsey's restaurant -------- "); + database.searchAllFoodByStore("Gordon Ramsey's restaurant").forEach(System.out::println); + } + catch (NoSuchElementException e) { + System.out.println("There is no such store! " + e); + } + + // ---- search food by Name by canteen ------ + try { + System.out.println("------- testing the search food by canteen and by name function --------"); + System.out.println("Input: Fried , Science ## OutPut: " + database.searchFoodByNameByCanteen("Fried", "Science")); + System.out.println("Input: Chicken , Science ## OutPut: " + database.searchFoodByNameByCanteen("Chicken", "Science")); + System.out.println("Input: lobster , Science ## OutPut: " + database.searchFoodByNameByCanteen("lobster", "Science")); + System.out.println("Input: lobster , Raffles Hotel Suite ## OutPut: " + database.searchFoodByNameByCanteen("lobster", "Raffles Hotel Suite")); + } + catch (NoSuchElementException e) { + System.out.println("There is either no such canteen or no such food in that canteen!" + e); + } + + // ---- search all food below calorie ------ + + System.out.println("------- testing the search food below calorie function --------"); + System.out.println(" ---- Input : 400"); + database.searchAllFoodBelowCalorie(400).forEach(System.out::println); + System.out.println(" ---- Input : 200"); + database.searchAllFoodBelowCalorie(200).forEach(System.out::println); + System.out.println(" ---- Input : 3428"); + database.searchAllFoodBelowCalorie(3428).forEach(System.out::println); + } } \ No newline at end of file From a457ed2e1421ef0a3db2fd07274120622a1d9f66 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 11 Oct 2020 15:34:46 +0800 Subject: [PATCH 055/271] Change input parameter for two methods --- src/main/java/seedu/duke/Ui.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 5bae580485..2c0fab226d 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -1,5 +1,7 @@ package seedu.duke; +import java.util.ArrayList; + /** * Represents a text user interface. * A Ui objects deals with user interaction by showing users the appropriate messages after a @@ -144,15 +146,15 @@ public void printNewFood(Food newFood) { * Prints all the food items in the food list in the order that they were added or a message stating * that the food list is empty if there are no food items. * - * @param foodList The food list containing all the food items. + * @param foodList The arraylist containing all the food items. */ - public void printFoodList(FoodList foodList) { - if (foodList.getFoods().isEmpty()) { + public void printFoodList(ArrayList foodList) { + if (foodList.isEmpty()) { print("DietBook is currently empty."); } else { String allFood = ""; int foodItemNumber = 1; - for (Food food : foodList.getFoods()) { + for (Food food : foodList) { allFood += LINE_SEPARATOR + " " + foodItemNumber + "." + food; foodItemNumber++; } @@ -178,11 +180,11 @@ public void printDatabase(List foodDatabase) { /** * Prints all the information related to the user. * - * @param person The user. + * @param personInformation The user's personal information. */ - public void printPersonInformation(Person person) { + public void printPersonInformation(String personInformation) { print("Here is your information:" + LINE_SEPARATOR - + person); + + personInformation); } /** From 2879c68d6ad0c60196d6836728b949f817d72869 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 12 Oct 2020 08:50:28 +0800 Subject: [PATCH 056/271] Further documentation - portionSize() -> getPortionSize() --- src/main/java/seedu/duke/list/FoodEntry.java | 6 +++--- src/main/java/seedu/duke/list/FoodList.java | 8 +++++++- src/main/java/seedu/duke/list/FoodListManager.java | 12 ++++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/duke/list/FoodEntry.java b/src/main/java/seedu/duke/list/FoodEntry.java index 8016d6bf32..7aa6f115e6 100644 --- a/src/main/java/seedu/duke/list/FoodEntry.java +++ b/src/main/java/seedu/duke/list/FoodEntry.java @@ -4,7 +4,7 @@ /** - * Data class to story both serving sizes and a food object as a single object. + * Data class to store both serving sizes and a food object as a single object. */ public class FoodEntry { private int portionSize; @@ -25,7 +25,7 @@ public Food getFood() { return food; } - public int portionSize() { + public int getPortionSize() { return portionSize; } @@ -34,4 +34,4 @@ public String toString() { return String.format("%s -- (%s)", food.toString(), portionSize); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java index 4d862540a1..92f92c47e3 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -43,6 +43,7 @@ public String addFood(int portionSize, String name, int calorie, /** * Food database search functionality support. + * Not expected to function. Added for completeness. * Currently just throws a not found exception when called in this manner. * @param portionSize integer to designate number of servings * @param name food object to be added @@ -61,12 +62,17 @@ public String delete(int index) throws IndexOutOfBoundsException { throw e; } } - + public boolean clear() { this.foodEntries = new ArrayList<>(); return true; } + /** + * Obtain the food objects in Foodlist as an ArrayList. + * For other classes that wish to operate on the Food items directly. + * @return Arraylist of ordered Food objects in Foodlist's foodEntries. + */ public ArrayList getFoods() { return FoodListManager.listToFoods(foodEntries); } diff --git a/src/main/java/seedu/duke/list/FoodListManager.java b/src/main/java/seedu/duke/list/FoodListManager.java index cff588f01b..7165cae639 100644 --- a/src/main/java/seedu/duke/list/FoodListManager.java +++ b/src/main/java/seedu/duke/list/FoodListManager.java @@ -11,17 +11,25 @@ */ public class FoodListManager { + /** + * Internal helper method to convert the items in the arraylist into enumed strings. + * Primarily used to obtain String representations of the list. + */ protected static String listToString(ArrayList list) { String listString = ""; for (int i = 1; i <= list.size(); i++) { - FoodEntry task = list.get(i - 1); + FoodEntry entry = list.get(i - 1); listString += i + ". " - + task.toString() + "\n"; + + entry.toString() + "\n"; } return listString; } + /** + * Similar to listToString. + * Extracts only the Food component from FoodEntries. + */ protected static ArrayList listToFoods(ArrayList list) { ArrayList foods = new ArrayList<>(); list.forEach(x -> { From f878ec139ab1e38f3b045d6cc16118bded267efe Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 12 Oct 2020 14:04:30 +0800 Subject: [PATCH 057/271] Change input parameters for three methods --- src/main/java/seedu/duke/Ui.java | 86 ++++++++++++++------------------ 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 2c0fab226d..16810111ea 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -1,6 +1,6 @@ package seedu.duke; -import java.util.ArrayList; +import java.util.List; /** * Represents a text user interface. @@ -26,7 +26,7 @@ public void printWelcomeMessage() { + "| | | | | |___ | | | |__| | | | | | | | |/ /" + LINE_SEPARATOR + "| | | | | ___| | | | __ <| | | | | | | /" + LINE_SEPARATOR + "| |__| | | |___ | | | |__| | |__| | | | | |\\ \\" + LINE_SEPARATOR - + "|_______/|__|______| |__| |_______/ \\______/ \\______/|__| \\__\" + LINE_SEPARATOR"; + + "|_______/|__|______| |__| |_______/ \\______/ \\______/|__| \\__\\" + LINE_SEPARATOR; print(logo + LINE_SEPARATOR + "Hello! Welcome to DietBook!" + LINE_SEPARATOR + "I am Diet, your guide to using DietBook. What is your name?" + LINE_SEPARATOR @@ -40,32 +40,28 @@ public void printWelcomeMessage() { * * @param name The name of the user. */ - public void printAskUserForPersonalInformationMessage(String name) { + public void printAskForUserInfoMessage(String name) { print("Hi " + name + "!" + LINE_SEPARATOR + "Before we get started, I would like to know about about you so that I can make more " - + "accurate calculations for you :)" + LINE_SEPARATOR - + "Therefore, could you please share with me the following:" + LINE_SEPARATOR - + "1. Your gender either F for female or M for male." + LINE_SEPARATOR - + "2. Your age which is a positive integer." + LINE_SEPARATOR - + "3. Your height in cm." + LINE_SEPARATOR - + "4. Your original weight in kg." + LINE_SEPARATOR - + "5. Your target weight in kg, or your original weight if your original weight is also " - + "your target weight." + LINE_SEPARATOR - + "6. Activity level from 1 to 5." + LINE_SEPARATOR - + " 1. " + ActivityLevel.NONE.getDescription() + LINE_SEPARATOR - + " 2. " + ActivityLevel.LOW.getDescription() + LINE_SEPARATOR - + " 3. " + ActivityLevel.MEDIUM.getDescription() + LINE_SEPARATOR - + " 4. " + ActivityLevel.HIGH.getDescription() + LINE_SEPARATOR - + " 5. " + ActivityLevel.EXTREME.getDescription() + LINE_SEPARATOR + LINE_SEPARATOR + + LINE_SEPARATOR + + "accurate calculations for you :). Therefore, could you please share with me the " + + "following:" + LINE_SEPARATOR + + "- Your gender either F for female or M for male." + LINE_SEPARATOR + + "- Your age which is a positive integer." + LINE_SEPARATOR + + "- Your height in cm." + LINE_SEPARATOR + + "- Your original weight in kg." + LINE_SEPARATOR + + "- Your target weight in kg, or your original weight if that is also your target weight." + + LINE_SEPARATOR + + "- Your activity level, represented by a number from 1 to 5." + LINE_SEPARATOR + + " 1 = " + ActivityLevel.NONE.getDescription() + LINE_SEPARATOR + + " 2 = " + ActivityLevel.LOW.getDescription() + LINE_SEPARATOR + + " 3 = " + ActivityLevel.MEDIUM.getDescription() + LINE_SEPARATOR + + " 4 = " + ActivityLevel.HIGH.getDescription() + LINE_SEPARATOR + + " 5 = " + ActivityLevel.EXTREME.getDescription() + LINE_SEPARATOR + LINE_SEPARATOR + "Please input your details in the following format:" + LINE_SEPARATOR - + " info g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL o/ORIGINAL_WEIGHT t/TARGET_WEIGHT" + + " info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT t/TARGET_WEIGHT l/ACTIVITY_LEVEL" + LINE_SEPARATOR - + " Example: info g/F a/21 h/165 l/2 o/65 t/55"); - //"4. Your current weight in kg." - //"5. Your target weight in kg, or your current weight if your current weight is also your target - // weight."; - //" info g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL c/CURRENT_WEIGHT t/TARGET_WEIGHT"); - //" Example: info g/F a/21 h/165 l/2 c/65 t/55"; + + " Example: info g/F a/21 h/165 o/65 t/55 l/2"); } // public void printWelcomeMessage() { @@ -93,11 +89,11 @@ public void printAskUserForPersonalInformationMessage(String name) { // System.out.println("6. Your target weight in kg, or your current weight if your " // + "current weight is also your target weight."); // System.out.println("7. Activity level from 1 to 5."); -// System.out.println(" 1. " + ActvityLevel.NONE.getDescription()); -// System.out.println(" 2. " + ActvityLevel.LOW.getDescription()); -// System.out.println(" 3. " + ActvityLevel.MEDIUM.getDescription()); -// System.out.println(" 4. " + ActvityLevel.HIGH.getDescription()); -// System.out.println(" 5. " + ActvityLevel.EXTEREME.getDescription()); +// System.out.println(" 1. " + ActivityLevel.NONE.getDescription()); +// System.out.println(" 2. " + ActivityLevel.LOW.getDescription()); +// System.out.println(" 3. " + ActivityLevel.MEDIUM.getDescription()); +// System.out.println(" 4. " + ActivityLevel.HIGH.getDescription()); +// System.out.println(" 5. " + ActivityLevel.EXTREME.getDescription()); // System.out.println(LINE_SEPARATOR); // System.out.println("Please input your details in the following format:"); // System.out.println(" info n/NAME g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL o/ORIGINAL_WEIGHT " @@ -116,13 +112,13 @@ public void printAskUserForPersonalInformationMessage(String name) { public void printTutorialMessage() { print("Thank you! DietBook has been initialised and you may start by entering any of the commands " + "listed below." + LINE_SEPARATOR + LINE_SEPARATOR - + "To add you own food: add n/FOOD_NAME x/PORTION_SIZE k/CALORIE [c/CARB] [p/PROTEIN] " - + "[f/FAT]" + LINE_SEPARATOR + + "To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE" + LINE_SEPARATOR + + "To view all food in the database: data" + LINE_SEPARATOR + + "To add you own food: add n/FOOD_NAME x/PORTION_SIZE k/CALORIE [c/CARBOHYDRATE] " + + "[p/PROTEIN] [f/FAT]" + LINE_SEPARATOR + "To view all food in DietBook: list" + LINE_SEPARATOR + "To delete a food from DietBook: delete INDEX" + LINE_SEPARATOR + "To delete all food items from the DietBook: clear" + LINE_SEPARATOR - + "To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE\n" + LINE_SEPARATOR - + "To view all food in the database: data" + LINE_SEPARATOR + "To show user information: userinfo" + LINE_SEPARATOR + "To calculate carbohydrate intake: calculate carbohydrate" + LINE_SEPARATOR + "To calculate calorie intake: calculate calorie" + LINE_SEPARATOR @@ -135,9 +131,9 @@ public void printTutorialMessage() { /** * Prints a message to show that the food specified has been added to the food list. * - * @param newFood The new food item that was added to the food list. + * @param newFood The string representation of the new food item that was added to the food list. */ - public void printNewFood(Food newFood) { + public void printNewFood(String newFood) { print("Got it! I've added this food item:" + LINE_SEPARATOR + " " + newFood); } @@ -146,19 +142,13 @@ public void printNewFood(Food newFood) { * Prints all the food items in the food list in the order that they were added or a message stating * that the food list is empty if there are no food items. * - * @param foodList The arraylist containing all the food items. + * @param allFood The string representation of all the food items in the food list. */ - public void printFoodList(ArrayList foodList) { - if (foodList.isEmpty()) { + public void printFoodList(String allFood) { + if (allFood.length() < 1) { print("DietBook is currently empty."); } else { - String allFood = ""; - int foodItemNumber = 1; - for (Food food : foodList) { - allFood += LINE_SEPARATOR + " " + foodItemNumber + "." + food; - foodItemNumber++; - } - print("Here are the food items in DietBook:" + allFood); + print("Here are the food items in DietBook:" + LINE_SEPARATOR + allFood); } } @@ -246,9 +236,9 @@ public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, in /** * Prints a message to show that the food specified has been deleted from the food list. * - * @param deletedFood The food that was deleted from the food list. + * @param deletedFood The string representation of the food that was deleted from the food list. */ - public void printDeletedFood(Food deletedFood) { + public void printDeletedFood(String deletedFood) { print("Noted. I've removed this food item:" + LINE_SEPARATOR + " " + deletedFood); } @@ -287,7 +277,7 @@ public void printErrorMessage(String errorMessage) { public void print(String message) { String divider = "__________________________________________________________________________________________" - + "__________"; + + "______________________________________________________"; System.out.println(divider + LINE_SEPARATOR + message + LINE_SEPARATOR From 92a56d932d4ca4bb6cec1b62953a611feb45af55 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 12 Oct 2020 15:11:01 +0800 Subject: [PATCH 058/271] Import necessary classes --- src/main/java/seedu/duke/Ui.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 16810111ea..a33007cac4 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -1,5 +1,8 @@ package seedu.duke; +import seedu.duke.food.Food; +import seedu.duke.person.ActivityLevel; + import java.util.List; /** From c6d18d912c79c610c60fae19bc2a5dc88f0151f3 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Mon, 12 Oct 2020 21:38:13 +0800 Subject: [PATCH 059/271] calculator v0.5 added JUnit test --- build.gradle | 2 + src/main/java/seedu/calculator/Food.java | 43 ++++++++++++++++ .../java/seedu/calculator/calculator.java | 23 +++++---- .../java/seedu/calculator/calculatorTest.java | 50 +++++++++++++++++++ 4 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 src/main/java/seedu/calculator/Food.java create mode 100644 src/test/java/seedu/calculator/calculatorTest.java diff --git a/build.gradle b/build.gradle index b0c5528fb5..3d863f228c 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,8 @@ repositories { } dependencies { + implementation 'org.junit.jupiter:junit-jupiter:5.4.2' + implementation 'org.junit.jupiter:junit-jupiter:5.4.2' testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' } diff --git a/src/main/java/seedu/calculator/Food.java b/src/main/java/seedu/calculator/Food.java new file mode 100644 index 0000000000..e8f19f20f5 --- /dev/null +++ b/src/main/java/seedu/calculator/Food.java @@ -0,0 +1,43 @@ +package seedu.calculator; + +public class Food { + private final String name; + private final int calorie; + private final int carbohydrate; + private final int protein; + private final int fats; + + public Food(String name, int calorie, int carbohydrate, int protein, int fats) { + this.name = name; + this.calorie = calorie; + this.carbohydrate = carbohydrate; + this.protein = protein; + this.fats = fats; + } + + public int getFats() { + return fats; + } + + public String getName() { + return name; + } + + public int getCalorie() { + return calorie; + } + + public int getCarbohydrate() { + return carbohydrate; + } + + public int getProtein() { + return protein; + } + + @Override + public String toString() { + return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate + + " | fats : " + fats; + } +} diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/calculator.java index e6fd57fae0..69e34ca0e4 100644 --- a/src/main/java/seedu/calculator/calculator.java +++ b/src/main/java/seedu/calculator/calculator.java @@ -1,13 +1,16 @@ package seedu.calculator; import java.util.ArrayList; -import seedu.foodList; +//import seedu.foodList; /** * Represents a calculator of food items in foodList. */ public class calculator { - private static Food total = new Food (total, 1, 0, 0, 0, 0); + private static int totalCalorie = 0; + private static int totalCarbohydrate = 0; + private static int totalProtein = 0; + private static int totalFats = 0; /** * Construct a calculator taking in a foodList. Add up calories, @@ -18,10 +21,10 @@ public class calculator { public calculator(ArrayList foodList){ try { for(int i=0; i< foodList.size(); i++){ - total.calorie += foodList.get(i).portionSize * foodList.get(i).calorie; - total.carbs += foodList.get(i).portionSize * foodList.get(i).carbs(i); - total.protein += foodList.get(i).portionSize * foodList.get(i).protein(i); - total.fats += foodList.get(i).portionSize * foodList.get(i).fats(i); + totalCalorie += foodList.get(i).getCalorie(); + totalCarbohydrate += foodList.get(i).getCarbohydrate(); + totalProtein += foodList.get(i).getProtein(); + totalFats += foodList.get(i).getFats(); } } catch (NullPointerException e) { System.out.println("Ops, This foodList is null!"); @@ -34,7 +37,7 @@ public calculator(ArrayList foodList){ * @return the value of total calorie of food items in foodList. */ public int calculateCalorie(){ - return total.calorie; + return totalCalorie; } /** @@ -43,7 +46,7 @@ public int calculateCalorie(){ * @return the value of total carbs of food items in foodList. */ public int calculateCarbs(){ - return total.carbs; + return totalCarbohydrate; } /** @@ -52,7 +55,7 @@ public int calculateCarbs(){ * @return the value of total protein of food items in foodList. */ public int calculateProtein(){ - return total.protein; + return totalProtein; } /** @@ -61,6 +64,6 @@ public int calculateProtein(){ * @return the value of total fats of food items in foodList. */ public int calculateFats(){ - return total.fats; + return totalFats; } } \ No newline at end of file diff --git a/src/test/java/seedu/calculator/calculatorTest.java b/src/test/java/seedu/calculator/calculatorTest.java new file mode 100644 index 0000000000..731ba04da8 --- /dev/null +++ b/src/test/java/seedu/calculator/calculatorTest.java @@ -0,0 +1,50 @@ +package seedu.calculator; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.*; + +class calculatorTest { + + @Test + void calculateCalorie() { + ArrayList foodList = new ArrayList<>(); + foodList.add(new Food("chicken rice", 666, 55, 30, 0)); + foodList.add(new Food("pancake", 150, 16, 0, 0)); + foodList.add(new Food("bao", 290, 0, 16, 0)); + calculator calculator = new calculator(foodList); + assertEquals(666 + 150 + 290, calculator.calculateCalorie()); + } + + @Test + void calculateCarbs() { + ArrayList foodList = new ArrayList<>(); + foodList.add(new Food("chicken rice", 666, 55, 30, 0)); + foodList.add(new Food("pancake", 150, 16, 0, 0)); + foodList.add(new Food("bao", 290, 0, 16, 0)); + calculator calculator = new calculator(foodList); + assertEquals(55 + 16, calculator.calculateCarbs()); + } + + @Test + void calculateProtein() { + ArrayList foodList = new ArrayList<>(); + foodList.add(new Food("chicken rice", 666, 55, 30, 0)); + foodList.add(new Food("pancake", 150, 16, 0, 0)); + foodList.add(new Food("bao", 290, 0, 16, 0)); + calculator calculator = new calculator(foodList); + assertEquals(30 + 16, calculator.calculateProtein()); + } + + @Test + void calculateFats() { + ArrayList foodList = new ArrayList<>(); + foodList.add(new Food("chicken rice", 666, 55, 30, 0)); + foodList.add(new Food("pancake", 150, 16, 0, 0)); + foodList.add(new Food("bao", 290, 0, 16, 0)); + calculator calculator = new calculator(foodList); + assertEquals(0, calculator.calculateFats()); + } +} \ No newline at end of file From 49e1372959fd97537058e73cc0a274d50b22a49b Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Mon, 12 Oct 2020 22:08:57 +0800 Subject: [PATCH 060/271] calculator v0.6 --- src/main/java/seedu/calculator/calculator.java | 2 +- src/test/java/seedu/calculator/calculatorTest.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/calculator.java index 69e34ca0e4..639ff272d5 100644 --- a/src/main/java/seedu/calculator/calculator.java +++ b/src/main/java/seedu/calculator/calculator.java @@ -66,4 +66,4 @@ public int calculateProtein(){ public int calculateFats(){ return totalFats; } -} \ No newline at end of file +} diff --git a/src/test/java/seedu/calculator/calculatorTest.java b/src/test/java/seedu/calculator/calculatorTest.java index 731ba04da8..64cdbae3a7 100644 --- a/src/test/java/seedu/calculator/calculatorTest.java +++ b/src/test/java/seedu/calculator/calculatorTest.java @@ -4,12 +4,12 @@ import java.util.ArrayList; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; class calculatorTest { @Test - void calculateCalorie() { + void calculateCalorie_foodListOfThreeItems_sumOfCalorie() { ArrayList foodList = new ArrayList<>(); foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); @@ -19,7 +19,7 @@ void calculateCalorie() { } @Test - void calculateCarbs() { + void calculateCarbs_foodListOfThreeItems_sumOfCarbs() { ArrayList foodList = new ArrayList<>(); foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); @@ -29,7 +29,7 @@ void calculateCarbs() { } @Test - void calculateProtein() { + void calculateProtein_foodListOfThreeItems_sumOfProtein() { ArrayList foodList = new ArrayList<>(); foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); @@ -39,7 +39,7 @@ void calculateProtein() { } @Test - void calculateFats() { + void calculateFats_foodListOfThreeItems_sumOfFats() { ArrayList foodList = new ArrayList<>(); foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); @@ -47,4 +47,4 @@ void calculateFats() { calculator calculator = new calculator(foodList); assertEquals(0, calculator.calculateFats()); } -} \ No newline at end of file +} From b4b2c503b01e05f87b90f0a42c084f0484f4e487 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Mon, 12 Oct 2020 23:02:35 +0800 Subject: [PATCH 061/271] calculator v0.7 fixes #25 --- src/main/java/seedu/calculator/calculator.java | 16 ++++++++-------- .../java/seedu/calculator/calculatorTest.java | 6 ++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/calculator.java index 639ff272d5..faf7766439 100644 --- a/src/main/java/seedu/calculator/calculator.java +++ b/src/main/java/seedu/calculator/calculator.java @@ -7,10 +7,10 @@ * Represents a calculator of food items in foodList. */ public class calculator { - private static int totalCalorie = 0; - private static int totalCarbohydrate = 0; - private static int totalProtein = 0; - private static int totalFats = 0; + private int totalCalorie = 0; + private int totalCarbohydrate = 0; + private int totalProtein = 0; + private int totalFat = 0; /** * Construct a calculator taking in a foodList. Add up calories, @@ -24,7 +24,7 @@ public calculator(ArrayList foodList){ totalCalorie += foodList.get(i).getCalorie(); totalCarbohydrate += foodList.get(i).getCarbohydrate(); totalProtein += foodList.get(i).getProtein(); - totalFats += foodList.get(i).getFats(); + totalFat += foodList.get(i).getFats(); } } catch (NullPointerException e) { System.out.println("Ops, This foodList is null!"); @@ -45,7 +45,7 @@ public int calculateCalorie(){ * * @return the value of total carbs of food items in foodList. */ - public int calculateCarbs(){ + public int calculateCarb(){ return totalCarbohydrate; } @@ -63,7 +63,7 @@ public int calculateProtein(){ * * @return the value of total fats of food items in foodList. */ - public int calculateFats(){ - return totalFats; + public int calculateFat(){ + return totalFat; } } diff --git a/src/test/java/seedu/calculator/calculatorTest.java b/src/test/java/seedu/calculator/calculatorTest.java index 64cdbae3a7..f8667b0ea6 100644 --- a/src/test/java/seedu/calculator/calculatorTest.java +++ b/src/test/java/seedu/calculator/calculatorTest.java @@ -8,6 +8,8 @@ class calculatorTest { + + @Test void calculateCalorie_foodListOfThreeItems_sumOfCalorie() { ArrayList foodList = new ArrayList<>(); @@ -25,7 +27,7 @@ void calculateCarbs_foodListOfThreeItems_sumOfCarbs() { foodList.add(new Food("pancake", 150, 16, 0, 0)); foodList.add(new Food("bao", 290, 0, 16, 0)); calculator calculator = new calculator(foodList); - assertEquals(55 + 16, calculator.calculateCarbs()); + assertEquals(55 + 16, calculator.calculateCarb()); } @Test @@ -45,6 +47,6 @@ void calculateFats_foodListOfThreeItems_sumOfFats() { foodList.add(new Food("pancake", 150, 16, 0, 0)); foodList.add(new Food("bao", 290, 0, 16, 0)); calculator calculator = new calculator(foodList); - assertEquals(0, calculator.calculateFats()); + assertEquals(0, calculator.calculateFat()); } } From 006a414e78a393cf68cf079613dd9a6210c43108 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 12 Oct 2020 23:03:14 +0800 Subject: [PATCH 062/271] Add assertions for Person class --- build.gradle | 1 + src/main/java/seedu/duke/person/Person.java | 29 +++++++++++++++++-- .../java/seedu/duke/person/PersonTest.java | 13 --------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index b0c5528fb5..91fffd027d 100644 --- a/build.gradle +++ b/build.gradle @@ -43,4 +43,5 @@ checkstyle { run{ standardInput = System.in + enableAssertions = true } diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/duke/person/Person.java index 91e0c32c2f..ad3d49b348 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/duke/person/Person.java @@ -32,7 +32,20 @@ public class Person { */ public Person(String name, Gender gender, int age, int height, int originalWeight, int targetWeight, ActivityLevel activityLevel) { - this.name = name; + assert name != null : "Name of person should not be null"; + assert name.trim().length() > 0 : "Name of person should not be an empty string"; + assert gender != null : "Gender of person should not be null"; + assert age > 0 : "Age of person should be greater than 0"; + assert age < 125 : "Age of person should be less than 125"; + assert height > 0 : "Height of person should be greater than 0"; + assert height < 273 : "Height of person should be less than 273"; + assert originalWeight > 0 : "Original weight of person should be greater than 0"; + assert originalWeight < 443 : "Original weight of person should be less than 443"; + assert targetWeight > 0 : "Target weight of person should be greater than 0"; + assert targetWeight < 443 : "Target weight of person should be less than 443"; + assert activityLevel != null : "Activity level of person should not be null"; + + this.name = name.trim(); this.gender = gender; this.age = age; this.height = height; @@ -56,7 +69,9 @@ public String getName() { * @param newName The new/revised name of the person. */ public void setName(String newName) { - name = newName; + assert newName != null : "The revised name of person should not be null"; + assert newName.trim().length() > 0 : "The revised name of person should not be an empty string"; + name = newName.trim(); } /** @@ -74,6 +89,7 @@ public Gender getGender() { * @param newGender The new/revised gender of the person. */ public void setGender(Gender newGender) { + assert newGender != null : "The revised gender of person should not be null"; gender = newGender; } @@ -92,6 +108,8 @@ public int getAge() { * @param newAge The new/revised age of the person. */ public void setAge(int newAge) { + assert newAge > 0 : "The revised age of person should be greater than 0"; + assert newAge < 125 : "The revised age of person should be lesser than 125"; age = newAge; } @@ -110,6 +128,8 @@ public int getHeight() { * @param newHeight The new/revised height of the person. */ public void setHeight(int newHeight) { + assert newHeight > 0 : "The revised height of person should be greater than 0"; + assert newHeight < 273 : "The revised height of person should be lesser than 273"; height = newHeight; } @@ -128,6 +148,8 @@ public int getOriginalWeight() { * @param newOriginalWeight The new/revised original weight of the person. */ public void setOriginalWeight(int newOriginalWeight) { + assert newOriginalWeight > 0 : "The revised original weight of person should be greater than 0"; + assert newOriginalWeight < 443 : "The revised original weight of person should be lesser than 443"; originalWeight = newOriginalWeight; } @@ -146,6 +168,8 @@ public int getTargetWeight() { * @param newTargetWeight The new/revised target weight of the person. */ public void setTargetWeight(int newTargetWeight) { + assert newTargetWeight > 0 : "The revised target weight of person should be greater than 0"; + assert newTargetWeight < 443 : "The revised target weight of person should be lesser than 443"; targetWeight = newTargetWeight; } @@ -164,6 +188,7 @@ public ActivityLevel getActivityLevel() { * @param newActivityLevel The new/revised activity level of the person. */ public void setActivityLevel(ActivityLevel newActivityLevel) { + assert newActivityLevel != null : "The revised activity level of person should not be null"; activityLevel = newActivityLevel; } diff --git a/src/test/java/seedu/duke/person/PersonTest.java b/src/test/java/seedu/duke/person/PersonTest.java index 415fd43134..714a66021b 100644 --- a/src/test/java/seedu/duke/person/PersonTest.java +++ b/src/test/java/seedu/duke/person/PersonTest.java @@ -4,7 +4,6 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; class PersonTest { @@ -38,12 +37,6 @@ void gender_personWithNewGender_returnsNewGender() { assertEquals(Gender.FEMALE, person.getGender()); } - @Test - void gender_personWithNullGender_returnsNullGender() { - person.setGender(null); - assertNull(person.getGender()); - } - @Test void getAge_person_returnsAge() { assertEquals(21, person.getAge()); @@ -99,12 +92,6 @@ void setActivityLevel_personWithNewActivityLevel_returnsNewActivityLevel() { assertEquals(ActivityLevel.HIGH, person.getActivityLevel()); } - @Test - void setActivityLevel_personWithNullActivityLevel_returnsNullActivityLevel() { - person.setActivityLevel(null); - assertNull(person.getActivityLevel()); - } - @Test void toString_person_returnsStringRepresentationOfPersonInformation() { assertEquals(" Name: Jack" + System.lineSeparator() From 6f6a0dd8f59cf698927d7338973408a0dc6ea7bb Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Mon, 12 Oct 2020 23:21:26 +0800 Subject: [PATCH 063/271] calculator v0.8 --- .../{calculator.java => Calculator.java} | 10 +++-- src/main/java/seedu/calculator/Food.java | 43 ------------------- .../java/seedu/calculator/calculatorTest.java | 8 ++-- 3 files changed, 10 insertions(+), 51 deletions(-) rename src/main/java/seedu/calculator/{calculator.java => Calculator.java} (90%) delete mode 100644 src/main/java/seedu/calculator/Food.java diff --git a/src/main/java/seedu/calculator/calculator.java b/src/main/java/seedu/calculator/Calculator.java similarity index 90% rename from src/main/java/seedu/calculator/calculator.java rename to src/main/java/seedu/calculator/Calculator.java index faf7766439..a30abf152e 100644 --- a/src/main/java/seedu/calculator/calculator.java +++ b/src/main/java/seedu/calculator/Calculator.java @@ -1,12 +1,14 @@ package seedu.calculator; import java.util.ArrayList; -//import seedu.foodList; + +import seedu.duke.Ui; +import seedu.duke.Food; /** * Represents a calculator of food items in foodList. */ -public class calculator { +public class Calculator { private int totalCalorie = 0; private int totalCarbohydrate = 0; private int totalProtein = 0; @@ -18,7 +20,7 @@ public class calculator { * * @param foodList foodList containing food items to calculate. */ - public calculator(ArrayList foodList){ + public Calculator(ArrayList foodList){ try { for(int i=0; i< foodList.size(); i++){ totalCalorie += foodList.get(i).getCalorie(); @@ -27,7 +29,7 @@ public calculator(ArrayList foodList){ totalFat += foodList.get(i).getFats(); } } catch (NullPointerException e) { - System.out.println("Ops, This foodList is null!"); + Ui.printErrorMessage("the foodList is null"); } } diff --git a/src/main/java/seedu/calculator/Food.java b/src/main/java/seedu/calculator/Food.java deleted file mode 100644 index e8f19f20f5..0000000000 --- a/src/main/java/seedu/calculator/Food.java +++ /dev/null @@ -1,43 +0,0 @@ -package seedu.calculator; - -public class Food { - private final String name; - private final int calorie; - private final int carbohydrate; - private final int protein; - private final int fats; - - public Food(String name, int calorie, int carbohydrate, int protein, int fats) { - this.name = name; - this.calorie = calorie; - this.carbohydrate = carbohydrate; - this.protein = protein; - this.fats = fats; - } - - public int getFats() { - return fats; - } - - public String getName() { - return name; - } - - public int getCalorie() { - return calorie; - } - - public int getCarbohydrate() { - return carbohydrate; - } - - public int getProtein() { - return protein; - } - - @Override - public String toString() { - return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate - + " | fats : " + fats; - } -} diff --git a/src/test/java/seedu/calculator/calculatorTest.java b/src/test/java/seedu/calculator/calculatorTest.java index f8667b0ea6..9a5b9f8f59 100644 --- a/src/test/java/seedu/calculator/calculatorTest.java +++ b/src/test/java/seedu/calculator/calculatorTest.java @@ -16,7 +16,7 @@ void calculateCalorie_foodListOfThreeItems_sumOfCalorie() { foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); foodList.add(new Food("bao", 290, 0, 16, 0)); - calculator calculator = new calculator(foodList); + Calculator calculator = new Calculator(foodList); assertEquals(666 + 150 + 290, calculator.calculateCalorie()); } @@ -26,7 +26,7 @@ void calculateCarbs_foodListOfThreeItems_sumOfCarbs() { foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); foodList.add(new Food("bao", 290, 0, 16, 0)); - calculator calculator = new calculator(foodList); + Calculator calculator = new Calculator(foodList); assertEquals(55 + 16, calculator.calculateCarb()); } @@ -36,7 +36,7 @@ void calculateProtein_foodListOfThreeItems_sumOfProtein() { foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); foodList.add(new Food("bao", 290, 0, 16, 0)); - calculator calculator = new calculator(foodList); + Calculator calculator = new Calculator(foodList); assertEquals(30 + 16, calculator.calculateProtein()); } @@ -46,7 +46,7 @@ void calculateFats_foodListOfThreeItems_sumOfFats() { foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); foodList.add(new Food("bao", 290, 0, 16, 0)); - calculator calculator = new calculator(foodList); + Calculator calculator = new Calculator(foodList); assertEquals(0, calculator.calculateFat()); } } From ae7c53b7dd086926e804c6866194f98feb8b432c Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Mon, 12 Oct 2020 23:26:06 +0800 Subject: [PATCH 064/271] calculator v0.9 --- src/test/java/seedu/calculator/calculatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/calculator/calculatorTest.java b/src/test/java/seedu/calculator/calculatorTest.java index 9a5b9f8f59..bc519ef548 100644 --- a/src/test/java/seedu/calculator/calculatorTest.java +++ b/src/test/java/seedu/calculator/calculatorTest.java @@ -6,7 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -class calculatorTest { +class CalculatorTest { From 7d17630703d0b8420186cd302d98be6215f26716 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 13 Oct 2020 01:17:14 +0800 Subject: [PATCH 065/271] Add assertions for Ui class --- build.gradle | 1 + src/main/java/seedu/duke/Ui.java | 34 ++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index b0c5528fb5..91fffd027d 100644 --- a/build.gradle +++ b/build.gradle @@ -43,4 +43,5 @@ checkstyle { run{ standardInput = System.in + enableAssertions = true } diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index a33007cac4..d1918cb8cd 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -44,6 +44,8 @@ public void printWelcomeMessage() { * @param name The name of the user. */ public void printAskForUserInfoMessage(String name) { + assert name != null : "Name should not be null"; + assert name.trim().length() > 0 : "Name should not be an empty string"; print("Hi " + name + "!" + LINE_SEPARATOR + "Before we get started, I would like to know about about you so that I can make more " + LINE_SEPARATOR @@ -137,6 +139,9 @@ public void printTutorialMessage() { * @param newFood The string representation of the new food item that was added to the food list. */ public void printNewFood(String newFood) { + assert newFood != null : "String representation of the food that was added should not be null"; + assert newFood.trim().length() > 0 : "String representation of the food that was added should not " + + "be an empty string"; print("Got it! I've added this food item:" + LINE_SEPARATOR + " " + newFood); } @@ -148,7 +153,8 @@ public void printNewFood(String newFood) { * @param allFood The string representation of all the food items in the food list. */ public void printFoodList(String allFood) { - if (allFood.length() < 1) { + assert allFood != null : "String representation of all food in food list should not be null"; + if (allFood.trim().length() < 1) { print("DietBook is currently empty."); } else { print("Here are the food items in DietBook:" + LINE_SEPARATOR + allFood); @@ -161,6 +167,8 @@ public void printFoodList(String allFood) { * @param foodDatabase The list containing all the food items stored in the database. */ public void printDatabase(List foodDatabase) { + assert foodDatabase != null : "Food database should not be null"; + assert foodDatabase.size() > 0 : "Food database should not be empty"; String allFood = ""; int foodItemNumber = 1; for (Food food: foodDatabase) { @@ -173,11 +181,13 @@ public void printDatabase(List foodDatabase) { /** * Prints all the information related to the user. * - * @param personInformation The user's personal information. + * @param personInfo The user's personal information. */ - public void printPersonInformation(String personInformation) { + public void printPersonInfo(String personInfo) { + assert personInfo != null : "Person information should not be null"; + assert personInfo.trim().length() > 0 : "Person information should not be an empty string"; print("Here is your information:" + LINE_SEPARATOR - + personInformation); + + personInfo); } /** @@ -186,6 +196,7 @@ public void printPersonInformation(String personInformation) { * @param carbohydrateIntake The total amount of carbohydrates of all the food in the food list. */ public void printCarbohydrateIntake(int carbohydrateIntake) { + assert carbohydrateIntake >= 0 : "Total carbohydrate intake should be equals to or greater than 0"; print("Total carbohydrate intake: " + carbohydrateIntake + "g"); } @@ -195,6 +206,7 @@ public void printCarbohydrateIntake(int carbohydrateIntake) { * @param calorieIntake The total amount of calories of all the food in the food list. */ public void printCalorieIntake(int calorieIntake) { + assert calorieIntake >= 0 : "Total calorie intake should be equals to or greater than 0"; print("Total calorie intake: " + calorieIntake + "kcal"); } @@ -204,6 +216,7 @@ public void printCalorieIntake(int calorieIntake) { * @param proteinIntake The total amount of proteins of all the food in the food list. */ public void printProteinIntake(int proteinIntake) { + assert proteinIntake >= 0 : "Total protein intake should be equals to or greater than 0 "; print("Total protein intake: " + proteinIntake + "g"); } @@ -213,6 +226,7 @@ public void printProteinIntake(int proteinIntake) { * @param fatIntake The total amount of fats of all the food in the food list. */ public void printFatIntake(int fatIntake) { + assert fatIntake >= 0 : "Total fat intake should be equals to or greater than 0"; print("Total fat intake: " + fatIntake + "g"); } @@ -226,6 +240,11 @@ public void printFatIntake(int fatIntake) { */ public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, int proteinIntake, int fatIntake) { + assert carbohydrateIntake >= 0 : "Total carbohydrate intake should be equals to or greater than 0"; + assert calorieIntake >= 0 : "Total calorie intake should be equals to or greater than 0"; + assert proteinIntake >= 0 : "Total protein intake should be equals to or greater than 0 "; + assert fatIntake >= 0 : "Total fat intake should be equals to or greater than 0"; + print("Total calorie intake: " + calorieIntake + "kcal" + LINE_SEPARATOR + "Total carbohydrate intake: " + carbohydrateIntake + "g" + LINE_SEPARATOR + "Total protein intake: " + proteinIntake + "g" + LINE_SEPARATOR @@ -242,6 +261,9 @@ public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, in * @param deletedFood The string representation of the food that was deleted from the food list. */ public void printDeletedFood(String deletedFood) { + assert deletedFood != null : "String representation of the food that was deleted should not be null"; + assert deletedFood.trim().length() > 0 : "String representation of the food that was deleted should" + + " not be an empty string"; print("Noted. I've removed this food item:" + LINE_SEPARATOR + " " + deletedFood); } @@ -260,6 +282,8 @@ public void printClearFoodListMessage() { * @param name The name of the user. */ public void printExitMessage(String name) { + assert name != null : "Name should not be null"; + assert name.trim().length() > 0 : "Name should not be an empty string"; print("Bye " + name + "! Hope to see you again soon!"); } @@ -269,6 +293,8 @@ public void printExitMessage(String name) { * @param errorMessage Message detailing what or where the error is. */ public void printErrorMessage(String errorMessage) { + assert errorMessage != null : "Error message should not be null"; + assert errorMessage.trim().length() > 0 : "Error message should not be an empty string"; print(":( Oh no..." + errorMessage); } From f233f3a676c0acf468fd69b42a523faa0c20354d Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Tue, 13 Oct 2020 04:25:06 +0800 Subject: [PATCH 066/271] Main, Parse, Manager Main parsing --- src/main/java/seedu/duke/DietBook.java | 42 ++++++ src/main/java/seedu/duke/DietException.java | 12 ++ src/main/java/seedu/duke/Duke.java | 21 --- src/main/java/seedu/duke/Manager.java | 53 +++++++ src/main/java/seedu/duke/Parser.java | 151 ++++++++++++++++++++ 5 files changed, 258 insertions(+), 21 deletions(-) create mode 100644 src/main/java/seedu/duke/DietBook.java create mode 100644 src/main/java/seedu/duke/DietException.java delete mode 100644 src/main/java/seedu/duke/Duke.java create mode 100644 src/main/java/seedu/duke/Manager.java create mode 100644 src/main/java/seedu/duke/Parser.java diff --git a/src/main/java/seedu/duke/DietBook.java b/src/main/java/seedu/duke/DietBook.java new file mode 100644 index 0000000000..eb63d10d7b --- /dev/null +++ b/src/main/java/seedu/duke/DietBook.java @@ -0,0 +1,42 @@ +package seedu.duke; +import java.io.IOException; + +public class DietBook { + private FoodList foodList; + private Ui ui; + private Manager manager; + private DataBase dataBase; + public static boolean isExit = false; + + /** + * Constructor for new DietBook + */ + public DietBook() { + ui = new Ui(); + foodList = new FoodList(); + dataBase = new Database(); + manager = new Manager(foodList, dataBase); + } + + /** + * Main method to run the program. + */ + public static void main(String[] args) { + DietBook dietBook = new DietBook(); + dietBook.ui.printWelcomeMessage(); + + while (!isExit) { + try { + String userInput = dietBook.manager.readCommand(); + Parser.parse(userInput, dietBook.manager, dietBook.ui); + } catch (DietException e) { + dietBook.ui.printErrorMessage(e.getMessage()); + } catch (IOException e) { + dietBook.ui.printErrorMessage(e.getMessage()); + break; + } finally { + dietBook.ui.divider(); + } + } + } +} diff --git a/src/main/java/seedu/duke/DietException.java b/src/main/java/seedu/duke/DietException.java new file mode 100644 index 0000000000..1cc3e09655 --- /dev/null +++ b/src/main/java/seedu/duke/DietException.java @@ -0,0 +1,12 @@ +package seedu.duke; + +public class DietException extends Exception { + public DietException(String message) { + super(message); + } + + @Override + public String toString() { + return getMessage(); + } +} 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/Manager.java b/src/main/java/seedu/duke/Manager.java new file mode 100644 index 0000000000..27b295470e --- /dev/null +++ b/src/main/java/seedu/duke/Manager.java @@ -0,0 +1,53 @@ +package seedu.duke; + +import java.util.Scanner; + +public class Manager { + private Person person; + private FoodList foodList; + private String name; + private DataBase dataBase; + private Calculator calculator; + private static Scanner s = new Scanner(System.in); + + public Manager(FoodList foodlist, DataBase dataBase) { + this.name = "John Doe"; + this.person = new Person(); + this.foodList = foodlist; + this.dataBase = dataBase; + this.calculator = new Calculator(0,0,0,0); + } + + public String readCommand() { + return s.nextLine(); + } + + public FoodList getFoodList() { + return this.foodList; + } + + public Person getPerson() { + return this.person; + } + + public void setPerson(String gender, String age,String height,String actLvl,String orgWeight,String targWeight) { + this.person = new Person(gender, age, height, actLvl, orgWeight, targWeight); + } + + public Calculator getCalculator() { + return this.calculator; + } + + public DataBase getDataBase() { + return this.dataBase; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java new file mode 100644 index 0000000000..7611544b6c --- /dev/null +++ b/src/main/java/seedu/duke/Parser.java @@ -0,0 +1,151 @@ +package seedu.duke; +import java.util.Arrays; + +public class Parser { + public static final String COMMAND_NAME = "name"; + public static final String COMMAND_LIST = "list"; + public static final String COMMAND_INFO = "info"; + public static final String COMMAND_EXIT = "exit"; + public static final String COMMAND_ADD = "add"; + public static final String COMMAND_CLEAR = "clear"; + public static final String COMMAND_DELETE = "delete"; + public static final String COMMAND_CALCULATE = "calculate"; + public static final String COMMAND_DATA = "data"; + public static final String COMMAND_USERINFO = "userinfo"; + public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; + public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; + + + /** + * Returns the command of a user input. + * @param userInput which is user input. + * @return First word which is the command of the user input. + */ + private static String getCommand(String userInput) { + return userInput.split(" ")[0]; + } + + /** + * Returns the subsequent parameter after the command from the user input. + * @param userInput user input. + * @return parameter part of the user input. + * @throws DietException when the user input is of a wrong format. + */ + private static String getCommandParam(String userInput) throws DietException { + String command = getCommand(userInput); + String[] input = {userInput}; + + if (userInput.split(command).length < 2 + || userInput.split(command)[1].equals(" ")) { + throw new DietException("☹ Error! Missing command parameters!"); + } else { + switch (command) { + case COMMAND_NAME: + return userInput.split(" ")[1]; + case COMMAND_CALCULATE: + for (String param: PARAM_CALCULATE) { + if (userInput.contains(param)) { + return userInput.split(" ")[1]; + } + } + throw new DietException("☹ Oops! Incorrect nutrient type"); + case COMMAND_ADD: + if (!userInput.contains("n/") || !userInput.contains("x/") || !userInput.contains("k/")) { + throw new DietException("☹ Oh no... Missing or incorrect add statement"); + } + return userInput.substring(userInput.indexOf(' ') + 1); + case COMMAND_INFO: + if (!Arrays.asList(input).containsAll(Arrays.asList(PARAM_INFO))) { + throw new DietException("☹ Oh no... Missing or incorrect info statement"); + } + return userInput.substring(userInput.indexOf(' ') + 1); + default: + return null; + } + } + } + + /** + * Returns the index after the command of a user input, e.g. delete 3. + * @param userInput user input. + * @return index part of the user input. + * @throws DietException when the user input is of a wrong format. + */ + private static int getCommandIndex(String userInput) throws DietException { + String command = getCommand(userInput); + + if (userInput.split(command).length < 2 || userInput.split(command)[1].equals(" ")) { + throw new DietException("☹ OOPS!!! Missing index of duke.task!"); + } + try { + return Integer.parseInt(userInput.split(" ")[1]) - 1; + } catch (NumberFormatException e) { + throw new DietException("☹ OOPS!!! No integer index detected!"); + } + } + + /** + * Makes sense of the user input and carries out the functions according to the command given. + * @param userInput user input. + * @throws DietException when the program does not recognize the command given. + */ + public static void parse(String userInput, Manager manager, Ui ui) throws DietException { + Calculator calculator = manager.getCalculator(); + switch (getCommand(userInput)) { + case COMMAND_NAME: + manager.setName(getCommandParam(userInput)); + ui.printAskForUserInfoMessage(manager.getName()) + return; + case COMMAND_EXIT: + ui.printExitMessage(manager.getName()); + DietBook.isExit = true; + return; + case COMMAND_LIST: + ui.printFoodList(manager.getFoodList()); + return; + case COMMAND_USERINFO: + ui.printPersonInformation(personInformation); + return; + case COMMAND_DATA: + manager.getDataBase().printAllData(); + return; + case COMMAND_DELETE: + ui.printDeletedFood(manager.getFoodList().get(getCommandIndex(userInput))); + manager.getFoodList().delete(getCommandIndex(userInput)); + return; + case COMMAND_CLEAR: + ui.printClearFoodListMessage(); + manager.getFoodList().clear; + return; + case COMMAND_CALCULATE: + if (getCommandParam(userInput).equals("all")) { + ui.printAllNutrientIntake(calculator.calculateCalorie(), calculator.calculateCarb(), + calculator.calculateProtein(), calculator.calculateFat()); + } else if (getCommandParam(userInput).equals("calorie")) { + ui.printCalorieIntake(calculator.calculateCalorie()); + } else if (getCommandParam(userInput).equals("carbohydrate")) { + ui.printCarbohydrateIntake(calculator.calculateCarb()); + } else if (getCommandParam(userInput).equals("protein")) { + ui.printProteinIntake(calculator.calculateProtein()); + } else { + ui.printFatIntake(calculator.calculateFat()); + } + return; + case COMMAND_INFO: + String[] processedParam = getCommandParam(userInput).split(" "); + String gender = processedParam[0].substring(processedParam[0].indexOf("/") + 1); + String age = processedParam[1].substring(processedParam[1].indexOf("/") + 1); + String height = processedParam[2].substring(processedParam[2].indexOf("/") + 1); + String actLvl = processedParam[3].substring(processedParam[3].indexOf("/") + 1); + String orgWeight = processedParam[4].substring(processedParam[4].indexOf("/") + 1); + String tarWeight = processedParam[5].substring(processedParam[5].indexOf("/") + 1); + manager.setPerson(gender, age, height, actLvl, orgWeight, tarWeight); + ui.printTutorialMessage(); + return; + case COMMAND_ADD: + return; + default: + throw new DietException("☹ There's no such command!"); + } + } +} From c7890f7032a047c9a13a592ce79ab84231bcc38d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 13 Oct 2020 12:11:35 +0800 Subject: [PATCH 067/271] Remove unnecessary commented out methods --- src/main/java/seedu/duke/Ui.java | 45 -------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index d1918cb8cd..352e2a978c 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -69,47 +69,6 @@ public void printAskForUserInfoMessage(String name) { + " Example: info g/F a/21 h/165 o/65 t/55 l/2"); } -// public void printWelcomeMessage() { -// String logo = " _______ __ ______ ________ _______ ______ ______ __ __" + LINE_SEPARATOR -// + "| __ \\| | ___|__ __| __ \\ / __ \\ / __ \\| | / /" + LINE_SEPARATOR -// + "| | | | | |___ | | | |__| | | | | | | | |/ /" + LINE_SEPARATOR -// + "| | | | | ___| | | | __ <| | | | | | | /" + LINE_SEPARATOR -// + "| |__| | | |___ | | | |__| | |__| | | | | |\\ \\" + LINE_SEPARATOR -// + "|_______/|__|______| |__| |_______/ \\______/ \\______/|__| \\__\" + LINE_SEPARATOR"; -// System.out.println(DIVIDER); -// System.out.println(logo); -// System.out.println("Hello! Welcome to DietBook!"); -// System.out.println("I am Diet, your guide to using DietBook."); -// System.out.println("Before we get started, I would like to know about about you so that I can make " -// + "more accurate calculations for you :)"); -// System.out.println("Therefore, could you please share with me the following:"); -// System.out.println("1. Your name."); -// System.out.println("2. Your gender either F for female or M for male".); -// System.out.println("3. Your age which is a positive integer."); -// System.out.println("4. Your height in cm."); -// System.out.println("5. Your current weight in kg."); -// System.out.println("5. Your original weight in kg."); -// System.out.println("6. Your target weight in kg, or your original weight if your " -// + "original weight is also your target weight."); -// System.out.println("6. Your target weight in kg, or your current weight if your " -// + "current weight is also your target weight."); -// System.out.println("7. Activity level from 1 to 5."); -// System.out.println(" 1. " + ActivityLevel.NONE.getDescription()); -// System.out.println(" 2. " + ActivityLevel.LOW.getDescription()); -// System.out.println(" 3. " + ActivityLevel.MEDIUM.getDescription()); -// System.out.println(" 4. " + ActivityLevel.HIGH.getDescription()); -// System.out.println(" 5. " + ActivityLevel.EXTREME.getDescription()); -// System.out.println(LINE_SEPARATOR); -// System.out.println("Please input your details in the following format:"); -// System.out.println(" info n/NAME g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL o/ORIGINAL_WEIGHT " -// + "t/TARGET_WEIGHT"); -// System.out.println(" info n/name g/GENDER a/AGE h/HEIGHT l/ACTIVITY_LEVEL c/CURRENT_WEIGHT " -// + "t/TARGET_WEIGHT"); -// System.out.println(" Example: info n/Suzy g/F a/21 h/165 l/2 o/65 t/55"); -// System.out.println(" Example: info n/Suzy g/F a/21 h/165 l/2 c/65 t/55"); -// System.out.println(DIVIDER); -// } - /** * Prints a message that notifies the user that DietBook has been initialised and shows a list of user * commands that the user can input. @@ -251,10 +210,6 @@ public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, in + "Total fat intake: " + fatIntake + "g"); } -// public void printNutrientIntake(String nutritionalIntake) { -// print(nutritionalIntake); -// } - /** * Prints a message to show that the food specified has been deleted from the food list. * From deb48279feb4ffad7a2fe4c594cd3d229d6f10f9 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 13 Oct 2020 18:10:52 +0800 Subject: [PATCH 068/271] calculator after pulling from tp repo. --- src/main/java/seedu/calculator/Calculator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/calculator/Calculator.java b/src/main/java/seedu/calculator/Calculator.java index a30abf152e..4385f43329 100644 --- a/src/main/java/seedu/calculator/Calculator.java +++ b/src/main/java/seedu/calculator/Calculator.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import seedu.duke.Ui; -import seedu.duke.Food; +import seedu.duke.Food; /** * Represents a calculator of food items in foodList. From bb8fc4ed5c13aeaed5bd58d5c4c16e39c4f4cf43 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 13 Oct 2020 18:46:03 +0800 Subject: [PATCH 069/271] calculator v1 --- .../java/seedu/calculator/Calculator.java | 30 ++++++++----------- src/main/java/seedu/duke/Duke.java | 3 +- ...alculatorTest.java => CalculatorTest.java} | 1 + 3 files changed, 16 insertions(+), 18 deletions(-) rename src/test/java/seedu/calculator/{calculatorTest.java => CalculatorTest.java} (98%) diff --git a/src/main/java/seedu/calculator/Calculator.java b/src/main/java/seedu/calculator/Calculator.java index 4385f43329..e50cf15f43 100644 --- a/src/main/java/seedu/calculator/Calculator.java +++ b/src/main/java/seedu/calculator/Calculator.java @@ -1,9 +1,8 @@ package seedu.calculator; -import java.util.ArrayList; +import seedu.duke.food.Food; -import seedu.duke.Ui; -import seedu.duke.Food; +import java.util.ArrayList; /** * Represents a calculator of food items in foodList. @@ -20,16 +19,13 @@ public class Calculator { * * @param foodList foodList containing food items to calculate. */ - public Calculator(ArrayList foodList){ - try { - for(int i=0; i< foodList.size(); i++){ - totalCalorie += foodList.get(i).getCalorie(); - totalCarbohydrate += foodList.get(i).getCarbohydrate(); - totalProtein += foodList.get(i).getProtein(); - totalFat += foodList.get(i).getFats(); - } - } catch (NullPointerException e) { - Ui.printErrorMessage("the foodList is null"); + public Calculator(ArrayList foodList) { + assert foodList != null : "the foodList should not be null."; + for (int i = 0; i < foodList.size(); i++) { + totalCalorie += foodList.get(i).getCalorie(); + totalCarbohydrate += foodList.get(i).getCarbohydrate(); + totalProtein += foodList.get(i).getProtein(); + totalFat += foodList.get(i).getFats(); } } @@ -38,7 +34,7 @@ public Calculator(ArrayList foodList){ * * @return the value of total calorie of food items in foodList. */ - public int calculateCalorie(){ + public int calculateCalorie() { return totalCalorie; } @@ -47,7 +43,7 @@ public int calculateCalorie(){ * * @return the value of total carbs of food items in foodList. */ - public int calculateCarb(){ + public int calculateCarb() { return totalCarbohydrate; } @@ -56,7 +52,7 @@ public int calculateCarb(){ * * @return the value of total protein of food items in foodList. */ - public int calculateProtein(){ + public int calculateProtein() { return totalProtein; } @@ -65,7 +61,7 @@ public int calculateProtein(){ * * @return the value of total fats of food items in foodList. */ - public int calculateFat(){ + public int calculateFat() { return totalFat; } } diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 74e5175952..5c74e68d59 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -6,7 +6,8 @@ public class Duke { /** * Main entry-point for the java.duke.Duke application. */ - public static void main(String[] args) { String logo = " ____ _ \n" + public static void main(String[] args) { + String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n" + "| |_| | |_| | < __/\n" diff --git a/src/test/java/seedu/calculator/calculatorTest.java b/src/test/java/seedu/calculator/CalculatorTest.java similarity index 98% rename from src/test/java/seedu/calculator/calculatorTest.java rename to src/test/java/seedu/calculator/CalculatorTest.java index bc519ef548..673e98c51f 100644 --- a/src/test/java/seedu/calculator/calculatorTest.java +++ b/src/test/java/seedu/calculator/CalculatorTest.java @@ -1,6 +1,7 @@ package seedu.calculator; import org.junit.jupiter.api.Test; +import seedu.duke.food.Food; import java.util.ArrayList; From 5d0eea5cf7a503d19ad46f1022ddc6db6b252012 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 13 Oct 2020 18:54:59 +0800 Subject: [PATCH 070/271] calculator version1 changed plural form to single form. --- src/test/java/seedu/calculator/CalculatorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/calculator/CalculatorTest.java b/src/test/java/seedu/calculator/CalculatorTest.java index 673e98c51f..e58f33a249 100644 --- a/src/test/java/seedu/calculator/CalculatorTest.java +++ b/src/test/java/seedu/calculator/CalculatorTest.java @@ -22,7 +22,7 @@ void calculateCalorie_foodListOfThreeItems_sumOfCalorie() { } @Test - void calculateCarbs_foodListOfThreeItems_sumOfCarbs() { + void calculateCarb_foodListOfThreeItems_sumOfCarb() { ArrayList foodList = new ArrayList<>(); foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); @@ -42,7 +42,7 @@ void calculateProtein_foodListOfThreeItems_sumOfProtein() { } @Test - void calculateFats_foodListOfThreeItems_sumOfFats() { + void calculateFat_foodListOfThreeItems_sumOfFat() { ArrayList foodList = new ArrayList<>(); foodList.add(new Food("chicken rice", 666, 55, 30, 0)); foodList.add(new Food("pancake", 150, 16, 0, 0)); From 7b7cd2fb8ad8833819c4417e6ad5cb438c3ba2a7 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 13 Oct 2020 21:12:28 +0800 Subject: [PATCH 071/271] pass gradle checkstyle test --- .../seedu/duke/database/DataBaseTest.java | 43 ++++++++++--------- src/test/java/seedu/duke/food/FoodTest.java | 3 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/test/java/seedu/duke/database/DataBaseTest.java b/src/test/java/seedu/duke/database/DataBaseTest.java index a060a3ea2c..116b4192bc 100644 --- a/src/test/java/seedu/duke/database/DataBaseTest.java +++ b/src/test/java/seedu/duke/database/DataBaseTest.java @@ -3,10 +3,9 @@ import java.io.FileNotFoundException; import java.util.NoSuchElementException; -import static org.junit.jupiter.api.Assertions.*; class DataBaseTest { - public static void main(String[] args){ + public static void main(String[] args) { DataBase database = new DataBase(); try { database.init(); @@ -30,23 +29,25 @@ public static void main(String[] args){ System.out.println("Input: Prawn ## OutPut: " + database.searchFoodByName("Prawn")); System.out.println("Input: Mee ## OutPut: " + database.searchFoodByName("Mee")); System.out.println("Input: lobster ## OutPut: " + database.searchFoodByName("lobster")); - System.out.println("Input: Prawn ## OutPut: " + database.searchFoodByName("koala bears")); - } - catch (NoSuchElementException e){ + } catch (NoSuchElementException e) { System.out.println("No such food found! " + e); } // ---- search food by store name test ---- System.out.println("------- testing the search food by store and by name function --------"); try { - System.out.println("Input: Fried , Halal Mini Wok ## OutPut: " + database.searchFoodByNameByStore("Fried", "Halal Mini Wok")); - System.out.println("Input: Chicken , Halal Mini Wok ## OutPut: " + database.searchFoodByNameByStore("Chicken", "Halal Mini Wok")); - System.out.println("Input: Chicken , Ayam Penyet ## OutPut: " + database.searchFoodByNameByStore("Chicken", "Ayam Penyet")); - System.out.println("Input: lobster , Michelin ## OutPut: " + database.searchFoodByNameByStore("lobster", "Michelin")); - System.out.println("Input: fish , Halal Mini Wok ## OutPut: " + database.searchFoodByNameByStore("fish", "Halal Mini Wok")); - } - catch (NoSuchElementException e){ + System.out.println("Input: Fried , Halal Mini Wok ## OutPut: " + + database.searchFoodByNameByStore("Fried", "Halal Mini Wok")); + System.out.println("Input: Chicken , Halal Mini Wok ## OutPut: " + + database.searchFoodByNameByStore("Chicken", "Halal Mini Wok")); + System.out.println("Input: Chicken , Ayam Penyet ## OutPut: " + + database.searchFoodByNameByStore("Chicken", "Ayam Penyet")); + System.out.println("Input: lobster , Michelin ## OutPut: " + + database.searchFoodByNameByStore("lobster", "Michelin")); + System.out.println("Input: fish , Halal Mini Wok ## OutPut: " + + database.searchFoodByNameByStore("fish", "Halal Mini Wok")); + } catch (NoSuchElementException e) { System.out.println("No such food found! " + e); } @@ -61,20 +62,22 @@ public static void main(String[] args){ database.searchAllFoodByStore("Michelin").forEach(System.out::println); System.out.println("------- Input: Gordan Ramsey's restaurant -------- "); database.searchAllFoodByStore("Gordon Ramsey's restaurant").forEach(System.out::println); - } - catch (NoSuchElementException e) { + } catch (NoSuchElementException e) { System.out.println("There is no such store! " + e); } // ---- search food by Name by canteen ------ try { System.out.println("------- testing the search food by canteen and by name function --------"); - System.out.println("Input: Fried , Science ## OutPut: " + database.searchFoodByNameByCanteen("Fried", "Science")); - System.out.println("Input: Chicken , Science ## OutPut: " + database.searchFoodByNameByCanteen("Chicken", "Science")); - System.out.println("Input: lobster , Science ## OutPut: " + database.searchFoodByNameByCanteen("lobster", "Science")); - System.out.println("Input: lobster , Raffles Hotel Suite ## OutPut: " + database.searchFoodByNameByCanteen("lobster", "Raffles Hotel Suite")); - } - catch (NoSuchElementException e) { + System.out.println("Input: Fried , Science ## OutPut: " + + database.searchFoodByNameByCanteen("Fried", "Science")); + System.out.println("Input: Chicken , Science ## OutPut: " + + database.searchFoodByNameByCanteen("Chicken", "Science")); + System.out.println("Input: lobster , Science ## OutPut: " + + database.searchFoodByNameByCanteen("lobster", "Science")); + System.out.println("Input: lobster , Raffles Hotel Suite ## OutPut: " + + database.searchFoodByNameByCanteen("lobster", "Raffles Hotel Suite")); + } catch (NoSuchElementException e) { System.out.println("There is either no such canteen or no such food in that canteen!" + e); } diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java index 1168a32770..97b646a032 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -2,12 +2,11 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; class FoodTest { private Food testFood; - public static void main(String[] args){ + public static void main(String[] args) { Food food = new Food("Kobe Beef", 480,50,40,30); System.out.println(food); } From 55f2117f10d1739742364196615a430e27d9bc3d Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 13 Oct 2020 21:17:05 +0800 Subject: [PATCH 072/271] add documentation for food class --- src/main/java/seedu/duke/food/Food.java | 11 +++++++++++ src/test/java/seedu/duke/food/FoodTest.java | 6 ++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index c1e03882ce..1dd650f493 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -1,5 +1,6 @@ package seedu.duke.food; + public class Food { private final String name; private final int calorie; @@ -7,6 +8,16 @@ public class Food { private final int protein; private final int fats; + /** + * Constructor of the Food class + * Store information regarding a food item: name, number of calories in kcal, amount of carbohydrate in grams, + * amount of protein in grams, amount of fats in grams. + * @param name name of food e.g. chicken rice + * @param calorie number of calories e.g. 480 kcal + * @param carbohydrate amount of carbohydrates e.g. 40 grams + * @param protein amount of protein e.g. 20 grams + * @param fats amount of fats e.g. 20 grams + */ public Food(String name, int calorie, int carbohydrate, int protein, int fats) { this.name = name; this.calorie = calorie; diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java index 7a45d44cd0..79d6e73eeb 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -6,19 +6,17 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; - class FoodTest { private Food testFood; @BeforeEach - public void setUp(){ + public void setUp() { testFood = new Food("Kobe Beef", 480,50,40,30); } @Test - public void footTest(){ + public void footTest() { assertEquals(testFood.getCalorie(), 480); assertEquals(testFood.getCarbohydrate(), 50); assertEquals(testFood.getProtein(), 40); From e73dbe8950c7c106fe6b78bdaf9d115650987576 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 13 Oct 2020 22:27:16 +0800 Subject: [PATCH 073/271] swap order of assertEquals --- src/test/java/seedu/duke/food/FoodTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java index 79d6e73eeb..8734c23d75 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -17,9 +17,9 @@ public void setUp() { @Test public void footTest() { - assertEquals(testFood.getCalorie(), 480); - assertEquals(testFood.getCarbohydrate(), 50); - assertEquals(testFood.getProtein(), 40); - assertEquals(testFood.getFats(),30); + assertEquals(480, testFood.getCalorie()); + assertEquals(50, testFood.getCarbohydrate()); + assertEquals(40, testFood.getProtein()); + assertEquals(30, testFood.getFats()); } } \ No newline at end of file From 57c5d39fb98b644d3d76301a70a9ca023067df90 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 13 Oct 2020 22:39:53 +0800 Subject: [PATCH 074/271] replace constructor java doc with class java doc --- src/main/java/seedu/duke/food/Food.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 1dd650f493..d4d6050cb8 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -1,6 +1,10 @@ package seedu.duke.food; - +/** + * Constructor of the Food class + * Store information regarding a food item: name, number of calories in kcal, amount of carbohydrate in grams, + * amount of protein in grams, amount of fats in grams. + */ public class Food { private final String name; private final int calorie; @@ -8,16 +12,7 @@ public class Food { private final int protein; private final int fats; - /** - * Constructor of the Food class - * Store information regarding a food item: name, number of calories in kcal, amount of carbohydrate in grams, - * amount of protein in grams, amount of fats in grams. - * @param name name of food e.g. chicken rice - * @param calorie number of calories e.g. 480 kcal - * @param carbohydrate amount of carbohydrates e.g. 40 grams - * @param protein amount of protein e.g. 20 grams - * @param fats amount of fats e.g. 20 grams - */ + public Food(String name, int calorie, int carbohydrate, int protein, int fats) { this.name = name; this.calorie = calorie; From f3c32184dc58a6a460c0bf530056e21623f649d7 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 13 Oct 2020 22:40:01 +0800 Subject: [PATCH 075/271] no message --- src/main/java/seedu/duke/food/Food.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index d4d6050cb8..3142009e4e 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -12,7 +12,6 @@ public class Food { private final int protein; private final int fats; - public Food(String name, int calorie, int carbohydrate, int protein, int fats) { this.name = name; this.calorie = calorie; @@ -46,4 +45,4 @@ public String toString() { return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate + " | fats : " + fats; } -} +} \ No newline at end of file From b1f031d82a862075887d508e7041c47898f77108 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Wed, 14 Oct 2020 23:43:46 +0800 Subject: [PATCH 076/271] v1.0 prototype v1.0 --- src/main/java/seedu/duke/DietBook.java | 12 ++-- src/main/java/seedu/duke/Manager.java | 17 +++-- src/main/java/seedu/duke/Parser.java | 97 ++++++++++++++++++++------ src/main/java/seedu/duke/Ui.java | 2 +- 4 files changed, 97 insertions(+), 31 deletions(-) diff --git a/src/main/java/seedu/duke/DietBook.java b/src/main/java/seedu/duke/DietBook.java index eb63d10d7b..bd3387630f 100644 --- a/src/main/java/seedu/duke/DietBook.java +++ b/src/main/java/seedu/duke/DietBook.java @@ -1,5 +1,8 @@ package seedu.duke; + import java.io.IOException; +import seedu.duke.database.DataBase; +import seedu.duke.list.FoodList; public class DietBook { private FoodList foodList; @@ -9,12 +12,12 @@ public class DietBook { public static boolean isExit = false; /** - * Constructor for new DietBook + * Constructor for new DietBook. */ public DietBook() { ui = new Ui(); foodList = new FoodList(); - dataBase = new Database(); + dataBase = new DataBase(); manager = new Manager(foodList, dataBase); } @@ -31,11 +34,8 @@ public static void main(String[] args) { Parser.parse(userInput, dietBook.manager, dietBook.ui); } catch (DietException e) { dietBook.ui.printErrorMessage(e.getMessage()); - } catch (IOException e) { - dietBook.ui.printErrorMessage(e.getMessage()); - break; } finally { - dietBook.ui.divider(); + System.out.println("__________________"); } } } diff --git a/src/main/java/seedu/duke/Manager.java b/src/main/java/seedu/duke/Manager.java index 27b295470e..31874debdc 100644 --- a/src/main/java/seedu/duke/Manager.java +++ b/src/main/java/seedu/duke/Manager.java @@ -1,7 +1,16 @@ package seedu.duke; +import seedu.duke.list.FoodList; +import seedu.duke.person.ActivityLevel; +import seedu.duke.person.Person; +import seedu.calculator.Calculator; +import seedu.duke.database.DataBase; +import seedu.duke.person.Gender; + + import java.util.Scanner; + public class Manager { private Person person; private FoodList foodList; @@ -12,10 +21,10 @@ public class Manager { public Manager(FoodList foodlist, DataBase dataBase) { this.name = "John Doe"; - this.person = new Person(); + this.person = new Person(this.name, Gender.MALE, 0,0,0,0, ActivityLevel.LOW); this.foodList = foodlist; this.dataBase = dataBase; - this.calculator = new Calculator(0,0,0,0); + this.calculator = new Calculator(foodList.getFoods()); } public String readCommand() { @@ -30,8 +39,8 @@ public Person getPerson() { return this.person; } - public void setPerson(String gender, String age,String height,String actLvl,String orgWeight,String targWeight) { - this.person = new Person(gender, age, height, actLvl, orgWeight, targWeight); + public void setPerson(String name, Gender gender, int age,int height,int orgWeight,int targWeight, ActivityLevel actLvl) { + this.person = new Person(name, gender, age, height, orgWeight, targWeight, actLvl); } public Calculator getCalculator() { diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 7611544b6c..1c3a360f0e 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -1,5 +1,9 @@ package seedu.duke; -import java.util.Arrays; + +import seedu.calculator.Calculator; +import seedu.duke.list.FoodList; +import seedu.duke.person.Gender; +import seedu.duke.person.ActivityLevel; public class Parser { public static final String COMMAND_NAME = "name"; @@ -14,6 +18,7 @@ public class Parser { public static final String COMMAND_USERINFO = "userinfo"; public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; + public static final String[] PARAM_ADD = {"n/","x/","k/","f/","p/","c/"}; /** @@ -48,15 +53,19 @@ private static String getCommandParam(String userInput) throws DietException { return userInput.split(" ")[1]; } } - throw new DietException("☹ Oops! Incorrect nutrient type"); + throw new DietException("☹ Incorrect nutrient type"); case COMMAND_ADD: - if (!userInput.contains("n/") || !userInput.contains("x/") || !userInput.contains("k/")) { - throw new DietException("☹ Oh no... Missing or incorrect add statement"); + for (String param: PARAM_ADD) { + if (!userInput.contains(param)) { + throw new DietException("☹ Missing or incorrect add statement"); + } } return userInput.substring(userInput.indexOf(' ') + 1); case COMMAND_INFO: - if (!Arrays.asList(input).containsAll(Arrays.asList(PARAM_INFO))) { - throw new DietException("☹ Oh no... Missing or incorrect info statement"); + for (String param: PARAM_INFO) { + if (!userInput.contains(param)) { + throw new DietException("☹ Missing or incorrect info statement"); + } } return userInput.substring(userInput.indexOf(' ') + 1); default: @@ -65,6 +74,60 @@ private static String getCommandParam(String userInput) throws DietException { } } + /** + * Processes the parameters for add command of user input and adds a Food object. + * @param userInput user input. + * @param foodList the FoodList object. + * @return name of the food that was added. + * @throws DietException when the user input is of a wrong format. + */ + private static String getProcessedAdd(String userInput, FoodList foodList) throws DietException { + String[] processedParam = getCommandParam(userInput).split(" "); + int portionSize = Integer.parseInt(processedParam[0].substring(processedParam[0].indexOf("/") + 1)); + String foodName = processedParam[1].substring(processedParam[1].indexOf("/") + 1); + int calorie = Integer.parseInt(processedParam[2].substring(processedParam[2].indexOf("/") + 1)); + int carb = Integer.parseInt(processedParam[3].substring(processedParam[3].indexOf("/") + 1)); + int protein = Integer.parseInt(processedParam[4].substring(processedParam[4].indexOf("/") + 1)); + int fat = Integer.parseInt(processedParam[5].substring(processedParam[5].indexOf("/") + 1)); + foodList.addFood(portionSize, foodName, calorie, carb, protein, fat); + return foodName; + } + + /** + * Processes the parameters for info command of user input and updates the Person object. + * @param userInput user input. + * @param manager the manager object. + * @throws DietException when the user input is of a wrong format. + */ + private static void executeProcessedInfo(String userInput, Manager manager) throws DietException { + Gender gender; + ActivityLevel actLvl; + String[] processedParam = getCommandParam(userInput).split(" "); + String processGender = processedParam[0].substring(processedParam[0].indexOf("/") + 1); + if (processGender.equals("M")) { + gender = Gender.MALE; + } else { + gender = Gender.FEMALE; + } + int age = Integer.parseInt(processedParam[1].substring(processedParam[1].indexOf("/") + 1)); + int height = Integer.parseInt(processedParam[2].substring(processedParam[2].indexOf("/") + 1)); + int orgWeight = Integer.parseInt(processedParam[3].substring(processedParam[3].indexOf("/") + 1)); + int tarWeight = Integer.parseInt(processedParam[4].substring(processedParam[4].indexOf("/") + 1)); + String processActLvl = processedParam[5].substring(processedParam[5].indexOf("/") + 1); + if (processActLvl.equals("1")) { + actLvl = ActivityLevel.NONE; + } else if (processActLvl.equals("2")) { + actLvl = ActivityLevel.LOW; + } else if (processActLvl.equals("3")) { + actLvl = ActivityLevel.MEDIUM; + } else if (processActLvl.equals("4")) { + actLvl = ActivityLevel.HIGH; + } else { + actLvl = ActivityLevel.EXTREME; + } + manager.setPerson(manager.getName(), gender, age, height, orgWeight, tarWeight, actLvl); + } + /** * Returns the index after the command of a user input, e.g. delete 3. * @param userInput user input. @@ -94,28 +157,28 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx switch (getCommand(userInput)) { case COMMAND_NAME: manager.setName(getCommandParam(userInput)); - ui.printAskForUserInfoMessage(manager.getName()) + ui.printAskForUserInfoMessage(manager.getName()); return; case COMMAND_EXIT: ui.printExitMessage(manager.getName()); DietBook.isExit = true; return; case COMMAND_LIST: - ui.printFoodList(manager.getFoodList()); + ui.printFoodList(manager.getFoodList().toString()); return; case COMMAND_USERINFO: - ui.printPersonInformation(personInformation); + ui.printPersonInfo(manager.getPerson().toString()); return; case COMMAND_DATA: - manager.getDataBase().printAllData(); + ui.printDatabase(manager.getDataBase().getFoodList()); return; case COMMAND_DELETE: - ui.printDeletedFood(manager.getFoodList().get(getCommandIndex(userInput))); + ui.printDeletedFood(manager.getFoodList().getFoods().get(getCommandIndex(userInput)).toString()); manager.getFoodList().delete(getCommandIndex(userInput)); return; case COMMAND_CLEAR: ui.printClearFoodListMessage(); - manager.getFoodList().clear; + manager.getFoodList().clear(); return; case COMMAND_CALCULATE: if (getCommandParam(userInput).equals("all")) { @@ -132,17 +195,11 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx } return; case COMMAND_INFO: - String[] processedParam = getCommandParam(userInput).split(" "); - String gender = processedParam[0].substring(processedParam[0].indexOf("/") + 1); - String age = processedParam[1].substring(processedParam[1].indexOf("/") + 1); - String height = processedParam[2].substring(processedParam[2].indexOf("/") + 1); - String actLvl = processedParam[3].substring(processedParam[3].indexOf("/") + 1); - String orgWeight = processedParam[4].substring(processedParam[4].indexOf("/") + 1); - String tarWeight = processedParam[5].substring(processedParam[5].indexOf("/") + 1); - manager.setPerson(gender, age, height, actLvl, orgWeight, tarWeight); + executeProcessedInfo(userInput, manager); ui.printTutorialMessage(); return; case COMMAND_ADD: + ui.printNewFood(getProcessedAdd(userInput, manager.getFoodList())); return; default: throw new DietException("☹ There's no such command!"); diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 352e2a978c..25f3a8d909 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -78,7 +78,7 @@ public void printTutorialMessage() { + "listed below." + LINE_SEPARATOR + LINE_SEPARATOR + "To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE" + LINE_SEPARATOR + "To view all food in the database: data" + LINE_SEPARATOR - + "To add you own food: add n/FOOD_NAME x/PORTION_SIZE k/CALORIE [c/CARBOHYDRATE] " + + "To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] " + "[p/PROTEIN] [f/FAT]" + LINE_SEPARATOR + "To view all food in DietBook: list" + LINE_SEPARATOR + "To delete a food from DietBook: delete INDEX" + LINE_SEPARATOR From 240b357b42799a01ca64cd275d59c640c458b5ee Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 15 Oct 2020 00:02:05 +0800 Subject: [PATCH 077/271] checkstyle fix --- src/main/java/seedu/duke/Manager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Manager.java b/src/main/java/seedu/duke/Manager.java index 31874debdc..b7a8c4cd96 100644 --- a/src/main/java/seedu/duke/Manager.java +++ b/src/main/java/seedu/duke/Manager.java @@ -39,7 +39,8 @@ public Person getPerson() { return this.person; } - public void setPerson(String name, Gender gender, int age,int height,int orgWeight,int targWeight, ActivityLevel actLvl) { + public void setPerson(String name, Gender gender, int age,int height,int orgWeight, + int targWeight, ActivityLevel actLvl) { this.person = new Person(name, gender, age, height, orgWeight, targWeight, actLvl); } From e592a470755666a420e11c20c3979f3fc0dc56e1 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 15 Oct 2020 00:10:06 +0800 Subject: [PATCH 078/271] shortened delete case --- src/main/java/seedu/duke/Parser.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 1c3a360f0e..910119f3a2 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -173,8 +173,7 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx ui.printDatabase(manager.getDataBase().getFoodList()); return; case COMMAND_DELETE: - ui.printDeletedFood(manager.getFoodList().getFoods().get(getCommandIndex(userInput)).toString()); - manager.getFoodList().delete(getCommandIndex(userInput)); + ui.printDeletedFood(manager.getFoodList().delete(getCommandIndex(userInput))); return; case COMMAND_CLEAR: ui.printClearFoodListMessage(); From 444a73ec314c218d8ba13244566c0ce7cb80bda9 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 15 Oct 2020 00:14:15 +0800 Subject: [PATCH 079/271] removed index subtraction --- 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 910119f3a2..932c2f8b08 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -141,7 +141,7 @@ private static int getCommandIndex(String userInput) throws DietException { throw new DietException("☹ OOPS!!! Missing index of duke.task!"); } try { - return Integer.parseInt(userInput.split(" ")[1]) - 1; + return Integer.parseInt(userInput.split(" ")[1]); } catch (NumberFormatException e) { throw new DietException("☹ OOPS!!! No integer index detected!"); } From 0f60ed3150097a8054ff718e2f15273ec76827fc Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 15 Oct 2020 00:28:08 +0800 Subject: [PATCH 080/271] added back duke --- src/main/java/seedu/duke/Duke.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/seedu/duke/Duke.java diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java new file mode 100644 index 0000000000..9f8063ee94 --- /dev/null +++ b/src/main/java/seedu/duke/Duke.java @@ -0,0 +1,21 @@ +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()); + } +} \ No newline at end of file From 8e3c91bb07d81713e2ec86a6ec0655f68d2a7881 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 15 Oct 2020 02:11:42 +0800 Subject: [PATCH 081/271] Change main class in build.gradle --- META-INF/MANIFEST.MF | 3 +++ build.gradle | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 META-INF/MANIFEST.MF diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..3d5a2c3351 --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: seedu.duke.DietBook + diff --git a/build.gradle b/build.gradle index c26af4dc9a..0130e89069 100644 --- a/build.gradle +++ b/build.gradle @@ -31,11 +31,11 @@ test { } application { - mainClassName = "seedu.duke.Duke" + mainClassName = "seedu.duke.DietBook" } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "dietbook" archiveClassifier = null } @@ -45,5 +45,5 @@ checkstyle { run{ standardInput = System.in - enableAssertions = true + enableAssertions = false } From 261f0f361f75a36952d001c81ff766e4cc41953b Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 15 Oct 2020 02:15:58 +0800 Subject: [PATCH 082/271] Remove I/O testing --- text-ui-test/EXPECTED.TXT | 8 -------- text-ui-test/input.txt | 1 - 2 files changed, 9 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 892cb6cae7..8b13789179 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,9 +1 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| -What is your name? -Hello James Gosling diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index f6ec2e9f95..e69de29bb2 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1 +0,0 @@ -James Gosling \ No newline at end of file From 09b6f8138c4e41b67ac02bb90ab3d020ef49ca6e Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 15 Oct 2020 02:20:03 +0800 Subject: [PATCH 083/271] Update Expected.TXT with welcome message --- text-ui-test/EXPECTED.TXT | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 8b13789179..c55d70517c 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1 +1,13 @@ +________________________________________________________________________________________________________________________________________________ + _______ __ ______ ________ _______ ______ ______ __ __ +| __ \| | ___|__ __| __ \ / __ \ / __ \| | / / +| | | | | |___ | | | |__| | | | | | | | |/ / +| | | | | ___| | | | __ <| | | | | | | / +| |__| | | |___ | | | |__| | |__| | | | | |\ \ +|_______/|__|______| |__| |_______/ \______/ \______/|__| \__\ +Hello! Welcome to DietBook! +I am Diet, your guide to using DietBook. What is your name? +Please input in the following format: + name YOUR_NAME +________________________________________________________________________________________________________________________________________________ From 3b22af22444f6b9da49d2163e944b8c7074d1521 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 15 Oct 2020 02:23:38 +0800 Subject: [PATCH 084/271] Add ending divider --- text-ui-test/EXPECTED.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index c55d70517c..68c874c5d9 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -11,3 +11,4 @@ I am Diet, your guide to using DietBook. What is your name? Please input in the following format: name YOUR_NAME ________________________________________________________________________________________________________________________________________________ +__________________ \ No newline at end of file From 7ad903c4e216655ed7398db32a76cfa4036209a5 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 15 Oct 2020 02:26:24 +0800 Subject: [PATCH 085/271] Add new line at the end of the file --- text-ui-test/EXPECTED.TXT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 68c874c5d9..f47f7db415 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -11,4 +11,4 @@ I am Diet, your guide to using DietBook. What is your name? Please input in the following format: name YOUR_NAME ________________________________________________________________________________________________________________________________________________ -__________________ \ No newline at end of file +__________________ From 17ab7bdd54a9b4f86402ab2af9302752e0951c69 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 15 Oct 2020 02:33:30 +0800 Subject: [PATCH 086/271] data printing --- src/main/java/seedu/duke/DietBook.java | 3 ++- src/main/java/seedu/duke/Parser.java | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/DietBook.java b/src/main/java/seedu/duke/DietBook.java index bd3387630f..b7003f2753 100644 --- a/src/main/java/seedu/duke/DietBook.java +++ b/src/main/java/seedu/duke/DietBook.java @@ -1,5 +1,6 @@ package seedu.duke; +import java.io.FileNotFoundException; import java.io.IOException; import seedu.duke.database.DataBase; import seedu.duke.list.FoodList; @@ -24,7 +25,7 @@ public DietBook() { /** * Main method to run the program. */ - public static void main(String[] args) { + public static void main(String[] args) throws FileNotFoundException { DietBook dietBook = new DietBook(); dietBook.ui.printWelcomeMessage(); diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 932c2f8b08..2539ef863b 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -5,6 +5,8 @@ import seedu.duke.person.Gender; import seedu.duke.person.ActivityLevel; +import java.io.FileNotFoundException; + public class Parser { public static final String COMMAND_NAME = "name"; public static final String COMMAND_LIST = "list"; @@ -152,7 +154,7 @@ private static int getCommandIndex(String userInput) throws DietException { * @param userInput user input. * @throws DietException when the program does not recognize the command given. */ - public static void parse(String userInput, Manager manager, Ui ui) throws DietException { + public static void parse(String userInput, Manager manager, Ui ui) throws DietException, FileNotFoundException { Calculator calculator = manager.getCalculator(); switch (getCommand(userInput)) { case COMMAND_NAME: @@ -170,6 +172,7 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx ui.printPersonInfo(manager.getPerson().toString()); return; case COMMAND_DATA: + manager.getDataBase().init(); ui.printDatabase(manager.getDataBase().getFoodList()); return; case COMMAND_DELETE: From dd57dd644cf398e036b6dc1b92468cb18c7b82cc Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 15 Oct 2020 10:47:50 +0800 Subject: [PATCH 087/271] fixed bugs for data, calculator --- build.gradle | 6 +++--- src/main/java/META-INF/MANIFEST.MF | 3 +++ src/main/java/seedu/duke/DietBook.java | 23 ++++++++++++----------- src/main/java/seedu/duke/Duke.java | 21 --------------------- src/main/java/seedu/duke/Manager.java | 4 ++++ src/main/java/seedu/duke/Parser.java | 12 ++++++++---- 6 files changed, 30 insertions(+), 39 deletions(-) create mode 100644 src/main/java/META-INF/MANIFEST.MF delete mode 100644 src/main/java/seedu/duke/Duke.java diff --git a/build.gradle b/build.gradle index c26af4dc9a..0130e89069 100644 --- a/build.gradle +++ b/build.gradle @@ -31,11 +31,11 @@ test { } application { - mainClassName = "seedu.duke.Duke" + mainClassName = "seedu.duke.DietBook" } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "dietbook" archiveClassifier = null } @@ -45,5 +45,5 @@ checkstyle { run{ standardInput = System.in - enableAssertions = true + enableAssertions = false } diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..3d5a2c3351 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: seedu.duke.DietBook + diff --git a/src/main/java/seedu/duke/DietBook.java b/src/main/java/seedu/duke/DietBook.java index bd3387630f..63524b73ca 100644 --- a/src/main/java/seedu/duke/DietBook.java +++ b/src/main/java/seedu/duke/DietBook.java @@ -1,5 +1,6 @@ package seedu.duke; +import java.io.FileNotFoundException; import java.io.IOException; import seedu.duke.database.DataBase; import seedu.duke.list.FoodList; @@ -11,20 +12,10 @@ public class DietBook { private DataBase dataBase; public static boolean isExit = false; - /** - * Constructor for new DietBook. - */ - public DietBook() { - ui = new Ui(); - foodList = new FoodList(); - dataBase = new DataBase(); - manager = new Manager(foodList, dataBase); - } - /** * Main method to run the program. */ - public static void main(String[] args) { + public static void main(String[] args) throws FileNotFoundException { DietBook dietBook = new DietBook(); dietBook.ui.printWelcomeMessage(); @@ -39,4 +30,14 @@ public static void main(String[] args) { } } } + + /** + * Constructor for new DietBook. + */ + public DietBook() { + ui = new Ui(); + foodList = new FoodList(); + dataBase = new DataBase(); + manager = new Manager(foodList, dataBase); + } } diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java deleted file mode 100644 index 9f8063ee94..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()); - } -} \ No newline at end of file diff --git a/src/main/java/seedu/duke/Manager.java b/src/main/java/seedu/duke/Manager.java index b7a8c4cd96..3b755c49ff 100644 --- a/src/main/java/seedu/duke/Manager.java +++ b/src/main/java/seedu/duke/Manager.java @@ -48,6 +48,10 @@ public Calculator getCalculator() { return this.calculator; } + public void setCalculator() { + this.calculator = new Calculator(foodList.getFoods()); + } + public DataBase getDataBase() { return this.dataBase; } diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 932c2f8b08..033fafb972 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -5,6 +5,8 @@ import seedu.duke.person.Gender; import seedu.duke.person.ActivityLevel; +import java.io.FileNotFoundException; + public class Parser { public static final String COMMAND_NAME = "name"; public static final String COMMAND_LIST = "list"; @@ -152,7 +154,7 @@ private static int getCommandIndex(String userInput) throws DietException { * @param userInput user input. * @throws DietException when the program does not recognize the command given. */ - public static void parse(String userInput, Manager manager, Ui ui) throws DietException { + public static void parse(String userInput, Manager manager, Ui ui) throws DietException, FileNotFoundException { Calculator calculator = manager.getCalculator(); switch (getCommand(userInput)) { case COMMAND_NAME: @@ -170,6 +172,7 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx ui.printPersonInfo(manager.getPerson().toString()); return; case COMMAND_DATA: + manager.getDataBase().init(); ui.printDatabase(manager.getDataBase().getFoodList()); return; case COMMAND_DELETE: @@ -180,14 +183,15 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx manager.getFoodList().clear(); return; case COMMAND_CALCULATE: + manager.setCalculator(); if (getCommandParam(userInput).equals("all")) { ui.printAllNutrientIntake(calculator.calculateCalorie(), calculator.calculateCarb(), calculator.calculateProtein(), calculator.calculateFat()); - } else if (getCommandParam(userInput).equals("calorie")) { + } else if (getCommandParam(userInput).contains("calorie")) { ui.printCalorieIntake(calculator.calculateCalorie()); - } else if (getCommandParam(userInput).equals("carbohydrate")) { + } else if (getCommandParam(userInput).contains("carbohydrate")) { ui.printCarbohydrateIntake(calculator.calculateCarb()); - } else if (getCommandParam(userInput).equals("protein")) { + } else if (getCommandParam(userInput).contains("protein")) { ui.printProteinIntake(calculator.calculateProtein()); } else { ui.printFatIntake(calculator.calculateFat()); From f698b2e5c5a009565fbc3f8fad66d15eaf9c8d44 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 15 Oct 2020 10:58:33 +0800 Subject: [PATCH 088/271] fixed calculator --- src/main/java/seedu/duke/Manager.java | 4 ++++ src/main/java/seedu/duke/Parser.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/seedu/duke/Manager.java b/src/main/java/seedu/duke/Manager.java index b7a8c4cd96..3b755c49ff 100644 --- a/src/main/java/seedu/duke/Manager.java +++ b/src/main/java/seedu/duke/Manager.java @@ -48,6 +48,10 @@ public Calculator getCalculator() { return this.calculator; } + public void setCalculator() { + this.calculator = new Calculator(foodList.getFoods()); + } + public DataBase getDataBase() { return this.dataBase; } diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 2539ef863b..c0e32315e0 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -177,6 +177,7 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx return; case COMMAND_DELETE: ui.printDeletedFood(manager.getFoodList().delete(getCommandIndex(userInput))); + manager.setCalculator(); return; case COMMAND_CLEAR: ui.printClearFoodListMessage(); @@ -202,6 +203,7 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx return; case COMMAND_ADD: ui.printNewFood(getProcessedAdd(userInput, manager.getFoodList())); + manager.setCalculator(); return; default: throw new DietException("☹ There's no such command!"); From 69358ede48900e9bbfa7a645e822662ff438385a Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Sun, 18 Oct 2020 17:06:52 +0800 Subject: [PATCH 089/271] change FilePathing to ClassPathing Data txt file referenced by DataBase now put in its resource directory as per current Gradle specifications (main/resource). ClassPathing used to access this data in init method. Some minor changes to style and removal of filepathing related exceptions and imports. --- .../java/seedu/duke/database/DataBase.java | 35 +++++++++++-------- .../duke/database => resources}/data.txt | 0 .../seedu/duke/database/DataBaseTest.java | 9 ++--- 3 files changed, 23 insertions(+), 21 deletions(-) rename src/main/{java/seedu/duke/database => resources}/data.txt (100%) diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/duke/database/DataBase.java index 74672a54ef..687d6528a6 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/duke/database/DataBase.java @@ -3,14 +3,12 @@ import seedu.duke.food.Food; -import java.io.File; -import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; -import java.util.NoSuchElementException; import java.util.Scanner; import java.util.stream.Collectors; import java.util.stream.Stream; +import java.io.InputStream; public class DataBase { private static final String START_SYMBOL = "&%START"; @@ -19,23 +17,27 @@ public class DataBase { private static final String DATA_FILE_SEPERATOR = "\\|"; - private static final String rootDirectory = System.getProperty("user.dir"); - private static final String dataFileFolder = "src" + File.separator + "main" + File.separator - + "java" + File.separator + "seedu" + File.separator + "duke" + File.separator + "database"; private final List canteenList; + /** + * Instantiate an empty Database object. + */ public DataBase() { this.canteenList = new ArrayList<>(); } /** - * Reads a file from the data base and puts it into the DataBase object. + * Loads and parses the resource main/resource/data.txt + * This data is used to build the internal canteenList. */ - public void init() throws FileNotFoundException { - String fileFolder = rootDirectory + File.separator + dataFileFolder; - File dataFile = new File(fileFolder + File.separator + "data.txt"); - Scanner fileReader = new Scanner(dataFile); + public void init() { + + InputStream dataStream = DataBase.class.getResourceAsStream("/data.txt"); + assert (dataStream != null) : "Could not load resource"; + + Scanner fileReader = new Scanner(dataStream); + String fileLine; boolean start = false; while (fileReader.hasNext()) { @@ -91,8 +93,8 @@ private Store fillStore(String name, Scanner fileSegment) { String fileLine = fileSegment.nextLine(); String[] fileData = fileLine.split(DATA_FILE_SEPERATOR); while (!(fileLine.equals(UP_SYMBOL))) { - food = new Food(fileData[0], Integer.parseInt(fileData[1]),Integer.parseInt(fileData[2]), - Integer.parseInt(fileData[3]),Integer.parseInt(fileData[4])); + food = new Food(fileData[0], Integer.parseInt(fileData[1]), Integer.parseInt(fileData[2]), + Integer.parseInt(fileData[3]), Integer.parseInt(fileData[4])); store.addFood(food); fileLine = fileSegment.nextLine(); fileData = fileLine.split(DATA_FILE_SEPERATOR); @@ -235,7 +237,7 @@ public Stream searchAllFoodBelowCalorie(int calorie) { * Returns all food within the calorie range. * * @param minCalorie minimum calories - * @param maxCalorie maxinum calories + * @param maxCalorie maximum calories * @return food stream */ public Stream searchAllFoodInCalorieRange(int minCalorie, int maxCalorie) { @@ -252,7 +254,10 @@ public Stream foodStream() { .flatMap(x -> x.getStoreList().stream()) .flatMap(x -> x.getFoodList().stream()); } - + + /** + * Provide a list of all food in the data base. + */ public List getFoodList() { return foodStream().collect(Collectors.toList()); } diff --git a/src/main/java/seedu/duke/database/data.txt b/src/main/resources/data.txt similarity index 100% rename from src/main/java/seedu/duke/database/data.txt rename to src/main/resources/data.txt diff --git a/src/test/java/seedu/duke/database/DataBaseTest.java b/src/test/java/seedu/duke/database/DataBaseTest.java index 116b4192bc..004a1d0a70 100644 --- a/src/test/java/seedu/duke/database/DataBaseTest.java +++ b/src/test/java/seedu/duke/database/DataBaseTest.java @@ -1,17 +1,14 @@ package seedu.duke.database; -import java.io.FileNotFoundException; import java.util.NoSuchElementException; class DataBaseTest { public static void main(String[] args) { DataBase database = new DataBase(); - try { - database.init(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } + + database.init(); + // ----- Print everything in the data base ----- database.printAllData(); From 993af58c76f4e32a6b151f20ac0311a1f89fb875 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 19 Oct 2020 12:17:46 +0800 Subject: [PATCH 090/271] Update Food.java Change `getFats()` to its singular `getFat()` for consistency with other methods. --- src/main/java/seedu/duke/food/Food.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/duke/food/Food.java index 9ea158bf5f..619062543a 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/duke/food/Food.java @@ -21,7 +21,7 @@ public Food(String name, int calorie, int carbohydrate, int protein, int fats) { this.fats = fats; } - public int getFats() { + public int getFat() { return fats; } From a55ea8fe39fef46e0e3895ad4ec3ecf8960234c8 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 19 Oct 2020 13:07:28 +0800 Subject: [PATCH 091/271] Update Tests Update tests to use getFat() instead --- src/main/java/seedu/calculator/Calculator.java | 2 +- src/test/java/seedu/duke/food/FoodTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/calculator/Calculator.java b/src/main/java/seedu/calculator/Calculator.java index e50cf15f43..dfbd8a221c 100644 --- a/src/main/java/seedu/calculator/Calculator.java +++ b/src/main/java/seedu/calculator/Calculator.java @@ -25,7 +25,7 @@ public Calculator(ArrayList foodList) { totalCalorie += foodList.get(i).getCalorie(); totalCarbohydrate += foodList.get(i).getCarbohydrate(); totalProtein += foodList.get(i).getProtein(); - totalFat += foodList.get(i).getFats(); + totalFat += foodList.get(i).getFat(); } } diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/duke/food/FoodTest.java index 8c866c2f89..fd7b5866b8 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/duke/food/FoodTest.java @@ -21,6 +21,6 @@ public void footTest() { assertEquals(480, testFood.getCalorie()); assertEquals(50, testFood.getCarbohydrate()); assertEquals(40, testFood.getProtein()); - assertEquals(30, testFood.getFats()); + assertEquals(30, testFood.getFat()); } } \ No newline at end of file From 4ff6f9a2e8c888f47a73fb0f06a09ffec23968e4 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 19 Oct 2020 13:09:11 +0800 Subject: [PATCH 092/271] Update .gitignore Added ignores for IDE agnosticism. --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index f69985ef1f..12141ee20e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ /out/ /*.iml +# VSCode files +/.vscode/ + # Gradle build files /.gradle/ /build/ @@ -15,3 +18,6 @@ bin/ /text-ui-test/ACTUAL.txt text-ui-test/EXPECTED-UNIX.TXT + +# IDE specific files +.project From f03597c66060da81ed0cf8ba965600566eae7b06 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 19 Oct 2020 13:11:06 +0800 Subject: [PATCH 093/271] Update FoodList: FP & Portion sizing - FoodListManager uses FP to be more DRY - Can get Food with nutrition values scaled according to portion size --- src/main/java/seedu/duke/list/FoodList.java | 12 ++- .../java/seedu/duke/list/FoodListManager.java | 81 +++++++++++++++---- .../seedu/duke/{ => list}/FoodListTest.java | 20 ++++- 3 files changed, 95 insertions(+), 18 deletions(-) rename src/test/java/seedu/duke/{ => list}/FoodListTest.java (56%) diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java index 92f92c47e3..4f949d8adc 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -54,7 +54,10 @@ public String addFood(int portionSize, String name) throws FoodNotFoundException throw new FoodNotFoundException(); } - + /** + * Deletes the the entry of the list at the provided index. + * index starts from 1 (not 0). i.e. is User's understanding of index. + */ public String delete(int index) throws IndexOutOfBoundsException { try { return FoodListManager.deleteEntry(foodEntries, index).toString(); @@ -77,6 +80,13 @@ public ArrayList getFoods() { return FoodListManager.listToFoods(foodEntries); } + /** + * Obtain list of food objects in FoodList, scaled to portion size. + */ + public ArrayList getPortionedFoods() { + return FoodListManager.listToPortionedFoods(foodEntries); + } + @Override public String toString() { return FoodListManager.listToString(foodEntries); diff --git a/src/main/java/seedu/duke/list/FoodListManager.java b/src/main/java/seedu/duke/list/FoodListManager.java index 7165cae639..cc5d8e511c 100644 --- a/src/main/java/seedu/duke/list/FoodListManager.java +++ b/src/main/java/seedu/duke/list/FoodListManager.java @@ -2,6 +2,9 @@ import seedu.duke.food.Food; import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.function.Consumer; /** * Class with static methods to execute "complex commands" on FoodList. @@ -13,37 +16,83 @@ public class FoodListManager { /** * Internal helper method to convert the items in the arraylist into enumed strings. - * Primarily used to obtain String representations of the list. + * Primarily used to obtain String representations of the entire list. */ protected static String listToString(ArrayList list) { String listString = ""; for (int i = 1; i <= list.size(); i++) { FoodEntry entry = list.get(i - 1); - listString += i + ". " + listString += " " + i + ". " + entry.toString() + "\n"; } return listString; } - /** - * Similar to listToString. - * Extracts only the Food component from FoodEntries. - */ - protected static ArrayList listToFoods(ArrayList list) { - ArrayList foods = new ArrayList<>(); - list.forEach(x -> { - foods.add(x.getFood()); - }); - return foods; - } - - protected static Food deleteEntry(ArrayList list, int index) throws IndexOutOfBoundsException { + protected static FoodEntry deleteEntry(List list, int index) throws IndexOutOfBoundsException { int indexToDelete = index - 1; try { - return list.remove(indexToDelete).getFood(); + return list.remove(indexToDelete); } catch (IndexOutOfBoundsException e) { throw e; } } + + /** + * Method to obtain list of foodentries in string rep. + * @param list The foodList arrayList + * @return List of foodEntries in their String rep. + */ + protected static List listToStrings(List list) { + Function function = x -> x.toString(); + return applyFunctionToList(list, function); + } + + /** + * Extracts the list of foods from the foodentries list. + * @param list list of foodEntries + * @return arraylist of Food objects. + */ + protected static ArrayList listToFoods(List list) { + Function function = x -> x.getFood(); + return applyFunctionToList(list, function); + } + + /** + * Creates a list of foods that have their nutritional values scaled by portion size. + * This is based on the FoodEntries in the list provided. + * @param list list of FoodEntries + * @return arraylist of Food objects + */ + protected static ArrayList listToPortionedFoods(List list) { + Function function = x -> { + Food baseFood = x.getFood(); + /** Explicitly getting return type of getPortionSize() is avoided. + * Future updates might see the type change from int to float + * return of getPortionSize() essentially treated as a "multipliable" + */ + return new Food(baseFood.getName(), + baseFood.getCalorie() * x.getPortionSize(), + baseFood.getCarbohydrate() * x.getPortionSize(), + baseFood.getProtein() * x.getPortionSize(), + baseFood.getFat() * x.getPortionSize()); + }; + return applyFunctionToList(list, function); + } + + /** + * Generic method to map a function across a list. + * @param list list to operate on + * @param function function to be mapped across list + * @return list of mapped items under provided function + */ + protected static ArrayList applyFunctionToList(List list, Function function) { + ArrayList appliedList = new ArrayList<>(); + Consumer addResultToAppliedList = x -> appliedList.add(function.apply(x)); + list.forEach(addResultToAppliedList); + return appliedList; + } + } + +// create a functional interface for the function instead: diff --git a/src/test/java/seedu/duke/FoodListTest.java b/src/test/java/seedu/duke/list/FoodListTest.java similarity index 56% rename from src/test/java/seedu/duke/FoodListTest.java rename to src/test/java/seedu/duke/list/FoodListTest.java index 96b31d9647..80df0a28d0 100644 --- a/src/test/java/seedu/duke/FoodListTest.java +++ b/src/test/java/seedu/duke/list/FoodListTest.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.duke.list; import seedu.duke.list.FoodList; import seedu.duke.food.Food; @@ -6,14 +6,32 @@ class FoodListTest { + + private FoodList list; + + @BeforeEAch + protected void setUp() { + this.list = new FoodList(); + + Food food = new Food("Kobe Beef", 480,50,40,30); + foodList.addFood(3, food); + foodList.addFood(2, "Sashimi", 100, 0, 30, 10); + + } + public static void main(String[] args) { + Food food = new Food("Kobe Beef", 480,50,40,30); FoodList foodList = new FoodList(); System.out.println(foodList.addFood(3, food)); System.out.println(foodList.addFood(2, "Sashimi", 100, 0, 30, 10)); System.out.println(foodList); + System.out.println(foodList.getPortionedFoods()); + System.out.println(foodList.delete(1)); System.out.println(foodList); + System.out.println(foodList.getFoods()); + } } \ No newline at end of file From 95976c74ebca8da128477cde420f0cbfa1236a79 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 19 Oct 2020 22:27:51 +0800 Subject: [PATCH 094/271] add Junit tests - Tests for key advanced features (deletion and list mapping). - add /.settings (vscode eclipse-gradle specfic) to gitignore --- .gitignore | 1 + .../java/seedu/duke/list/FoodListTest.java | 46 +++++++++++-------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 12141ee20e..d004289a1f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ text-ui-test/EXPECTED-UNIX.TXT # IDE specific files .project +/.settings/ diff --git a/src/test/java/seedu/duke/list/FoodListTest.java b/src/test/java/seedu/duke/list/FoodListTest.java index 80df0a28d0..3fed7febda 100644 --- a/src/test/java/seedu/duke/list/FoodListTest.java +++ b/src/test/java/seedu/duke/list/FoodListTest.java @@ -1,37 +1,47 @@ package seedu.duke.list; -import seedu.duke.list.FoodList; -import seedu.duke.food.Food; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import seedu.duke.food.Food; class FoodListTest { private FoodList list; - @BeforeEAch + @BeforeEach protected void setUp() { this.list = new FoodList(); Food food = new Food("Kobe Beef", 480,50,40,30); - foodList.addFood(3, food); - foodList.addFood(2, "Sashimi", 100, 0, 30, 10); + list.addFood(3, food); + list.addFood(2, "Sashimi", 100, 0, 30, 10); } - public static void main(String[] args) { + /** + * getPortionedList() should return list of food with scaled up nutritional values. + * getFoods() should return a list of food (Not food entries). + * Essentially 2 tests in 1. + */ + @Test + void foodPortionScaling_standardList_scaledFoodList() { + FoodList testList = new FoodList(); + + Food food = new Food("Kobe Beef", 480 * 3 ,50 * 3, 40 * 3, 30 * 3); + testList.addFood(1, food); + testList.addFood(1, "Sashimi", 200, 0, 60, 20); + assertEquals(testList.getFoods().toString(), list.getPortionedFoods().toString()); + } + + @Test + void deleteItemTest() { Food food = new Food("Kobe Beef", 480,50,40,30); - FoodList foodList = new FoodList(); - - System.out.println(foodList.addFood(3, food)); - System.out.println(foodList.addFood(2, "Sashimi", 100, 0, 30, 10)); - System.out.println(foodList); - System.out.println(foodList.getPortionedFoods()); - - System.out.println(foodList.delete(1)); - System.out.println(foodList); - System.out.println(foodList.getFoods()); - + FoodEntry entry = new FoodEntry(3, food); + assertEquals(list.delete(1), entry.toString()); } -} \ No newline at end of file + +} From 05f0a6ea29f4b2b41f8fd0807d3977c158d39f78 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 19 Oct 2020 22:41:22 +0800 Subject: [PATCH 095/271] javadocs --- src/main/java/seedu/duke/list/FoodList.java | 11 ++++++++++- src/test/java/seedu/duke/list/FoodListTest.java | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java index 4f949d8adc..8dc4fa3d40 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -12,6 +12,9 @@ public class FoodList { private ArrayList foodEntries; + /** + * Default constructor that instantiates FoodList with an empty foodentry arraylist. + */ public FoodList() { this.foodEntries = new ArrayList<>(); } @@ -33,7 +36,10 @@ public String addFood(int portionSize, Food food) { foodEntries.add(toAdd); return toAdd.toString(); } - + + /** + * Default add method that adds a food entry using the food details and portion size. + */ public String addFood(int portionSize, String name, int calorie, int carbohydrate, int protein, int fat) { FoodEntry toAdd = new FoodEntry(portionSize, name, calorie, carbohydrate, protein, fat); @@ -66,6 +72,9 @@ public String delete(int index) throws IndexOutOfBoundsException { } } + /** + * Discards previous foodEntry list and creates a new one. + */ public boolean clear() { this.foodEntries = new ArrayList<>(); return true; diff --git a/src/test/java/seedu/duke/list/FoodListTest.java b/src/test/java/seedu/duke/list/FoodListTest.java index 3fed7febda..99779fe16e 100644 --- a/src/test/java/seedu/duke/list/FoodListTest.java +++ b/src/test/java/seedu/duke/list/FoodListTest.java @@ -30,7 +30,7 @@ protected void setUp() { void foodPortionScaling_standardList_scaledFoodList() { FoodList testList = new FoodList(); - Food food = new Food("Kobe Beef", 480 * 3 ,50 * 3, 40 * 3, 30 * 3); + Food food = new Food("Kobe Beef", 480 * 3, 50 * 3, 40 * 3, 30 * 3); testList.addFood(1, food); testList.addFood(1, "Sashimi", 200, 0, 60, 20); From 70580ae7cdc46444ca165bfb3ebb90cb4507d624 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 19 Oct 2020 23:30:40 +0800 Subject: [PATCH 096/271] add assertions and docs --- src/main/java/seedu/duke/list/FoodEntry.java | 19 +++++++++++++++++-- src/main/java/seedu/duke/list/FoodList.java | 5 ++++- .../java/seedu/duke/list/FoodListManager.java | 3 ++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/duke/list/FoodEntry.java b/src/main/java/seedu/duke/list/FoodEntry.java index 7aa6f115e6..cd16f35cfe 100644 --- a/src/main/java/seedu/duke/list/FoodEntry.java +++ b/src/main/java/seedu/duke/list/FoodEntry.java @@ -7,24 +7,39 @@ * Data class to store both serving sizes and a food object as a single object. */ public class FoodEntry { - private int portionSize; - private Food food; + private final int portionSize; + private final Food food; + /** + * Convenience constructor mainly for testing. + * In the future, this is expected be the constructor for adding entries using food from the database. + */ public FoodEntry(int portionSize, Food food) { + assert (portionSize > 0) : "Non-positive, invalid portion size not caught."; this.portionSize = portionSize; this.food = food; } + /** + * Default constructor. Creates new food object as part of entry. + */ public FoodEntry(int portionSize, String name, int calorie, int carbohydrate, int protein, int fat) { + assert (portionSize > 0) : "Non-positive, invalid portion size not caught."; this.portionSize = portionSize; this.food = new Food(name, calorie, carbohydrate, protein, fat); } + /** + * Getter method for the Food object. + */ public Food getFood() { return food; } + /** + * Getter method for the portionSize object. + */ public int getPortionSize() { return portionSize; } diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java index 8dc4fa3d40..a334418f87 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -19,6 +19,9 @@ public FoodList() { this.foodEntries = new ArrayList<>(); } + /** + * Convenience constructor mainly for testing purposes. + */ protected FoodList(ArrayList entries) { this.foodEntries = entries; } @@ -36,7 +39,7 @@ public String addFood(int portionSize, Food food) { foodEntries.add(toAdd); return toAdd.toString(); } - + /** * Default add method that adds a food entry using the food details and portion size. */ diff --git a/src/main/java/seedu/duke/list/FoodListManager.java b/src/main/java/seedu/duke/list/FoodListManager.java index cc5d8e511c..45b9a5373f 100644 --- a/src/main/java/seedu/duke/list/FoodListManager.java +++ b/src/main/java/seedu/duke/list/FoodListManager.java @@ -30,6 +30,7 @@ protected static String listToString(ArrayList list) { } protected static FoodEntry deleteEntry(List list, int index) throws IndexOutOfBoundsException { + assert (index > 0) : "Invalid index (negative/zero) was given."; int indexToDelete = index - 1; try { return list.remove(indexToDelete); @@ -95,4 +96,4 @@ protected static ArrayList applyFunctionToList(List list, Function< } -// create a functional interface for the function instead: +// Potential future work: create a functional interface for the functions instead: From 80460038590b2cbef0dad5489faf396db3193174 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 20 Oct 2020 20:46:43 +0800 Subject: [PATCH 097/271] Rename duke package to dietbook --- build.gradle | 2 +- src/main/java/seedu/calculator/Calculator.java | 2 +- src/main/java/seedu/{duke => dietbook}/DietBook.java | 6 +++--- .../java/seedu/{duke => dietbook}/DietException.java | 2 +- src/main/java/seedu/{duke => dietbook}/Manager.java | 12 ++++++------ src/main/java/seedu/{duke => dietbook}/Parser.java | 8 ++++---- src/main/java/seedu/{duke => dietbook}/Ui.java | 6 +++--- .../seedu/{duke => dietbook}/database/Canteen.java | 2 +- .../seedu/{duke => dietbook}/database/DataBase.java | 4 ++-- .../seedu/{duke => dietbook}/database/Store.java | 4 ++-- .../java/seedu/{duke => dietbook}/food/Food.java | 2 +- .../seedu/{duke => dietbook}/list/FoodEntry.java | 4 ++-- .../java/seedu/{duke => dietbook}/list/FoodList.java | 4 ++-- .../{duke => dietbook}/list/FoodListManager.java | 4 ++-- .../list/FoodNotFoundException.java | 2 +- .../{duke => dietbook}/person/ActivityLevel.java | 2 +- .../java/seedu/{duke => dietbook}/person/Gender.java | 2 +- .../java/seedu/{duke => dietbook}/person/Person.java | 2 +- src/test/java/seedu/calculator/CalculatorTest.java | 2 +- src/test/java/seedu/{duke => dietbook}/DukeTest.java | 2 +- .../java/seedu/{duke => dietbook}/FoodListTest.java | 6 +++--- .../{duke => dietbook}/database/DataBaseTest.java | 2 +- .../java/seedu/{duke => dietbook}/food/FoodTest.java | 5 ++--- .../seedu/{duke => dietbook}/person/PersonTest.java | 2 +- 24 files changed, 44 insertions(+), 45 deletions(-) rename src/main/java/seedu/{duke => dietbook}/DietBook.java (91%) rename src/main/java/seedu/{duke => dietbook}/DietException.java (89%) rename src/main/java/seedu/{duke => dietbook}/Manager.java (86%) rename src/main/java/seedu/{duke => dietbook}/Parser.java (98%) rename src/main/java/seedu/{duke => dietbook}/Ui.java (99%) rename src/main/java/seedu/{duke => dietbook}/database/Canteen.java (94%) rename src/main/java/seedu/{duke => dietbook}/database/DataBase.java (99%) rename src/main/java/seedu/{duke => dietbook}/database/Store.java (91%) rename src/main/java/seedu/{duke => dietbook}/food/Food.java (97%) rename src/main/java/seedu/{duke => dietbook}/list/FoodEntry.java (92%) rename src/main/java/seedu/{duke => dietbook}/list/FoodList.java (97%) rename src/main/java/seedu/{duke => dietbook}/list/FoodListManager.java (96%) rename src/main/java/seedu/{duke => dietbook}/list/FoodNotFoundException.java (66%) rename src/main/java/seedu/{duke => dietbook}/person/ActivityLevel.java (97%) rename src/main/java/seedu/{duke => dietbook}/person/Gender.java (95%) rename src/main/java/seedu/{duke => dietbook}/person/Person.java (99%) rename src/test/java/seedu/{duke => dietbook}/DukeTest.java (88%) rename src/test/java/seedu/{duke => dietbook}/FoodListTest.java (83%) rename src/test/java/seedu/{duke => dietbook}/database/DataBaseTest.java (99%) rename src/test/java/seedu/{duke => dietbook}/food/FoodTest.java (89%) rename src/test/java/seedu/{duke => dietbook}/person/PersonTest.java (98%) diff --git a/build.gradle b/build.gradle index 0130e89069..8eee256504 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ test { } application { - mainClassName = "seedu.duke.DietBook" + mainClassName = "seedu.dietbook.DietBook" } shadowJar { diff --git a/src/main/java/seedu/calculator/Calculator.java b/src/main/java/seedu/calculator/Calculator.java index e50cf15f43..fe7c288242 100644 --- a/src/main/java/seedu/calculator/Calculator.java +++ b/src/main/java/seedu/calculator/Calculator.java @@ -1,6 +1,6 @@ package seedu.calculator; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.util.ArrayList; diff --git a/src/main/java/seedu/duke/DietBook.java b/src/main/java/seedu/dietbook/DietBook.java similarity index 91% rename from src/main/java/seedu/duke/DietBook.java rename to src/main/java/seedu/dietbook/DietBook.java index b7003f2753..24128b4a51 100644 --- a/src/main/java/seedu/duke/DietBook.java +++ b/src/main/java/seedu/dietbook/DietBook.java @@ -1,9 +1,9 @@ -package seedu.duke; +package seedu.dietbook; import java.io.FileNotFoundException; import java.io.IOException; -import seedu.duke.database.DataBase; -import seedu.duke.list.FoodList; +import seedu.dietbook.database.DataBase; +import seedu.dietbook.list.FoodList; public class DietBook { private FoodList foodList; diff --git a/src/main/java/seedu/duke/DietException.java b/src/main/java/seedu/dietbook/DietException.java similarity index 89% rename from src/main/java/seedu/duke/DietException.java rename to src/main/java/seedu/dietbook/DietException.java index 1cc3e09655..922514bfa5 100644 --- a/src/main/java/seedu/duke/DietException.java +++ b/src/main/java/seedu/dietbook/DietException.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.dietbook; public class DietException extends Exception { public DietException(String message) { diff --git a/src/main/java/seedu/duke/Manager.java b/src/main/java/seedu/dietbook/Manager.java similarity index 86% rename from src/main/java/seedu/duke/Manager.java rename to src/main/java/seedu/dietbook/Manager.java index 3b755c49ff..439b788e06 100644 --- a/src/main/java/seedu/duke/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -1,11 +1,11 @@ -package seedu.duke; +package seedu.dietbook; -import seedu.duke.list.FoodList; -import seedu.duke.person.ActivityLevel; -import seedu.duke.person.Person; +import seedu.dietbook.list.FoodList; +import seedu.dietbook.person.ActivityLevel; +import seedu.dietbook.person.Person; import seedu.calculator.Calculator; -import seedu.duke.database.DataBase; -import seedu.duke.person.Gender; +import seedu.dietbook.database.DataBase; +import seedu.dietbook.person.Gender; import java.util.Scanner; diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/dietbook/Parser.java similarity index 98% rename from src/main/java/seedu/duke/Parser.java rename to src/main/java/seedu/dietbook/Parser.java index c0e32315e0..b15f65b1a1 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/dietbook/Parser.java @@ -1,9 +1,9 @@ -package seedu.duke; +package seedu.dietbook; import seedu.calculator.Calculator; -import seedu.duke.list.FoodList; -import seedu.duke.person.Gender; -import seedu.duke.person.ActivityLevel; +import seedu.dietbook.list.FoodList; +import seedu.dietbook.person.Gender; +import seedu.dietbook.person.ActivityLevel; import java.io.FileNotFoundException; diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/dietbook/Ui.java similarity index 99% rename from src/main/java/seedu/duke/Ui.java rename to src/main/java/seedu/dietbook/Ui.java index 25f3a8d909..aee481e4ff 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -1,7 +1,7 @@ -package seedu.duke; +package seedu.dietbook; -import seedu.duke.food.Food; -import seedu.duke.person.ActivityLevel; +import seedu.dietbook.food.Food; +import seedu.dietbook.person.ActivityLevel; import java.util.List; diff --git a/src/main/java/seedu/duke/database/Canteen.java b/src/main/java/seedu/dietbook/database/Canteen.java similarity index 94% rename from src/main/java/seedu/duke/database/Canteen.java rename to src/main/java/seedu/dietbook/database/Canteen.java index 1243b0d9be..51946e60a8 100644 --- a/src/main/java/seedu/duke/database/Canteen.java +++ b/src/main/java/seedu/dietbook/database/Canteen.java @@ -1,4 +1,4 @@ -package seedu.duke.database; +package seedu.dietbook.database; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java similarity index 99% rename from src/main/java/seedu/duke/database/DataBase.java rename to src/main/java/seedu/dietbook/database/DataBase.java index 687d6528a6..0dd381a166 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -1,7 +1,7 @@ -package seedu.duke.database; +package seedu.dietbook.database; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/dietbook/database/Store.java similarity index 91% rename from src/main/java/seedu/duke/database/Store.java rename to src/main/java/seedu/dietbook/database/Store.java index af311ae856..fcb10d3071 100644 --- a/src/main/java/seedu/duke/database/Store.java +++ b/src/main/java/seedu/dietbook/database/Store.java @@ -1,6 +1,6 @@ -package seedu.duke.database; +package seedu.dietbook.database; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/dietbook/food/Food.java similarity index 97% rename from src/main/java/seedu/duke/food/Food.java rename to src/main/java/seedu/dietbook/food/Food.java index 9ea158bf5f..cdb6447657 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/dietbook/food/Food.java @@ -1,4 +1,4 @@ -package seedu.duke.food; +package seedu.dietbook.food; /** diff --git a/src/main/java/seedu/duke/list/FoodEntry.java b/src/main/java/seedu/dietbook/list/FoodEntry.java similarity index 92% rename from src/main/java/seedu/duke/list/FoodEntry.java rename to src/main/java/seedu/dietbook/list/FoodEntry.java index 7aa6f115e6..b58dc742e3 100644 --- a/src/main/java/seedu/duke/list/FoodEntry.java +++ b/src/main/java/seedu/dietbook/list/FoodEntry.java @@ -1,6 +1,6 @@ -package seedu.duke.list; +package seedu.dietbook.list; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; /** diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/dietbook/list/FoodList.java similarity index 97% rename from src/main/java/seedu/duke/list/FoodList.java rename to src/main/java/seedu/dietbook/list/FoodList.java index 92f92c47e3..0e3f26368f 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/dietbook/list/FoodList.java @@ -1,7 +1,7 @@ -package seedu.duke.list; +package seedu.dietbook.list; import java.util.ArrayList; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; /** diff --git a/src/main/java/seedu/duke/list/FoodListManager.java b/src/main/java/seedu/dietbook/list/FoodListManager.java similarity index 96% rename from src/main/java/seedu/duke/list/FoodListManager.java rename to src/main/java/seedu/dietbook/list/FoodListManager.java index 7165cae639..c0a15dbbd1 100644 --- a/src/main/java/seedu/duke/list/FoodListManager.java +++ b/src/main/java/seedu/dietbook/list/FoodListManager.java @@ -1,6 +1,6 @@ -package seedu.duke.list; +package seedu.dietbook.list; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.util.ArrayList; /** diff --git a/src/main/java/seedu/duke/list/FoodNotFoundException.java b/src/main/java/seedu/dietbook/list/FoodNotFoundException.java similarity index 66% rename from src/main/java/seedu/duke/list/FoodNotFoundException.java rename to src/main/java/seedu/dietbook/list/FoodNotFoundException.java index ca99d41a3e..9ab7aa42f3 100644 --- a/src/main/java/seedu/duke/list/FoodNotFoundException.java +++ b/src/main/java/seedu/dietbook/list/FoodNotFoundException.java @@ -1,4 +1,4 @@ -package seedu.duke.list; +package seedu.dietbook.list; public class FoodNotFoundException extends Exception{ } diff --git a/src/main/java/seedu/duke/person/ActivityLevel.java b/src/main/java/seedu/dietbook/person/ActivityLevel.java similarity index 97% rename from src/main/java/seedu/duke/person/ActivityLevel.java rename to src/main/java/seedu/dietbook/person/ActivityLevel.java index a045013b0d..ba71bd0a74 100644 --- a/src/main/java/seedu/duke/person/ActivityLevel.java +++ b/src/main/java/seedu/dietbook/person/ActivityLevel.java @@ -1,4 +1,4 @@ -package seedu.duke.person; +package seedu.dietbook.person; /** * Represents the physical activity level of a person or the amount of exercise a person engages in. diff --git a/src/main/java/seedu/duke/person/Gender.java b/src/main/java/seedu/dietbook/person/Gender.java similarity index 95% rename from src/main/java/seedu/duke/person/Gender.java rename to src/main/java/seedu/dietbook/person/Gender.java index 52b13a5a4b..b0bbe03e22 100644 --- a/src/main/java/seedu/duke/person/Gender.java +++ b/src/main/java/seedu/dietbook/person/Gender.java @@ -1,4 +1,4 @@ -package seedu.duke.person; +package seedu.dietbook.person; /** * Represents the gender of a person. diff --git a/src/main/java/seedu/duke/person/Person.java b/src/main/java/seedu/dietbook/person/Person.java similarity index 99% rename from src/main/java/seedu/duke/person/Person.java rename to src/main/java/seedu/dietbook/person/Person.java index ad3d49b348..eb85de0f98 100644 --- a/src/main/java/seedu/duke/person/Person.java +++ b/src/main/java/seedu/dietbook/person/Person.java @@ -1,4 +1,4 @@ -package seedu.duke.person; +package seedu.dietbook.person; /** * Represents a Person. diff --git a/src/test/java/seedu/calculator/CalculatorTest.java b/src/test/java/seedu/calculator/CalculatorTest.java index e58f33a249..3c4502b25f 100644 --- a/src/test/java/seedu/calculator/CalculatorTest.java +++ b/src/test/java/seedu/calculator/CalculatorTest.java @@ -1,7 +1,7 @@ package seedu.calculator; import org.junit.jupiter.api.Test; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.util.ArrayList; diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/dietbook/DukeTest.java similarity index 88% rename from src/test/java/seedu/duke/DukeTest.java rename to src/test/java/seedu/dietbook/DukeTest.java index 2dda5fd651..eef4b4c86a 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/dietbook/DukeTest.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.dietbook; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/seedu/duke/FoodListTest.java b/src/test/java/seedu/dietbook/FoodListTest.java similarity index 83% rename from src/test/java/seedu/duke/FoodListTest.java rename to src/test/java/seedu/dietbook/FoodListTest.java index 96b31d9647..1d3858913a 100644 --- a/src/test/java/seedu/duke/FoodListTest.java +++ b/src/test/java/seedu/dietbook/FoodListTest.java @@ -1,7 +1,7 @@ -package seedu.duke; +package seedu.dietbook; -import seedu.duke.list.FoodList; -import seedu.duke.food.Food; +import seedu.dietbook.list.FoodList; +import seedu.dietbook.food.Food; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/duke/database/DataBaseTest.java b/src/test/java/seedu/dietbook/database/DataBaseTest.java similarity index 99% rename from src/test/java/seedu/duke/database/DataBaseTest.java rename to src/test/java/seedu/dietbook/database/DataBaseTest.java index 004a1d0a70..4729c939e2 100644 --- a/src/test/java/seedu/duke/database/DataBaseTest.java +++ b/src/test/java/seedu/dietbook/database/DataBaseTest.java @@ -1,4 +1,4 @@ -package seedu.duke.database; +package seedu.dietbook.database; import java.util.NoSuchElementException; diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/dietbook/food/FoodTest.java similarity index 89% rename from src/test/java/seedu/duke/food/FoodTest.java rename to src/test/java/seedu/dietbook/food/FoodTest.java index 8c866c2f89..9696e058fa 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/dietbook/food/FoodTest.java @@ -1,7 +1,6 @@ -package seedu.duke.food; - -import seedu.duke.food.Food; +package seedu.dietbook.food; +import seedu.dietbook.food.Food; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/duke/person/PersonTest.java b/src/test/java/seedu/dietbook/person/PersonTest.java similarity index 98% rename from src/test/java/seedu/duke/person/PersonTest.java rename to src/test/java/seedu/dietbook/person/PersonTest.java index 714a66021b..ec5311d784 100644 --- a/src/test/java/seedu/duke/person/PersonTest.java +++ b/src/test/java/seedu/dietbook/person/PersonTest.java @@ -1,4 +1,4 @@ -package seedu.duke.person; +package seedu.dietbook.person; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From d78cdb1e25b0f54d5fc612f57b2a1e1272338811 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 20 Oct 2020 20:48:06 +0800 Subject: [PATCH 098/271] Remove Duke.java --- src/main/java/seedu/duke/Duke.java | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/main/java/seedu/duke/Duke.java diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java deleted file mode 100644 index 9f8063ee94..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()); - } -} \ No newline at end of file From a169dd4658b7cec96d74d6223d4b1a28b43f8a77 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Wed, 21 Oct 2020 14:59:34 +0800 Subject: [PATCH 099/271] add DatedFoodEntry FoodEntry child class that supports datetime functionality. --- .../java/seedu/duke/list/DatedFoodEntry.java | 64 +++++++++++++++++++ .../java/seedu/duke/list/FoodListTest.java | 16 ++++- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/duke/list/DatedFoodEntry.java diff --git a/src/main/java/seedu/duke/list/DatedFoodEntry.java b/src/main/java/seedu/duke/list/DatedFoodEntry.java new file mode 100644 index 0000000000..ad2c3f9395 --- /dev/null +++ b/src/main/java/seedu/duke/list/DatedFoodEntry.java @@ -0,0 +1,64 @@ +package seedu.duke.list; + +import seedu.duke.food.Food; +import java.time.LocalDateTime; + +public class DatedFoodEntry extends FoodEntry implements Comparable { + + protected final LocalDateTime dateTime; + + /** + * Default constructor method. + * Creates a food entry with a DateTime set to now. + */ + public DatedFoodEntry(int portionSize, String name, int calorie, + int carbohydrate, int protein, int fat) { + super(portionSize, name, calorie, carbohydrate, protein, fat); + this.dateTime = LocalDateTime.now(); + } + + /** + * Convenience constructor for testing. + * Also could be for adding food objects directly via DataBase. + */ + public DatedFoodEntry(int portionSize, Food food) { + super(portionSize, food); + this.dateTime = LocalDateTime.now(); + } + + /** + * Convenience constructor for testing. + * Could also be for adding backlogged entries with food objects directly via Database. + */ + public DatedFoodEntry(int portionSize, Food food, LocalDateTime dateTime) { + super(portionSize, food); + assert (dateTime != null) : "Should not add null DateTime." + + "Use other constructor to create with LocalDateTime.now() instead."; + this.dateTime = dateTime; + } + + /** + * For adding backlogged entries. + */ + public DatedFoodEntry(int portionSize, String name, int calorie, + int carbohydrate, int protein, int fat, LocalDateTime dateTime) { + super(portionSize, name, calorie, carbohydrate, protein, fat); + + assert (dateTime != null) : "Should not add null DateTime." + + "Use other constructor to create with LocalDateTime.now() instead."; + assert (dateTime.isBefore(LocalDateTime.now())) : "Attempting to add entry that hasn't happened yet."; + + this.dateTime = dateTime; + + } + + protected LocalDateTime getDateTime() { + return dateTime; + } + + @Override + public int compareTo(DatedFoodEntry other) { + return dateTime.compareTo(other.getDateTime()); + } + +} diff --git a/src/test/java/seedu/duke/list/FoodListTest.java b/src/test/java/seedu/duke/list/FoodListTest.java index 99779fe16e..e0e056a79b 100644 --- a/src/test/java/seedu/duke/list/FoodListTest.java +++ b/src/test/java/seedu/duke/list/FoodListTest.java @@ -3,19 +3,24 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -import seedu.duke.food.Food; +import java.time.LocalDateTime; +import seedu.duke.food.Food; class FoodListTest { private FoodList list; + private Food food; @BeforeEach protected void setUp() { this.list = new FoodList(); Food food = new Food("Kobe Beef", 480,50,40,30); + this.food = food; + list.addFood(3, food); list.addFood(2, "Sashimi", 100, 0, 30, 10); @@ -44,4 +49,13 @@ void deleteItemTest() { assertEquals(list.delete(1), entry.toString()); } + @Test + void dateComparisonTest() { + DatedFoodEntry entry = new DatedFoodEntry(2, food); + DatedFoodEntry pastEntry = new DatedFoodEntry(2, food, LocalDateTime.MIN); + + assertTrue(entry.compareTo(pastEntry) > 0); + + } + } From 4f1855d2f03f46a747963340fa7c974e62fec0c4 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 21 Oct 2020 15:53:29 +0800 Subject: [PATCH 100/271] implement saver --- src/main/java/seedu/duke/saveload/Saver.java | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/main/java/seedu/duke/saveload/Saver.java diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/duke/saveload/Saver.java new file mode 100644 index 0000000000..0b831035a1 --- /dev/null +++ b/src/main/java/seedu/duke/saveload/Saver.java @@ -0,0 +1,65 @@ +package seedu.duke.saveload; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class Saver { + private static final String ROOT_DIRECTORY = System.getProperty("user.home"); + private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; + private static final String EMPTY_SYMBOL = "%NULL&!!LL"; + private static final String SEPERATOR_SYMBOL = "&%SEPERATOR%$$"; + private static final String FILE_EXTENSION = ".txt"; + + private final String[][] entries; + private final int height; + private final int width; + + public Saver(int width, int height){ + this.height = height; + this.width = width; + this.entries = new String[height][width]; + + for (int i = 0; i < width; i ++){ + for (int j = 0; j < height; j++){ + entries[j][i] = EMPTY_SYMBOL; + } + } + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void add(String entry, int x_position, int y_position){ + this.entries[y_position][x_position] = entry; + } + + public void delete(int x_position, int y_position){ + this.entries[y_position][x_position] = EMPTY_SYMBOL; + } + + public void save(String folderName, String fileName){ + try { + File directory = new File(BASE_FOLDER_NAME + File.separator + folderName); + directory.mkdir(); + FileWriter writer = new FileWriter(BASE_FOLDER_NAME + File.separator + folderName + + File.separator + fileName + FILE_EXTENSION); + for (int j = 0; j < height; j ++){ + for (int i = 0; i < width; i++){ + writer.write(SEPERATOR_SYMBOL); + writer.write(entries[j][i]); + } + writer.write("\n"); + } + writer.close(); + } + catch(IOException e){ + System.out.println("Oops, the file writer took in a directory for some reason!"); + } + } +} From 3dc0ac39df982fb7c7ddf295a27d9f381e6ffbcf Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 21 Oct 2020 16:40:16 +0800 Subject: [PATCH 101/271] add test for saver class --- src/main/java/seedu/duke/saveload/Loader.java | 5 ++ src/main/java/seedu/duke/saveload/Saver.java | 53 +++++++++++++++++-- .../seedu/duke/saveload/SaveLoadFileTest.java | 12 +++++ .../java/seedu/duke/saveload/SaverTest.java | 37 +++++++++++++ 4 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 src/main/java/seedu/duke/saveload/Loader.java create mode 100644 src/test/java/seedu/duke/saveload/SaveLoadFileTest.java create mode 100644 src/test/java/seedu/duke/saveload/SaverTest.java diff --git a/src/main/java/seedu/duke/saveload/Loader.java b/src/main/java/seedu/duke/saveload/Loader.java new file mode 100644 index 0000000000..c1f5360a72 --- /dev/null +++ b/src/main/java/seedu/duke/saveload/Loader.java @@ -0,0 +1,5 @@ +package seedu.duke.saveload; + +public class Loader { + +} diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/duke/saveload/Saver.java index 0b831035a1..1ae3d08a9c 100644 --- a/src/main/java/seedu/duke/saveload/Saver.java +++ b/src/main/java/seedu/duke/saveload/Saver.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.Optional; public class Saver { private static final String ROOT_DIRECTORY = System.getProperty("user.home"); @@ -11,6 +12,11 @@ public class Saver { private static final String SEPERATOR_SYMBOL = "&%SEPERATOR%$$"; private static final String FILE_EXTENSION = ".txt"; + static { + File rootDirectory = new File(BASE_FOLDER_NAME); + rootDirectory.mkdir(); + } + private final String[][] entries; private final int height; private final int width; @@ -35,20 +41,59 @@ public int getHeight() { return height; } - public void add(String entry, int x_position, int y_position){ - this.entries[y_position][x_position] = entry; + public void add(String entry, int x_position, int y_position) throws IndexOutOfBoundsException{ + try { + this.entries[y_position - 1][x_position - 1] = entry; + } + catch (ArrayIndexOutOfBoundsException e){ + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); + } + } + + public void delete(int x_position, int y_position) throws IndexOutOfBoundsException{ + try { + this.entries[y_position - 1][x_position - 1] = EMPTY_SYMBOL; + } + catch (ArrayIndexOutOfBoundsException e){ + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); + } } - public void delete(int x_position, int y_position){ - this.entries[y_position][x_position] = EMPTY_SYMBOL; + public Optional get(int x_position, int y_position){ + try { + if (this.entries[y_position - 1][x_position - 1].equals(EMPTY_SYMBOL)) { + return Optional.empty(); + } else { + return Optional.of(this.entries[y_position][x_position]); + } + } + catch (ArrayIndexOutOfBoundsException e){ + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); + } } + /*** + * Saves the data table into a text file in the following format: + * width + * height + * row 1 entry 1 (seperator) row 1 entry 2 (separator) .... + * row 2 entry 1 (separator) row 2 entry 2 (separator) .... + * .... + * + * @param folderName name of the folder + * @param fileName name of the file + */ public void save(String folderName, String fileName){ try { File directory = new File(BASE_FOLDER_NAME + File.separator + folderName); directory.mkdir(); FileWriter writer = new FileWriter(BASE_FOLDER_NAME + File.separator + folderName + File.separator + fileName + FILE_EXTENSION); + writer.write(width + "\n"); + writer.write(height + "\n"); for (int j = 0; j < height; j ++){ for (int i = 0; i < width; i++){ writer.write(SEPERATOR_SYMBOL); diff --git a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java new file mode 100644 index 0000000000..b3a7c40196 --- /dev/null +++ b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java @@ -0,0 +1,12 @@ +package seedu.duke.saveload; + +public class SaveLoadFileTest { + public static void main(String[] args){ + Saver saver = new Saver(10, 6); + saver.add("banana", 5, 2); + saver.add("pineapple", 7, 1); + saver.add("cheetan", 2, 3); + saver.add("beetles", 1, 4); + saver.save("save_load_test","test1"); + } +} diff --git a/src/test/java/seedu/duke/saveload/SaverTest.java b/src/test/java/seedu/duke/saveload/SaverTest.java new file mode 100644 index 0000000000..7df613fa0b --- /dev/null +++ b/src/test/java/seedu/duke/saveload/SaverTest.java @@ -0,0 +1,37 @@ +package seedu.duke.saveload; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Optional; + +public class SaverTest { + private Saver saver; + + @BeforeEach + public void setUp() throws Exception{ + saver = new Saver(10, 6); + saver.add("banana", 5, 2); + saver.add("pineapple", 7, 1); + } + + @Test + public void get(){ + assertEquals(Optional.of("banana"), saver.get(5,2)); + assertEquals(Optional.of("pineapple"), saver.get(7,1)); + assertEquals(Optional.empty(), saver.get(1,1)); + assertThrows(IndexOutOfBoundsException.class, () -> saver.get(-1992,3500)); + } + + @Test + public void delete(){ + saver.add("Deletion lotion", 4,2); + assertEquals(Optional.of("Deletion lotion"), saver.get(4,2)); + saver.delete(4,2); + assertEquals(Optional.empty(), saver.get(4,2)); + assertThrows(IndexOutOfBoundsException.class, () -> saver.delete(-3402,9999)); + } +} From 62c030adafbc04a2abc67acd1832f8abcb599c34 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 21 Oct 2020 17:03:50 +0800 Subject: [PATCH 102/271] implement loader --- src/main/java/seedu/duke/saveload/Loader.java | 63 ++++++++++++++++++- src/main/java/seedu/duke/saveload/Saver.java | 6 +- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/duke/saveload/Loader.java b/src/main/java/seedu/duke/saveload/Loader.java index c1f5360a72..0fa4698986 100644 --- a/src/main/java/seedu/duke/saveload/Loader.java +++ b/src/main/java/seedu/duke/saveload/Loader.java @@ -1,5 +1,66 @@ package seedu.duke.saveload; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Optional; +import java.util.Scanner; + public class Loader { - + private static final String ROOT_DIRECTORY = System.getProperty("user.home"); + private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; + private static final String EMPTY_SYMBOL = "%NULL&!!LL"; + private static final String SEPARATOR_SYMBOL = "&%SEPERATOR%AAA%"; + private static final String FILE_EXTENSION = ".txt"; + + private final String[][] entries; + private final int width; + private final int height; + + public static Loader load(String folderName, String fileName) throws FileNotFoundException { + return new Loader(folderName, fileName); + } + + private Loader(String folderName, String fileName) throws FileNotFoundException { + File file = new File(BASE_FOLDER_NAME + File.separator + folderName + +File.separator + fileName + FILE_EXTENSION); + Scanner reader = new Scanner(file); + width = Integer.parseInt(reader.nextLine()); + height = Integer.parseInt(reader.nextLine()); + entries = new String[height][width]; + String[] line; + for (int j = 0; j < height; j++){ + line = reader.nextLine().split(SEPARATOR_SYMBOL); + if (width >= 0) System.arraycopy(line, 1, entries[j], 0, width); + } + } + + /** + * Get the String entry stored at the specified position in the table if it is present. + * @param x_position the x position in the table from 1 to the table width + * @param y_position the y position in the table from 1 to the table height + * @return Optional of the String. The Optional is empty is no entry is stored + * @throws IndexOutOfBoundsException if the x or y given is not as above + */ + public Optional get(int x_position, int y_position) throws IndexOutOfBoundsException { + try { + if (this.entries[y_position - 1][x_position - 1].equals(EMPTY_SYMBOL)) { + return Optional.empty(); + } else { + return Optional.of(this.entries[y_position][x_position]); + } + } + catch (ArrayIndexOutOfBoundsException e){ + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); + } + } + + + public int getHeight() { + return height; + } + + public int getWidth() { + return width; + } } diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/duke/saveload/Saver.java index 1ae3d08a9c..89be347e28 100644 --- a/src/main/java/seedu/duke/saveload/Saver.java +++ b/src/main/java/seedu/duke/saveload/Saver.java @@ -9,7 +9,7 @@ public class Saver { private static final String ROOT_DIRECTORY = System.getProperty("user.home"); private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; private static final String EMPTY_SYMBOL = "%NULL&!!LL"; - private static final String SEPERATOR_SYMBOL = "&%SEPERATOR%$$"; + private static final String SEPERATOR_SYMBOL = "&%SEPERATOR%AAA%"; private static final String FILE_EXTENSION = ".txt"; static { @@ -79,8 +79,8 @@ public Optional get(int x_position, int y_position){ * Saves the data table into a text file in the following format: * width * height - * row 1 entry 1 (seperator) row 1 entry 2 (separator) .... - * row 2 entry 1 (separator) row 2 entry 2 (separator) .... + * (seperator) row 1 entry 1 (seperator) row 1 entry 2 (separator) .... + * (seperator) row 2 entry 1 (separator) row 2 entry 2 (separator) .... * .... * * @param folderName name of the folder From b43add73ab70d976090cda3d6ed3648885e72957 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 21 Oct 2020 17:18:47 +0800 Subject: [PATCH 103/271] test loader class --- src/main/java/seedu/duke/saveload/Loader.java | 8 ++++++-- .../java/seedu/duke/saveload/SaveLoadFileTest.java | 13 ++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/duke/saveload/Loader.java b/src/main/java/seedu/duke/saveload/Loader.java index 0fa4698986..2d532fd7f3 100644 --- a/src/main/java/seedu/duke/saveload/Loader.java +++ b/src/main/java/seedu/duke/saveload/Loader.java @@ -5,6 +5,10 @@ import java.util.Optional; import java.util.Scanner; +/** + * Handles reading of stored text file. + * Note: the first five fields must be same + */ public class Loader { private static final String ROOT_DIRECTORY = System.getProperty("user.home"); private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; @@ -46,10 +50,10 @@ public Optional get(int x_position, int y_position) throws IndexOutOfBou if (this.entries[y_position - 1][x_position - 1].equals(EMPTY_SYMBOL)) { return Optional.empty(); } else { - return Optional.of(this.entries[y_position][x_position]); + return Optional.of(this.entries[y_position-1][x_position-1]); } } - catch (ArrayIndexOutOfBoundsException e){ + catch (ArrayIndexOutOfBoundsException e) { throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + "saver table!"); } diff --git a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java index b3a7c40196..d46116b9b7 100644 --- a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java +++ b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java @@ -1,12 +1,23 @@ package seedu.duke.saveload; +import java.io.FileNotFoundException; + public class SaveLoadFileTest { - public static void main(String[] args){ + public static void main(String[] args) throws FileNotFoundException { Saver saver = new Saver(10, 6); + Loader loader; saver.add("banana", 5, 2); saver.add("pineapple", 7, 1); saver.add("cheetan", 2, 3); saver.add("beetles", 1, 4); saver.save("save_load_test","test1"); + + loader = Loader.load("save_load_test","test1"); + loader.get(5, 2).ifPresent(System.out::println); + loader.get(7, 1).ifPresent(System.out::println); + loader.get(2, 3).ifPresent(System.out::println); + loader.get(1, 4).ifPresent(System.out::println); + loader.get(1, 3).ifPresent(System.out::println); + loader.get(10, 6).ifPresent(System.out::println); } } From fd5ad65f8e1fb939b966a4f5623d7a0c0d666a2f Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 21 Oct 2020 17:26:09 +0800 Subject: [PATCH 104/271] add documentation --- src/main/java/seedu/duke/saveload/Saver.java | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/duke/saveload/Saver.java index 89be347e28..7d7d3136c6 100644 --- a/src/main/java/seedu/duke/saveload/Saver.java +++ b/src/main/java/seedu/duke/saveload/Saver.java @@ -5,6 +5,11 @@ import java.io.IOException; import java.util.Optional; + +/** + * Saver class allows storage of string data into a table with a given width and height + * It has a function that can write the data stored in it's table. + */ public class Saver { private static final String ROOT_DIRECTORY = System.getProperty("user.home"); private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; @@ -41,6 +46,13 @@ public int getHeight() { return height; } + /** + * Adds the string provided to the position x,y on the table. + * @param entry the entry to be provided into this position + * @param x_position x position + * @param y_position y position + * @throws IndexOutOfBoundsException x or y position is out of bounds + */ public void add(String entry, int x_position, int y_position) throws IndexOutOfBoundsException{ try { this.entries[y_position - 1][x_position - 1] = entry; @@ -51,6 +63,12 @@ public void add(String entry, int x_position, int y_position) throws IndexOutOfB } } + /** + * Deletes the entry in the table. + * @param x_position x position + * @param y_position y position + * @throws IndexOutOfBoundsException + */ public void delete(int x_position, int y_position) throws IndexOutOfBoundsException{ try { this.entries[y_position - 1][x_position - 1] = EMPTY_SYMBOL; @@ -61,6 +79,12 @@ public void delete(int x_position, int y_position) throws IndexOutOfBoundsExcept } } + /** + * Gets a entry stored in the table. + * @param x_position x position + * @param y_position y position + * @return Optional of String that is empty if the position does not contain an entry. + */ public Optional get(int x_position, int y_position){ try { if (this.entries[y_position - 1][x_position - 1].equals(EMPTY_SYMBOL)) { From 30de965ab56cda247a976676fb09c4dc9513c2fe Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 21 Oct 2020 17:42:44 +0800 Subject: [PATCH 105/271] fix check style tests --- src/main/java/seedu/duke/saveload/Loader.java | 25 +++---- src/main/java/seedu/duke/saveload/Saver.java | 66 +++++++++---------- .../seedu/duke/saveload/SaveLoadFileTest.java | 2 +- .../java/seedu/duke/saveload/SaverTest.java | 8 +-- 4 files changed, 49 insertions(+), 52 deletions(-) diff --git a/src/main/java/seedu/duke/saveload/Loader.java b/src/main/java/seedu/duke/saveload/Loader.java index 2d532fd7f3..72311fd1b1 100644 --- a/src/main/java/seedu/duke/saveload/Loader.java +++ b/src/main/java/seedu/duke/saveload/Loader.java @@ -26,36 +26,37 @@ public static Loader load(String folderName, String fileName) throws FileNotFoun private Loader(String folderName, String fileName) throws FileNotFoundException { File file = new File(BASE_FOLDER_NAME + File.separator + folderName - +File.separator + fileName + FILE_EXTENSION); + + File.separator + fileName + FILE_EXTENSION); Scanner reader = new Scanner(file); width = Integer.parseInt(reader.nextLine()); height = Integer.parseInt(reader.nextLine()); entries = new String[height][width]; String[] line; - for (int j = 0; j < height; j++){ + for (int j = 0; j < height; j++) { line = reader.nextLine().split(SEPARATOR_SYMBOL); - if (width >= 0) System.arraycopy(line, 1, entries[j], 0, width); + if (width >= 0) { + System.arraycopy(line, 1, entries[j], 0, width); + } } } /** * Get the String entry stored at the specified position in the table if it is present. - * @param x_position the x position in the table from 1 to the table width - * @param y_position the y position in the table from 1 to the table height + * @param xposition the x position in the table from 1 to the table width + * @param yposition the y position in the table from 1 to the table height * @return Optional of the String. The Optional is empty is no entry is stored * @throws IndexOutOfBoundsException if the x or y given is not as above */ - public Optional get(int x_position, int y_position) throws IndexOutOfBoundsException { + public Optional get(int xposition, int yposition) throws IndexOutOfBoundsException { try { - if (this.entries[y_position - 1][x_position - 1].equals(EMPTY_SYMBOL)) { + if (this.entries[yposition - 1][xposition - 1].equals(EMPTY_SYMBOL)) { return Optional.empty(); } else { - return Optional.of(this.entries[y_position-1][x_position-1]); + return Optional.of(this.entries[yposition - 1][xposition - 1]); } - } - catch (ArrayIndexOutOfBoundsException e) { - throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + - "saver table!"); + } catch (ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); } } diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/duke/saveload/Saver.java index 7d7d3136c6..720b0d1ae1 100644 --- a/src/main/java/seedu/duke/saveload/Saver.java +++ b/src/main/java/seedu/duke/saveload/Saver.java @@ -26,13 +26,13 @@ public class Saver { private final int height; private final int width; - public Saver(int width, int height){ + public Saver(int width, int height) { this.height = height; this.width = width; this.entries = new String[height][width]; - for (int i = 0; i < width; i ++){ - for (int j = 0; j < height; j++){ + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { entries[j][i] = EMPTY_SYMBOL; } } @@ -49,57 +49,54 @@ public int getHeight() { /** * Adds the string provided to the position x,y on the table. * @param entry the entry to be provided into this position - * @param x_position x position - * @param y_position y position + * @param xposition x position + * @param yposition y position * @throws IndexOutOfBoundsException x or y position is out of bounds */ - public void add(String entry, int x_position, int y_position) throws IndexOutOfBoundsException{ + public void add(String entry, int xposition, int yposition) throws IndexOutOfBoundsException { try { - this.entries[y_position - 1][x_position - 1] = entry; - } - catch (ArrayIndexOutOfBoundsException e){ - throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + - "saver table!"); + this.entries[yposition - 1][xposition - 1] = entry; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); } } /** * Deletes the entry in the table. - * @param x_position x position - * @param y_position y position - * @throws IndexOutOfBoundsException + * @param xposition x position + * @param yposition y position + * @throws IndexOutOfBoundsException x or y position is out of bounds */ - public void delete(int x_position, int y_position) throws IndexOutOfBoundsException{ + public void delete(int xposition, int yposition) throws IndexOutOfBoundsException { try { - this.entries[y_position - 1][x_position - 1] = EMPTY_SYMBOL; - } - catch (ArrayIndexOutOfBoundsException e){ - throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + - "saver table!"); + this.entries[yposition - 1][xposition - 1] = EMPTY_SYMBOL; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); } } /** * Gets a entry stored in the table. - * @param x_position x position - * @param y_position y position + * @param xposition x position + * @param yposition y position * @return Optional of String that is empty if the position does not contain an entry. */ - public Optional get(int x_position, int y_position){ + public Optional get(int xposition, int yposition) { try { - if (this.entries[y_position - 1][x_position - 1].equals(EMPTY_SYMBOL)) { + if (this.entries[yposition - 1][xposition - 1].equals(EMPTY_SYMBOL)) { return Optional.empty(); } else { - return Optional.of(this.entries[y_position][x_position]); + return Optional.of(this.entries[yposition - 1][xposition - 1]); } - } - catch (ArrayIndexOutOfBoundsException e){ - throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + - "saver table!"); + } catch (ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); } } - /*** + /** * Saves the data table into a text file in the following format: * width * height @@ -110,7 +107,7 @@ public Optional get(int x_position, int y_position){ * @param folderName name of the folder * @param fileName name of the file */ - public void save(String folderName, String fileName){ + public void save(String folderName, String fileName) { try { File directory = new File(BASE_FOLDER_NAME + File.separator + folderName); directory.mkdir(); @@ -118,16 +115,15 @@ public void save(String folderName, String fileName){ + File.separator + fileName + FILE_EXTENSION); writer.write(width + "\n"); writer.write(height + "\n"); - for (int j = 0; j < height; j ++){ - for (int i = 0; i < width; i++){ + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { writer.write(SEPERATOR_SYMBOL); writer.write(entries[j][i]); } writer.write("\n"); } writer.close(); - } - catch(IOException e){ + } catch (IOException e) { System.out.println("Oops, the file writer took in a directory for some reason!"); } } diff --git a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java index d46116b9b7..7f9cd5acaf 100644 --- a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java +++ b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java @@ -5,13 +5,13 @@ public class SaveLoadFileTest { public static void main(String[] args) throws FileNotFoundException { Saver saver = new Saver(10, 6); - Loader loader; saver.add("banana", 5, 2); saver.add("pineapple", 7, 1); saver.add("cheetan", 2, 3); saver.add("beetles", 1, 4); saver.save("save_load_test","test1"); + Loader loader; loader = Loader.load("save_load_test","test1"); loader.get(5, 2).ifPresent(System.out::println); loader.get(7, 1).ifPresent(System.out::println); diff --git a/src/test/java/seedu/duke/saveload/SaverTest.java b/src/test/java/seedu/duke/saveload/SaverTest.java index 7df613fa0b..9fbe56e768 100644 --- a/src/test/java/seedu/duke/saveload/SaverTest.java +++ b/src/test/java/seedu/duke/saveload/SaverTest.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Optional; @@ -12,14 +12,14 @@ public class SaverTest { private Saver saver; @BeforeEach - public void setUp() throws Exception{ + public void setUp() { saver = new Saver(10, 6); saver.add("banana", 5, 2); saver.add("pineapple", 7, 1); } @Test - public void get(){ + public void get() { assertEquals(Optional.of("banana"), saver.get(5,2)); assertEquals(Optional.of("pineapple"), saver.get(7,1)); assertEquals(Optional.empty(), saver.get(1,1)); @@ -27,7 +27,7 @@ public void get(){ } @Test - public void delete(){ + public void delete() { saver.add("Deletion lotion", 4,2); assertEquals(Optional.of("Deletion lotion"), saver.get(4,2)); saver.delete(4,2); From 4bb71e462e1621fad1facca1b32aec443f31950f Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Wed, 21 Oct 2020 17:55:01 +0800 Subject: [PATCH 106/271] Shorten output divider --- src/main/java/seedu/duke/Ui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 25f3a8d909..bd11c231bc 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -261,7 +261,7 @@ public void printErrorMessage(String errorMessage) { public void print(String message) { String divider = "__________________________________________________________________________________________" - + "______________________________________________________"; + + "____________________"; System.out.println(divider + LINE_SEPARATOR + message + LINE_SEPARATOR From 51e3eccf8b7a4c693b8327fa741efefba276e84b Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Wed, 21 Oct 2020 17:58:32 +0800 Subject: [PATCH 107/271] Change printDatabase method input paramater To reduce coupling between Food and Ui class. --- src/main/java/seedu/duke/Ui.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index bd11c231bc..6f41445d95 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -123,18 +123,12 @@ public void printFoodList(String allFood) { /** * Prints all the food in the database sorted by the canteen and then the store it is found. * - * @param foodDatabase The list containing all the food items stored in the database. + * @param foodDatabase The string representation of all the food items stored in the database. */ - public void printDatabase(List foodDatabase) { + public void printDatabase(String foodDatabase) { assert foodDatabase != null : "Food database should not be null"; - assert foodDatabase.size() > 0 : "Food database should not be empty"; - String allFood = ""; - int foodItemNumber = 1; - for (Food food: foodDatabase) { - allFood += LINE_SEPARATOR + " " + foodItemNumber + "." + food; - foodItemNumber++; - } - print("Here are the food items in the database:" + allFood); + assert foodDatabase.trim().length() > 0 : "Food database should not be empty"; + print("Here are the food items in the database:" + LINE_SEPARATOR + foodDatabase); } /** From 838f46af1878839ca03e590b5347558d47dcad45 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 22 Oct 2020 01:04:53 +0800 Subject: [PATCH 108/271] Remove unused import --- src/main/java/seedu/duke/Ui.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index 6f41445d95..ea54cfb782 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -1,6 +1,5 @@ package seedu.duke; -import seedu.duke.food.Food; import seedu.duke.person.ActivityLevel; import java.util.List; From 398ceb005b6be089756e09346a9100c5778f09a6 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 22 Oct 2020 01:07:25 +0800 Subject: [PATCH 109/271] Get gender description from Gender object --- src/main/java/seedu/duke/Ui.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index ea54cfb782..a4cc1724a5 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -1,6 +1,7 @@ package seedu.duke; import seedu.duke.person.ActivityLevel; +import seedu.duke.person.Gender; import java.util.List; @@ -50,7 +51,8 @@ public void printAskForUserInfoMessage(String name) { + LINE_SEPARATOR + "accurate calculations for you :). Therefore, could you please share with me the " + "following:" + LINE_SEPARATOR - + "- Your gender either F for female or M for male." + LINE_SEPARATOR + + "- Your gender either F for " + Gender.FEMALE.getDescription() + " or M for " + + Gender.MALE.getDescription() + "." + LINE_SEPARATOR + "- Your age which is a positive integer." + LINE_SEPARATOR + "- Your height in cm." + LINE_SEPARATOR + "- Your original weight in kg." + LINE_SEPARATOR From 50bd94d35c95667865df743e9fbce4a22f49899d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 22 Oct 2020 01:09:19 +0800 Subject: [PATCH 110/271] Add method to convert LocalDateTime to String --- src/main/java/seedu/duke/Ui.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index a4cc1724a5..be89fc0942 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -3,7 +3,8 @@ import seedu.duke.person.ActivityLevel; import seedu.duke.person.Gender; -import java.util.List; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; /** * Represents a text user interface. @@ -121,6 +122,18 @@ public void printFoodList(String allFood) { } } + + /** + * Returns a string representation of the date time in the format dd MMM yyyy HHmm. + * + * @param dateTime The date time that needs to be converted into a String. + * @return Returns a string representation of the date and time in the format dd MMM yyyy HHmm. + */ + public String stringDateTime(LocalDateTime dateTime) { + assert dateTime != null : "Date time to be converted into string should not be null"; + return dateTime.format(DateTimeFormatter.ofPattern("dd MMM yyyy HHmm")); + } + /** * Prints all the food in the database sorted by the canteen and then the store it is found. * From 6d5a8f034e6aaf32e3183c10bc4440609336c789 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 22 Oct 2020 01:10:54 +0800 Subject: [PATCH 111/271] Add Junit tests for stringDateTime method in Ui --- src/test/java/seedu/duke/UiTest.java | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/java/seedu/duke/UiTest.java diff --git a/src/test/java/seedu/duke/UiTest.java b/src/test/java/seedu/duke/UiTest.java new file mode 100644 index 0000000000..f0eeb79c54 --- /dev/null +++ b/src/test/java/seedu/duke/UiTest.java @@ -0,0 +1,36 @@ +package seedu.duke; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.duke.person.Person; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +class UiTest { + + private Ui ui; + + @BeforeEach + public void setUp() { + ui = new Ui(); + } + + @Test + void stringDateTime_nullInput_expectAssertionError() { + assertThrows(AssertionError.class, () -> ui.stringDateTime(null)); + } + + @Test + void stringDateTime_LocalDateTime_returnsStringOfLocalDateTime() { + LocalDateTime dateTime = LocalDateTime.parse("2020-10-21T23:59"); + assertEquals("21 Oct 2020 2359",ui.stringDateTime(dateTime)); + } + + @Test + void stringDateTime_LocalDateTimeWithSeconds_returnsStringOfLocalDateTimeWithoutSeconds() { + LocalDateTime dateTime = LocalDateTime.parse("2020-10-21T23:59:22"); + assertEquals("21 Oct 2020 2359",ui.stringDateTime(dateTime)); + } +} From 50f4f3eb78db22c0263b9adf4841e458b97ec963 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 22 Oct 2020 01:23:49 +0800 Subject: [PATCH 112/271] Add printFoodListGivenTimePeriod method The method prints food items in the food list that were recorded during a certain time period. --- src/main/java/seedu/duke/Ui.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/seedu/duke/Ui.java b/src/main/java/seedu/duke/Ui.java index be89fc0942..2de5a54aa9 100644 --- a/src/main/java/seedu/duke/Ui.java +++ b/src/main/java/seedu/duke/Ui.java @@ -122,6 +122,31 @@ public void printFoodList(String allFood) { } } + /** + * Prints food items recorded into the food list during a given time period in the order that they were + * added or a message stating no food items were recorded during the given time period. + * + * @param foods The string representation of food items in the food list recorded during the time + * period given. + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. + */ + public void printFoodListGivenTimePeriod(String foods, LocalDateTime start, LocalDateTime end) { + assert foods != null : "String representation of food items in the food list recorded during the " + + "time period given should not be null"; + assert start != null : "Starting date time of the time period should not be null"; + assert end != null : "Ending date time of the time period should not be null"; + assert !start.isAfter(end) : "Starting date time should not be later than ending date time " + + "of the time period"; + String stringStart = stringDateTime(start); + String stringEnd = stringDateTime(end); + if (foods.trim().length() < 1) { + print("No food item was recorded in DietBook between " + stringStart + " and " + stringEnd + "."); + } else { + print("Here are the food items recorded in DietBook between " + stringStart + " and " + stringEnd + + " :" + LINE_SEPARATOR + foods); + } + } /** * Returns a string representation of the date time in the format dd MMM yyyy HHmm. From c471d25243b585c16840bb86dabd7fb5a76bfce9 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 22 Oct 2020 02:18:16 +0800 Subject: [PATCH 113/271] Major Issue Fixes - add -> full information - swappable, optional add command - swappable info command - catch index error for delete --- src/main/java/seedu/duke/Parser.java | 145 +++++++++++++++++++-------- 1 file changed, 103 insertions(+), 42 deletions(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 033fafb972..5517f0e10f 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -20,7 +20,7 @@ public class Parser { public static final String COMMAND_USERINFO = "userinfo"; public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; - public static final String[] PARAM_ADD = {"n/","x/","k/","f/","p/","c/"}; + public static final String[] PARAM_ADD = {"n/","x/","k/"}; /** @@ -44,7 +44,7 @@ private static String getCommandParam(String userInput) throws DietException { if (userInput.split(command).length < 2 || userInput.split(command)[1].equals(" ")) { - throw new DietException("☹ Error! Missing command parameters!"); + throw new DietException("Error! Missing command parameters!"); } else { switch (command) { case COMMAND_NAME: @@ -55,18 +55,18 @@ private static String getCommandParam(String userInput) throws DietException { return userInput.split(" ")[1]; } } - throw new DietException("☹ Incorrect nutrient type"); + throw new DietException("Incorrect nutrient type"); case COMMAND_ADD: for (String param: PARAM_ADD) { if (!userInput.contains(param)) { - throw new DietException("☹ Missing or incorrect add statement"); + throw new DietException("Missing or incorrect add statement"); } } return userInput.substring(userInput.indexOf(' ') + 1); case COMMAND_INFO: for (String param: PARAM_INFO) { if (!userInput.contains(param)) { - throw new DietException("☹ Missing or incorrect info statement"); + throw new DietException("Missing or incorrect info statement"); } } return userInput.substring(userInput.indexOf(' ') + 1); @@ -84,15 +84,45 @@ private static String getCommandParam(String userInput) throws DietException { * @throws DietException when the user input is of a wrong format. */ private static String getProcessedAdd(String userInput, FoodList foodList) throws DietException { - String[] processedParam = getCommandParam(userInput).split(" "); - int portionSize = Integer.parseInt(processedParam[0].substring(processedParam[0].indexOf("/") + 1)); - String foodName = processedParam[1].substring(processedParam[1].indexOf("/") + 1); - int calorie = Integer.parseInt(processedParam[2].substring(processedParam[2].indexOf("/") + 1)); - int carb = Integer.parseInt(processedParam[3].substring(processedParam[3].indexOf("/") + 1)); - int protein = Integer.parseInt(processedParam[4].substring(processedParam[4].indexOf("/") + 1)); - int fat = Integer.parseInt(processedParam[5].substring(processedParam[5].indexOf("/") + 1)); - foodList.addFood(portionSize, foodName, calorie, carb, protein, fat); - return foodName; + int portionSize = 1; + String foodName = "Food Name"; + int calorie = 0; + int carb = 0; + int protein = 0; + int fat = 0; + String trimmedParam; + String[] processedParam; + String[] paramList = {"x/", "n/", "k/", "c/", "p/", "f/"}; + for (String param: paramList) { + if (getCommandParam(userInput).contains(param)) { + processedParam = getCommandParam(userInput).split(param); + trimmedParam = processedParam[1].trim(); + if (processedParam[1].contains("/")) { + trimmedParam = processedParam[1].substring(0, processedParam[1].indexOf("/") - 2).trim(); + } + switch (param) { + case "x/": + portionSize = Integer.parseInt(trimmedParam); + break; + case "n/": + foodName = trimmedParam; + break; + case "k/": + calorie = Integer.parseInt(trimmedParam); + break; + case "c/": + carb = Integer.parseInt(trimmedParam); + break; + case "p/": + protein = Integer.parseInt(trimmedParam); + break; + default: + fat = Integer.parseInt(trimmedParam); + break; + } + } + } + return foodList.addFood(portionSize, foodName, calorie, carb, protein, fat); } /** @@ -102,30 +132,57 @@ private static String getProcessedAdd(String userInput, FoodList foodList) throw * @throws DietException when the user input is of a wrong format. */ private static void executeProcessedInfo(String userInput, Manager manager) throws DietException { - Gender gender; - ActivityLevel actLvl; - String[] processedParam = getCommandParam(userInput).split(" "); - String processGender = processedParam[0].substring(processedParam[0].indexOf("/") + 1); - if (processGender.equals("M")) { - gender = Gender.MALE; - } else { - gender = Gender.FEMALE; - } - int age = Integer.parseInt(processedParam[1].substring(processedParam[1].indexOf("/") + 1)); - int height = Integer.parseInt(processedParam[2].substring(processedParam[2].indexOf("/") + 1)); - int orgWeight = Integer.parseInt(processedParam[3].substring(processedParam[3].indexOf("/") + 1)); - int tarWeight = Integer.parseInt(processedParam[4].substring(processedParam[4].indexOf("/") + 1)); - String processActLvl = processedParam[5].substring(processedParam[5].indexOf("/") + 1); - if (processActLvl.equals("1")) { - actLvl = ActivityLevel.NONE; - } else if (processActLvl.equals("2")) { - actLvl = ActivityLevel.LOW; - } else if (processActLvl.equals("3")) { - actLvl = ActivityLevel.MEDIUM; - } else if (processActLvl.equals("4")) { - actLvl = ActivityLevel.HIGH; - } else { - actLvl = ActivityLevel.EXTREME; + Gender gender = Gender.MALE; + ActivityLevel actLvl = ActivityLevel.NONE; + int age = 0; + int height = 0; + int orgWeight = 0; + int tarWeight = 0; + String trimmedParam; + String[] processedParam; + String[] paramList = {"g/", "a/", "h/", "o/", "t/", "l/"}; + for (String param: paramList) { + processedParam = getCommandParam(userInput).split(param); + trimmedParam = processedParam[1].trim(); + if (processedParam[1].contains("/")) { + trimmedParam = processedParam[1].substring(0, processedParam[1].indexOf("/") - 2).trim(); + } + switch (param) { + case "g/": + String processGender = trimmedParam; + if (processGender.equals("M")) { + gender = Gender.MALE; + } else { + gender = Gender.FEMALE; + } + break; + case "a/": + age = Integer.parseInt(trimmedParam); + break; + case "h/": + height = Integer.parseInt(trimmedParam); + break; + case "o/": + orgWeight = Integer.parseInt(trimmedParam); + break; + case "t/": + tarWeight = Integer.parseInt(trimmedParam); + break; + default: + String processActLvl = trimmedParam; + if (processActLvl.equals("1")) { + actLvl = ActivityLevel.NONE; + } else if (processActLvl.equals("2")) { + actLvl = ActivityLevel.LOW; + } else if (processActLvl.equals("3")) { + actLvl = ActivityLevel.MEDIUM; + } else if (processActLvl.equals("4")) { + actLvl = ActivityLevel.HIGH; + } else { + actLvl = ActivityLevel.EXTREME; + } + break; + } } manager.setPerson(manager.getName(), gender, age, height, orgWeight, tarWeight, actLvl); } @@ -140,12 +197,12 @@ private static int getCommandIndex(String userInput) throws DietException { String command = getCommand(userInput); if (userInput.split(command).length < 2 || userInput.split(command)[1].equals(" ")) { - throw new DietException("☹ OOPS!!! Missing index of duke.task!"); + throw new DietException("OOPS!!! Missing index of duke.task!"); } try { return Integer.parseInt(userInput.split(" ")[1]); } catch (NumberFormatException e) { - throw new DietException("☹ OOPS!!! No integer index detected!"); + throw new DietException("OOPS!!! No integer index detected!"); } } @@ -176,7 +233,11 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx ui.printDatabase(manager.getDataBase().getFoodList()); return; case COMMAND_DELETE: - ui.printDeletedFood(manager.getFoodList().delete(getCommandIndex(userInput))); + try { + ui.printDeletedFood(manager.getFoodList().delete(getCommandIndex(userInput))); + } catch (IndexOutOfBoundsException e) { + throw new DietException("No such index!"); + } return; case COMMAND_CLEAR: ui.printClearFoodListMessage(); @@ -205,7 +266,7 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx ui.printNewFood(getProcessedAdd(userInput, manager.getFoodList())); return; default: - throw new DietException("☹ There's no such command!"); + throw new DietException("There's no such command!"); } } } From 6d0987880f61b1ff9abc42436c193f39c702199d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 22 Oct 2020 10:26:06 +0800 Subject: [PATCH 114/271] Update package and remove wilcard import --- src/test/java/seedu/dietbook/UiTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/java/seedu/dietbook/UiTest.java b/src/test/java/seedu/dietbook/UiTest.java index f0eeb79c54..f25dccd228 100644 --- a/src/test/java/seedu/dietbook/UiTest.java +++ b/src/test/java/seedu/dietbook/UiTest.java @@ -1,12 +1,13 @@ -package seedu.duke; +package seedu.dietbook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.duke.person.Person; +import seedu.dietbook.person.Person; import java.time.LocalDateTime; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class UiTest { From 4174aecb5ddadf191f0723c65af3353d71c1714c Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 22 Oct 2020 10:26:43 +0800 Subject: [PATCH 115/271] Remove unused import in JUnit test --- src/test/java/seedu/dietbook/UiTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/seedu/dietbook/UiTest.java b/src/test/java/seedu/dietbook/UiTest.java index f25dccd228..91076665f1 100644 --- a/src/test/java/seedu/dietbook/UiTest.java +++ b/src/test/java/seedu/dietbook/UiTest.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.dietbook.person.Person; import java.time.LocalDateTime; From 9720f7790f263c9eb9e9f6fc9aa080838c4ab335 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Fri, 23 Oct 2020 00:56:40 +0800 Subject: [PATCH 116/271] Add methods to trim Strings and get length --- src/main/java/seedu/dietbook/Ui.java | 64 +++++++++++++++++++--------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 9ad3cdf8c2..eec8ede96c 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -46,8 +46,8 @@ public void printWelcomeMessage() { */ public void printAskForUserInfoMessage(String name) { assert name != null : "Name should not be null"; - assert name.trim().length() > 0 : "Name should not be an empty string"; - print("Hi " + name + "!" + LINE_SEPARATOR + assert trimStringGetLength(name) > 0 : "Name should not be an empty string"; + print("Hi " + trimString(name) + "!" + LINE_SEPARATOR + "Before we get started, I would like to know about about you so that I can make more " + LINE_SEPARATOR + "accurate calculations for you :). Therefore, could you please share with me the " @@ -101,10 +101,10 @@ public void printTutorialMessage() { */ public void printNewFood(String newFood) { assert newFood != null : "String representation of the food that was added should not be null"; - assert newFood.trim().length() > 0 : "String representation of the food that was added should not " + assert trimStringGetLength(newFood) > 0 : "String representation of the food that was added should not " + "be an empty string"; print("Got it! I've added this food item:" + LINE_SEPARATOR - + " " + newFood); + + " " + trimString(newFood)); } /** @@ -115,10 +115,10 @@ public void printNewFood(String newFood) { */ public void printFoodList(String allFood) { assert allFood != null : "String representation of all food in food list should not be null"; - if (allFood.trim().length() < 1) { + if (trimStringGetLength(allFood) < 1) { print("DietBook is currently empty."); } else { - print("Here are the food items in DietBook:" + LINE_SEPARATOR + allFood); + print("Here are the food items in DietBook:" + LINE_SEPARATOR + trimString(allFood)); } } @@ -140,11 +140,11 @@ public void printFoodListGivenTimePeriod(String foods, LocalDateTime start, Loca + "of the time period"; String stringStart = stringDateTime(start); String stringEnd = stringDateTime(end); - if (foods.trim().length() < 1) { + if (trimStringGetLength(foods) < 1) { print("No food item was recorded in DietBook between " + stringStart + " and " + stringEnd + "."); } else { print("Here are the food items recorded in DietBook between " + stringStart + " and " + stringEnd - + " :" + LINE_SEPARATOR + foods); + + " :" + LINE_SEPARATOR + trimString(foods)); } } @@ -166,8 +166,8 @@ public String stringDateTime(LocalDateTime dateTime) { */ public void printDatabase(String foodDatabase) { assert foodDatabase != null : "Food database should not be null"; - assert foodDatabase.trim().length() > 0 : "Food database should not be empty"; - print("Here are the food items in the database:" + LINE_SEPARATOR + foodDatabase); + assert trimStringGetLength(foodDatabase) > 0 : "Food database should not be empty"; + print("Here are the food items in the database:" + LINE_SEPARATOR + trimString(foodDatabase)); } /** @@ -177,9 +177,9 @@ public void printDatabase(String foodDatabase) { */ public void printPersonInfo(String personInfo) { assert personInfo != null : "Person information should not be null"; - assert personInfo.trim().length() > 0 : "Person information should not be an empty string"; + assert trimStringGetLength(personInfo) > 0 : "Person information should not be an empty string"; print("Here is your information:" + LINE_SEPARATOR - + personInfo); + + trimString(personInfo)); } /** @@ -250,10 +250,10 @@ public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, in */ public void printDeletedFood(String deletedFood) { assert deletedFood != null : "String representation of the food that was deleted should not be null"; - assert deletedFood.trim().length() > 0 : "String representation of the food that was deleted should" + assert trimStringGetLength(deletedFood) > 0 : "String representation of the food that was deleted should" + " not be an empty string"; print("Noted. I've removed this food item:" + LINE_SEPARATOR - + " " + deletedFood); + + " " + trimString(deletedFood)); } /** @@ -271,8 +271,8 @@ public void printClearFoodListMessage() { */ public void printExitMessage(String name) { assert name != null : "Name should not be null"; - assert name.trim().length() > 0 : "Name should not be an empty string"; - print("Bye " + name + "! Hope to see you again soon!"); + assert trimStringGetLength(name) > 0 : "Name should not be an empty string"; + print("Bye " + trimString(name) + "! Hope to see you again soon!"); } /** @@ -282,8 +282,32 @@ public void printExitMessage(String name) { */ public void printErrorMessage(String errorMessage) { assert errorMessage != null : "Error message should not be null"; - assert errorMessage.trim().length() > 0 : "Error message should not be an empty string"; - print(":( Oh no..." + errorMessage); + assert trimStringGetLength(errorMessage) > 0 : "Error message should not be an empty string"; + print(":( Oh no..." + trimString(errorMessage)); + } + + /** + * Returns an integer representing the length of the string after it has been trimmed for leading and + * trailing spaces. + * + * @param string The string to be trimmed and have its length determined. + * @return An integer representing the length of the string after it has been trimmed for leading and + * trailing spaces. + */ + public int trimStringGetLength(String string) { + assert string != null : "String to trim and have length determined should not be null"; + return trimString(string).length(); + } + + /** + * Returns a string that has been trimmed for leading and trailing spaces. + * + * @param string The string to be trimmed for leading and trailing spaces. + * @return A string that has been trimmed for leading and trailing spaces. + */ + public String trimString(String string) { + assert string != null : "String to trim should not be null"; + return string.trim(); } /** @@ -292,12 +316,14 @@ public void printErrorMessage(String errorMessage) { * @param message The message to show the user. */ public void print(String message) { + assert message != null : "Message to print should not be null"; + assert trimStringGetLength(message) > 0 : "Message to print should not be an empty string"; String divider = "__________________________________________________________________________________________" + "____________________"; System.out.println(divider + LINE_SEPARATOR - + message + LINE_SEPARATOR + + trimString(message) + LINE_SEPARATOR + divider); } From 23c9a75719758aa799fb1de59f3e2b66234215d7 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Fri, 23 Oct 2020 00:57:52 +0800 Subject: [PATCH 117/271] Add JUnit tests for two Ui methods --- src/test/java/seedu/dietbook/UiTest.java | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/test/java/seedu/dietbook/UiTest.java b/src/test/java/seedu/dietbook/UiTest.java index 91076665f1..35314fb5f5 100644 --- a/src/test/java/seedu/dietbook/UiTest.java +++ b/src/test/java/seedu/dietbook/UiTest.java @@ -33,4 +33,54 @@ void stringDateTime_LocalDateTimeWithSeconds_returnsStringOfLocalDateTimeWithout LocalDateTime dateTime = LocalDateTime.parse("2020-10-21T23:59:22"); assertEquals("21 Oct 2020 2359",ui.stringDateTime(dateTime)); } + + @Test + void trimStringGetLength_nullInput_expectAssertionError() { + assertThrows(AssertionError.class, () -> ui.trimStringGetLength(null)); + } + + @Test + void trimStringGetLength_stringWithNoLeadingOrTrailingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength("food")); + } + + @Test + void trimStringGetLength_StringWithLeadingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength(" food")); + } + + @Test + void trimStringGetLength_StringWithTrailingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength("food ")); + } + + @Test + void trimStringGetLength_StringWithLeadingAndTrailingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength(" food ")); + } + + @Test + void trimString_nullInput_expectAssertionError() { + assertThrows(AssertionError.class, () -> ui.trimString(null)); + } + + @Test + void trimString_StringWithLeadingSpaces_returnsStringWithoutLeadingSpaces() { + assertEquals("food", ui.trimString(" food")); + } + + @Test + void trimString_StringWithTrailingSpaces_returnsStringWithoutTrailingSpaces() { + assertEquals("food", ui.trimString("food ")); + } + + @Test + void trimString_StringWithLeadingAndTrailingSpaces_returnsStringWithoutLeadingAndTrailingSpaces() { + assertEquals("food", ui.trimString(" food ")); + } + + @Test + void trimString_StringWithNoLeadingAndTrailingSpaces_returnsString() { + assertEquals("food", ui.trimString("food")); + } } From 79bd2b93ba3a03134cdcf606878afab100f45169 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Fri, 23 Oct 2020 13:16:33 +0800 Subject: [PATCH 118/271] Improved input parser --- src/main/java/seedu/duke/Parser.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index f56932e4d1..00e9effc37 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -48,11 +48,11 @@ private static String getCommandParam(String userInput) throws DietException { } else { switch (command) { case COMMAND_NAME: - return userInput.split(" ")[1]; + return userInput.split("name")[1].trim(); case COMMAND_CALCULATE: for (String param: PARAM_CALCULATE) { if (userInput.contains(param)) { - return userInput.split(" ")[1]; + return userInput.split("calculate")[1].trim(); } } throw new DietException("Incorrect nutrient type"); @@ -249,11 +249,11 @@ public static void parse(String userInput, Manager manager, Ui ui) throws DietEx if (getCommandParam(userInput).equals("all")) { ui.printAllNutrientIntake(calculator.calculateCalorie(), calculator.calculateCarb(), calculator.calculateProtein(), calculator.calculateFat()); - } else if (getCommandParam(userInput).contains("calorie")) { + } else if (getCommandParam(userInput).equals("calorie")) { ui.printCalorieIntake(calculator.calculateCalorie()); - } else if (getCommandParam(userInput).contains("carbohydrate")) { + } else if (getCommandParam(userInput).equals("carbohydrate")) { ui.printCarbohydrateIntake(calculator.calculateCarb()); - } else if (getCommandParam(userInput).contains("protein")) { + } else if (getCommandParam(userInput).equals("protein")) { ui.printProteinIntake(calculator.calculateProtein()); } else { ui.printFatIntake(calculator.calculateFat()); From b6b556a56df654f2fc116f2294fb0d8573e89271 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 23 Oct 2020 15:31:07 +0800 Subject: [PATCH 119/271] Implement FoodSaveLoadManager This acts as a inbetween between save and load classes and Food List --- .../java/seedu/duke/saveload/EmptyLoader.java | 26 +++++++ .../java/seedu/duke/saveload/FileLoader.java | 68 ++++++++++++++++ .../duke/saveload/FoodSaveLoadManager.java | 78 +++++++++++++++++++ src/main/java/seedu/duke/saveload/Loader.java | 67 ++-------------- src/main/java/seedu/duke/saveload/Saver.java | 25 +++++- .../saveload/FoodSaveLoadManagerTest.java | 62 +++++++++++++++ .../seedu/duke/saveload/SaveLoadFileTest.java | 18 ++--- 7 files changed, 271 insertions(+), 73 deletions(-) create mode 100644 src/main/java/seedu/duke/saveload/EmptyLoader.java create mode 100644 src/main/java/seedu/duke/saveload/FileLoader.java create mode 100644 src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java create mode 100644 src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java diff --git a/src/main/java/seedu/duke/saveload/EmptyLoader.java b/src/main/java/seedu/duke/saveload/EmptyLoader.java new file mode 100644 index 0000000000..97cc788644 --- /dev/null +++ b/src/main/java/seedu/duke/saveload/EmptyLoader.java @@ -0,0 +1,26 @@ +package seedu.duke.saveload; + +import java.util.Optional; + +/** + * Place holder class for Loader, does not do anything + * Throws IllegalAccessException if there is any attempt to access this class. + */ +public class EmptyLoader extends Loader{ + protected EmptyLoader(){ } + + @Override + public Optional get(int xposition, int yposition) throws IllegalAccessException { + throw new IllegalAccessException("Do not attempt to get from an empty loader!"); + } + + @Override + int getHeight() throws IllegalAccessException { + throw new IllegalAccessException("Do not attempt to get from an empty loader!"); + } + + @Override + int getWidth() throws IllegalAccessException { + throw new IllegalAccessException("Do not attempt to get from an empty loader!"); + } +} diff --git a/src/main/java/seedu/duke/saveload/FileLoader.java b/src/main/java/seedu/duke/saveload/FileLoader.java new file mode 100644 index 0000000000..88d92b6235 --- /dev/null +++ b/src/main/java/seedu/duke/saveload/FileLoader.java @@ -0,0 +1,68 @@ +package seedu.duke.saveload; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Optional; +import java.util.Scanner; + +/** + * Handles reading of stored text file. + * Note: the first five fields must be same + */ +public class FileLoader extends Loader{ + private static final String ROOT_DIRECTORY = System.getProperty("user.home"); + private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; + private static final String EMPTY_SYMBOL = "%NULL&!!LL"; + private static final String SEPARATOR_SYMBOL = "&%SEPERATOR%AAA%"; + private static final String FILE_EXTENSION = ".txt"; + + private final String[][] entries; + private final int width; + private final int height; + + + protected FileLoader(String folderName, String fileName) throws FileNotFoundException { + File file = new File(BASE_FOLDER_NAME + File.separator + folderName + + File.separator + fileName + FILE_EXTENSION); + Scanner reader = new Scanner(file); + width = Integer.parseInt(reader.nextLine()); + height = Integer.parseInt(reader.nextLine()); + entries = new String[height][width]; + String[] line; + for (int j = 0; j < height; j++) { + line = reader.nextLine().split(SEPARATOR_SYMBOL); + if (width >= 0) { + System.arraycopy(line, 1, entries[j], 0, width); + } + } + } + + /** + * Get the String entry stored at the specified position in the table if it is present. + * @param xposition the x position in the table from 1 to the table width + * @param yposition the y position in the table from 1 to the table height + * @return Optional of the String. The Optional is empty is no entry is stored + * @throws IndexOutOfBoundsException if the x or y given is not as above + */ + public Optional get(int xposition, int yposition) throws IndexOutOfBoundsException { + try { + if (this.entries[yposition - 1][xposition - 1].equals(EMPTY_SYMBOL)) { + return Optional.empty(); + } else { + return Optional.of(this.entries[yposition - 1][xposition - 1]); + } + } catch (ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" + + "saver table!"); + } + } + + + public int getHeight() { + return height; + } + + public int getWidth() { + return width; + } +} diff --git a/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java b/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java new file mode 100644 index 0000000000..2154f53b55 --- /dev/null +++ b/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java @@ -0,0 +1,78 @@ +package seedu.duke.saveload; + +import seedu.duke.food.Food; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; + +/** + * Server as a in-between class between loader saver and food list + */ +public class FoodSaveLoadManager { + private static final int DEFAULT_SAVER_WIDTH = 5; + private static final int DEFAULT_SAVER_HEIGHT = 10; + + private static final String FOOD_FOLDER_NAME = "Food%%UOISDN%%FOLDER"; + + private static final String DEFAULT_NAME = "MISSING NAME"; + private static final String DEFAULT_NUTRITION_VALUE = "0"; + + private Saver saver; + private Loader fileLoader; + + public FoodSaveLoadManager() { + this.saver = new Saver(DEFAULT_SAVER_WIDTH, DEFAULT_SAVER_HEIGHT); + this.fileLoader = Loader.loadEmpty(); + } + + /** + * Call this function to load a food file + * @param fileName name of file + * @throws FileNotFoundException if there is no such save file + */ + public void load(String fileName) throws FileNotFoundException { + this.fileLoader = Loader.load(FOOD_FOLDER_NAME, fileName); + } + + public void clearLoader(){ + this.fileLoader = Loader.loadEmpty(); + } + + /** + * Returns a list of food that is stored in the loader + * @return + * @throws IllegalAccessException When this method is called without first loading a food file + */ + public List getFoodList() throws IllegalAccessException { + ArrayList foodlist = new ArrayList<>(); + Food newFood; + for (int j = 1; j < fileLoader.getHeight() + 1; j++) { + newFood = new Food( + fileLoader.get(j,1).orElse(DEFAULT_NAME), + Integer.parseInt(fileLoader.get(j,2).orElse(DEFAULT_NUTRITION_VALUE)), + Integer.parseInt(fileLoader.get(j,3).orElse(DEFAULT_NUTRITION_VALUE)), + Integer.parseInt(fileLoader.get(j,4).orElse(DEFAULT_NUTRITION_VALUE)), + Integer.parseInt(fileLoader.get(j,5).orElse(DEFAULT_NUTRITION_VALUE))); + foodlist.add(newFood); + } + return foodlist; + } + + /** + * saves a input food list to a file + * @param fileName the name of the file to save to + * @param foodlist list of food objects to be saved + */ + public void save(String fileName, List foodlist){ + this.saver.resetSize(DEFAULT_SAVER_WIDTH, foodlist.size()); + for (int j = 1; j < foodlist.size() + 1; j++){ + saver.add(foodlist.get(j-1).getName(), 1, j); + saver.add(Integer.toString(foodlist.get(j-1).getCalorie()), 2, j); + saver.add(Integer.toString(foodlist.get(j-1).getCarbohydrate()), 3, j); + saver.add(Integer.toString(foodlist.get(j-1).getProtein()), 4, j); + saver.add(Integer.toString(foodlist.get(j-1).getFats()), 5, j); + } + saver.save(FOOD_FOLDER_NAME, fileName); + } +} diff --git a/src/main/java/seedu/duke/saveload/Loader.java b/src/main/java/seedu/duke/saveload/Loader.java index 72311fd1b1..15aee3b7e4 100644 --- a/src/main/java/seedu/duke/saveload/Loader.java +++ b/src/main/java/seedu/duke/saveload/Loader.java @@ -1,71 +1,18 @@ package seedu.duke.saveload; -import java.io.File; import java.io.FileNotFoundException; import java.util.Optional; -import java.util.Scanner; - -/** - * Handles reading of stored text file. - * Note: the first five fields must be same - */ -public class Loader { - private static final String ROOT_DIRECTORY = System.getProperty("user.home"); - private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; - private static final String EMPTY_SYMBOL = "%NULL&!!LL"; - private static final String SEPARATOR_SYMBOL = "&%SEPERATOR%AAA%"; - private static final String FILE_EXTENSION = ".txt"; - - private final String[][] entries; - private final int width; - private final int height; +abstract class Loader { public static Loader load(String folderName, String fileName) throws FileNotFoundException { - return new Loader(folderName, fileName); - } - - private Loader(String folderName, String fileName) throws FileNotFoundException { - File file = new File(BASE_FOLDER_NAME + File.separator + folderName - + File.separator + fileName + FILE_EXTENSION); - Scanner reader = new Scanner(file); - width = Integer.parseInt(reader.nextLine()); - height = Integer.parseInt(reader.nextLine()); - entries = new String[height][width]; - String[] line; - for (int j = 0; j < height; j++) { - line = reader.nextLine().split(SEPARATOR_SYMBOL); - if (width >= 0) { - System.arraycopy(line, 1, entries[j], 0, width); - } - } + return new FileLoader(folderName, fileName); } - /** - * Get the String entry stored at the specified position in the table if it is present. - * @param xposition the x position in the table from 1 to the table width - * @param yposition the y position in the table from 1 to the table height - * @return Optional of the String. The Optional is empty is no entry is stored - * @throws IndexOutOfBoundsException if the x or y given is not as above - */ - public Optional get(int xposition, int yposition) throws IndexOutOfBoundsException { - try { - if (this.entries[yposition - 1][xposition - 1].equals(EMPTY_SYMBOL)) { - return Optional.empty(); - } else { - return Optional.of(this.entries[yposition - 1][xposition - 1]); - } - } catch (ArrayIndexOutOfBoundsException e) { - throw new IndexOutOfBoundsException("The x or y position provided must be within the the dimensions of the" - + "saver table!"); - } + public static Loader loadEmpty(){ + return new EmptyLoader(); } - - public int getHeight() { - return height; - } - - public int getWidth() { - return width; - } + abstract Optional get(int xposition, int yposition) throws IllegalAccessException; + abstract int getHeight() throws IllegalAccessException; + abstract int getWidth() throws IllegalAccessException; } diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/duke/saveload/Saver.java index 720b0d1ae1..73ea31814d 100644 --- a/src/main/java/seedu/duke/saveload/Saver.java +++ b/src/main/java/seedu/duke/saveload/Saver.java @@ -22,15 +22,22 @@ public class Saver { rootDirectory.mkdir(); } - private final String[][] entries; - private final int height; - private final int width; + private String[][] entries; + private int height; + private int width; public Saver(int width, int height) { + setWidthAndHeight(width,height); + initEntries(); + } + + private void setWidthAndHeight(int width, int height){ this.height = height; this.width = width; - this.entries = new String[height][width]; + } + private void initEntries(){ + this.entries = new String[height][width]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { entries[j][i] = EMPTY_SYMBOL; @@ -46,6 +53,16 @@ public int getHeight() { return height; } + /** + * Clears the entire table and set it to the new size + * @param newWidth the new width + * @param newHeight the new height + */ + public void resetSize(int newWidth, int newHeight){ + setWidthAndHeight(newWidth, newHeight); + initEntries(); + } + /** * Adds the string provided to the position x,y on the table. * @param entry the entry to be provided into this position diff --git a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java new file mode 100644 index 0000000000..bbae66f558 --- /dev/null +++ b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java @@ -0,0 +1,62 @@ +package seedu.duke.saveload; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.duke.food.Food; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; + +public class FoodSaveLoadManagerTest { + private FoodSaveLoadManager testManager; + private List inputFoodList; + private Food food1; + private Food food2; + private Food food3; + private Food food4; + + private List testFoodList; + + @BeforeEach + private void setUp() throws FileNotFoundException { + testManager = new FoodSaveLoadManager(); + inputFoodList = new ArrayList<>(); + food1 = new Food("Apple", 20000,20,5,1); + food2 = new Food("Peach", 3000,50,2,3); + food3 = new Food("Bacon", 1000,20,10,99); + food4 = new Food("Silicon", 500,100,50,10); + + inputFoodList.add(food1); + inputFoodList.add(food2); + inputFoodList.add(food3); + inputFoodList.add(food4); + + testManager.save("Victor's Food List", inputFoodList); + testManager.load("Victor's Food List"); + } + + @Test + private void getFoodList_WithoutLoading() throws Exception { + testManager.clearLoader(); + assertThrows(IllegalAccessException.class ,() -> testManager.getFoodList()); + } + + @Test + private void getFoodList_FileDoesNotExist() throws Exception{ + assertThrows(FileNotFoundException.class, () -> testManager.load("Over the Moon!")); + } + + @Test + private void getFoodListTest() throws Exception { + testFoodList = testManager.getFoodList(); + assertEquals(4, testFoodList.size()); + assertEquals("Apple", testFoodList.get(0).getName()); + assertEquals(20000, testFoodList.get(0).getCalorie()); + assertEquals("Silicon", testFoodList.get(3).getName()); + assertEquals(500, testFoodList.get(3).getCalorie()); + } +} diff --git a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java index 7f9cd5acaf..1b09acfb81 100644 --- a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java +++ b/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java @@ -3,7 +3,7 @@ import java.io.FileNotFoundException; public class SaveLoadFileTest { - public static void main(String[] args) throws FileNotFoundException { + public static void main(String[] args) throws FileNotFoundException, IllegalAccessException { Saver saver = new Saver(10, 6); saver.add("banana", 5, 2); saver.add("pineapple", 7, 1); @@ -11,13 +11,13 @@ public static void main(String[] args) throws FileNotFoundException { saver.add("beetles", 1, 4); saver.save("save_load_test","test1"); - Loader loader; - loader = Loader.load("save_load_test","test1"); - loader.get(5, 2).ifPresent(System.out::println); - loader.get(7, 1).ifPresent(System.out::println); - loader.get(2, 3).ifPresent(System.out::println); - loader.get(1, 4).ifPresent(System.out::println); - loader.get(1, 3).ifPresent(System.out::println); - loader.get(10, 6).ifPresent(System.out::println); + Loader fileLoader; + fileLoader = Loader.load("save_load_test","test1"); + fileLoader.get(5, 2).ifPresent(System.out::println); + fileLoader.get(7, 1).ifPresent(System.out::println); + fileLoader.get(2, 3).ifPresent(System.out::println); + fileLoader.get(1, 4).ifPresent(System.out::println); + fileLoader.get(1, 3).ifPresent(System.out::println); + fileLoader.get(10, 6).ifPresent(System.out::println); } } From a1da7e07a1e12ef860387e1a281c60ab7fdb344a Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 23 Oct 2020 15:44:36 +0800 Subject: [PATCH 120/271] debug FoodSaveLoadManager Add manual test Passed manual test --- .../duke/saveload/FoodSaveLoadManager.java | 10 ++--- .../FoodSaveLoadManagerManualTest.java | 42 +++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java diff --git a/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java b/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java index 2154f53b55..cc83665acf 100644 --- a/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java +++ b/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java @@ -49,11 +49,11 @@ public List getFoodList() throws IllegalAccessException { Food newFood; for (int j = 1; j < fileLoader.getHeight() + 1; j++) { newFood = new Food( - fileLoader.get(j,1).orElse(DEFAULT_NAME), - Integer.parseInt(fileLoader.get(j,2).orElse(DEFAULT_NUTRITION_VALUE)), - Integer.parseInt(fileLoader.get(j,3).orElse(DEFAULT_NUTRITION_VALUE)), - Integer.parseInt(fileLoader.get(j,4).orElse(DEFAULT_NUTRITION_VALUE)), - Integer.parseInt(fileLoader.get(j,5).orElse(DEFAULT_NUTRITION_VALUE))); + fileLoader.get(1,j).orElse(DEFAULT_NAME), + Integer.parseInt(fileLoader.get(2,j).orElse(DEFAULT_NUTRITION_VALUE)), + Integer.parseInt(fileLoader.get(3,j).orElse(DEFAULT_NUTRITION_VALUE)), + Integer.parseInt(fileLoader.get(4,j).orElse(DEFAULT_NUTRITION_VALUE)), + Integer.parseInt(fileLoader.get(5,j).orElse(DEFAULT_NUTRITION_VALUE))); foodlist.add(newFood); } return foodlist; diff --git a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java new file mode 100644 index 0000000000..c90a08ad67 --- /dev/null +++ b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java @@ -0,0 +1,42 @@ +package seedu.duke.saveload; + +import seedu.duke.food.Food; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; + +public class FoodSaveLoadManagerManualTest { + static private FoodSaveLoadManager testManager; + static private List inputFoodList; + static private Food food1; + static private Food food2; + static private Food food3; + static private Food food4; + + static private List testFoodList; + + public static void main(String[] args) throws FileNotFoundException, IllegalAccessException { + testManager = new FoodSaveLoadManager(); + inputFoodList = new ArrayList<>(); + food1 = new Food("Apple", 20000,20,5,1); + food2 = new Food("Peach", 3000,50,2,3); + food3 = new Food("Bacon", 1000,20,10,99); + food4 = new Food("Silicon", 500,100,50,10); + + inputFoodList.add(food1); + inputFoodList.add(food2); + inputFoodList.add(food3); + inputFoodList.add(food4); + + testManager.save("Victor's Food List", inputFoodList); + testManager.load("Victor's Food List"); + + testFoodList = testManager.getFoodList(); + + System.out.println(testFoodList.get(0).getName()); + System.out.println(testFoodList.get(0).getCalorie()); + System.out.println(testFoodList.get(3).getName()); + System.out.println(testFoodList.get(3).getCalorie()); + } +} From 4ba066e2fe1edefe3790ecce22393bd2d4f71a06 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 23 Oct 2020 15:58:26 +0800 Subject: [PATCH 121/271] clear check style tests --- .../java/seedu/duke/saveload/EmptyLoader.java | 5 ++-- .../java/seedu/duke/saveload/FileLoader.java | 2 +- .../duke/saveload/FoodSaveLoadManager.java | 26 +++++++++---------- src/main/java/seedu/duke/saveload/Loader.java | 4 ++- src/main/java/seedu/duke/saveload/Saver.java | 8 +++--- .../FoodSaveLoadManagerManualTest.java | 23 +++++----------- .../saveload/FoodSaveLoadManagerTest.java | 4 +-- 7 files changed, 33 insertions(+), 39 deletions(-) diff --git a/src/main/java/seedu/duke/saveload/EmptyLoader.java b/src/main/java/seedu/duke/saveload/EmptyLoader.java index 97cc788644..96e1f82240 100644 --- a/src/main/java/seedu/duke/saveload/EmptyLoader.java +++ b/src/main/java/seedu/duke/saveload/EmptyLoader.java @@ -6,8 +6,9 @@ * Place holder class for Loader, does not do anything * Throws IllegalAccessException if there is any attempt to access this class. */ -public class EmptyLoader extends Loader{ - protected EmptyLoader(){ } +public class EmptyLoader extends Loader { + protected EmptyLoader(){ + } @Override public Optional get(int xposition, int yposition) throws IllegalAccessException { diff --git a/src/main/java/seedu/duke/saveload/FileLoader.java b/src/main/java/seedu/duke/saveload/FileLoader.java index 88d92b6235..70e20b7c72 100644 --- a/src/main/java/seedu/duke/saveload/FileLoader.java +++ b/src/main/java/seedu/duke/saveload/FileLoader.java @@ -9,7 +9,7 @@ * Handles reading of stored text file. * Note: the first five fields must be same */ -public class FileLoader extends Loader{ +public class FileLoader extends Loader { private static final String ROOT_DIRECTORY = System.getProperty("user.home"); private static final String BASE_FOLDER_NAME = ROOT_DIRECTORY + File.separator + "dietbook"; private static final String EMPTY_SYMBOL = "%NULL&!!LL"; diff --git a/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java b/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java index cc83665acf..6e070a7893 100644 --- a/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java +++ b/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java @@ -7,7 +7,7 @@ import java.util.List; /** - * Server as a in-between class between loader saver and food list + * Server as a in-between class between loader saver and food list. */ public class FoodSaveLoadManager { private static final int DEFAULT_SAVER_WIDTH = 5; @@ -27,7 +27,7 @@ public FoodSaveLoadManager() { } /** - * Call this function to load a food file + * Call this function to load a food file. * @param fileName name of file * @throws FileNotFoundException if there is no such save file */ @@ -35,13 +35,13 @@ public void load(String fileName) throws FileNotFoundException { this.fileLoader = Loader.load(FOOD_FOLDER_NAME, fileName); } - public void clearLoader(){ + public void clearLoader() { this.fileLoader = Loader.loadEmpty(); } /** - * Returns a list of food that is stored in the loader - * @return + * Returns a list of food that is stored in the loader. + * @return the food list obtained from the data in the loaded file * @throws IllegalAccessException When this method is called without first loading a food file */ public List getFoodList() throws IllegalAccessException { @@ -60,18 +60,18 @@ public List getFoodList() throws IllegalAccessException { } /** - * saves a input food list to a file + * saves a input food list to a file. * @param fileName the name of the file to save to * @param foodlist list of food objects to be saved */ - public void save(String fileName, List foodlist){ + public void save(String fileName, List foodlist) { this.saver.resetSize(DEFAULT_SAVER_WIDTH, foodlist.size()); - for (int j = 1; j < foodlist.size() + 1; j++){ - saver.add(foodlist.get(j-1).getName(), 1, j); - saver.add(Integer.toString(foodlist.get(j-1).getCalorie()), 2, j); - saver.add(Integer.toString(foodlist.get(j-1).getCarbohydrate()), 3, j); - saver.add(Integer.toString(foodlist.get(j-1).getProtein()), 4, j); - saver.add(Integer.toString(foodlist.get(j-1).getFats()), 5, j); + for (int j = 1; j < foodlist.size() + 1; j++) { + saver.add(foodlist.get(j - 1).getName(), 1, j); + saver.add(Integer.toString(foodlist.get(j - 1).getCalorie()), 2, j); + saver.add(Integer.toString(foodlist.get(j - 1).getCarbohydrate()), 3, j); + saver.add(Integer.toString(foodlist.get(j - 1).getProtein()), 4, j); + saver.add(Integer.toString(foodlist.get(j - 1).getFats()), 5, j); } saver.save(FOOD_FOLDER_NAME, fileName); } diff --git a/src/main/java/seedu/duke/saveload/Loader.java b/src/main/java/seedu/duke/saveload/Loader.java index 15aee3b7e4..076a5e7112 100644 --- a/src/main/java/seedu/duke/saveload/Loader.java +++ b/src/main/java/seedu/duke/saveload/Loader.java @@ -8,11 +8,13 @@ public static Loader load(String folderName, String fileName) throws FileNotFoun return new FileLoader(folderName, fileName); } - public static Loader loadEmpty(){ + public static Loader loadEmpty() { return new EmptyLoader(); } abstract Optional get(int xposition, int yposition) throws IllegalAccessException; + abstract int getHeight() throws IllegalAccessException; + abstract int getWidth() throws IllegalAccessException; } diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/duke/saveload/Saver.java index 73ea31814d..8c2f5075ef 100644 --- a/src/main/java/seedu/duke/saveload/Saver.java +++ b/src/main/java/seedu/duke/saveload/Saver.java @@ -31,12 +31,12 @@ public Saver(int width, int height) { initEntries(); } - private void setWidthAndHeight(int width, int height){ + private void setWidthAndHeight(int width, int height) { this.height = height; this.width = width; } - private void initEntries(){ + private void initEntries() { this.entries = new String[height][width]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { @@ -54,11 +54,11 @@ public int getHeight() { } /** - * Clears the entire table and set it to the new size + * Clears the entire table and set it to the new size. * @param newWidth the new width * @param newHeight the new height */ - public void resetSize(int newWidth, int newHeight){ + public void resetSize(int newWidth, int newHeight) { setWidthAndHeight(newWidth, newHeight); initEntries(); } diff --git a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java index c90a08ad67..4f07f241f0 100644 --- a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java +++ b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java @@ -7,22 +7,13 @@ import java.util.List; public class FoodSaveLoadManagerManualTest { - static private FoodSaveLoadManager testManager; - static private List inputFoodList; - static private Food food1; - static private Food food2; - static private Food food3; - static private Food food4; - - static private List testFoodList; - public static void main(String[] args) throws FileNotFoundException, IllegalAccessException { - testManager = new FoodSaveLoadManager(); - inputFoodList = new ArrayList<>(); - food1 = new Food("Apple", 20000,20,5,1); - food2 = new Food("Peach", 3000,50,2,3); - food3 = new Food("Bacon", 1000,20,10,99); - food4 = new Food("Silicon", 500,100,50,10); + final FoodSaveLoadManager testManager = new FoodSaveLoadManager(); + List inputFoodList = new ArrayList<>(); + Food food1 = new Food("Apple", 20000, 20, 5, 1); + Food food2 = new Food("Peach", 3000, 50, 2, 3); + Food food3 = new Food("Bacon", 1000, 20, 10, 99); + Food food4 = new Food("Silicon", 500, 100, 50, 10); inputFoodList.add(food1); inputFoodList.add(food2); @@ -32,7 +23,7 @@ public static void main(String[] args) throws FileNotFoundException, IllegalAcce testManager.save("Victor's Food List", inputFoodList); testManager.load("Victor's Food List"); - testFoodList = testManager.getFoodList(); + List testFoodList = testManager.getFoodList(); System.out.println(testFoodList.get(0).getName()); System.out.println(testFoodList.get(0).getCalorie()); diff --git a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java index bbae66f558..e286b9bb45 100644 --- a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java +++ b/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java @@ -42,11 +42,11 @@ private void setUp() throws FileNotFoundException { @Test private void getFoodList_WithoutLoading() throws Exception { testManager.clearLoader(); - assertThrows(IllegalAccessException.class ,() -> testManager.getFoodList()); + assertThrows(IllegalAccessException.class, () -> testManager.getFoodList()); } @Test - private void getFoodList_FileDoesNotExist() throws Exception{ + private void getFoodList_FileDoesNotExist() throws Exception { assertThrows(FileNotFoundException.class, () -> testManager.load("Over the Moon!")); } From 7d084bb3830e9a91dafe33537a0e31a3a2673cb5 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Fri, 23 Oct 2020 16:19:14 +0800 Subject: [PATCH 122/271] copy food over to test --- src/test/java/seedu/duke/food/Food.java | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/test/java/seedu/duke/food/Food.java diff --git a/src/test/java/seedu/duke/food/Food.java b/src/test/java/seedu/duke/food/Food.java new file mode 100644 index 0000000000..c43d8f0384 --- /dev/null +++ b/src/test/java/seedu/duke/food/Food.java @@ -0,0 +1,44 @@ +package seedu.duke.food; + + +public class Food { + private final String name; + private final int calorie; + private final int carbohydrate; + private final int protein; + private final int fats; + + public Food(String name, int calorie, int carbohydrate, int protein, int fats) { + this.name = name; + this.calorie = calorie; + this.carbohydrate = carbohydrate; + this.protein = protein; + this.fats = fats; + } + + public int getFats() { + return fats; + } + + public String getName() { + return name; + } + + public int getCalorie() { + return calorie; + } + + public int getCarbohydrate() { + return carbohydrate; + } + + public int getProtein() { + return protein; + } + + @Override + public String toString() { + return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate + + " | fats : " + fats; + } +} From 6002a6dd1fb141ae528c90329d7861a362273963 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Fri, 23 Oct 2020 22:00:57 +0800 Subject: [PATCH 123/271] refactor location --- src/main/java/seedu/dietbook/Manager.java | 2 +- src/main/java/seedu/dietbook/Parser.java | 2 +- src/main/java/seedu/{ => dietbook}/calculator/Calculator.java | 2 +- .../java/seedu/{ => dietbook}/calculator/CalculatorTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/seedu/{ => dietbook}/calculator/Calculator.java (98%) rename src/test/java/seedu/{ => dietbook}/calculator/CalculatorTest.java (98%) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 439b788e06..a64094e32b 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -3,7 +3,7 @@ import seedu.dietbook.list.FoodList; import seedu.dietbook.person.ActivityLevel; import seedu.dietbook.person.Person; -import seedu.calculator.Calculator; +import seedu.dietbook.calculator.Calculator; import seedu.dietbook.database.DataBase; import seedu.dietbook.person.Gender; diff --git a/src/main/java/seedu/dietbook/Parser.java b/src/main/java/seedu/dietbook/Parser.java index b15f65b1a1..2486e212be 100644 --- a/src/main/java/seedu/dietbook/Parser.java +++ b/src/main/java/seedu/dietbook/Parser.java @@ -1,6 +1,6 @@ package seedu.dietbook; -import seedu.calculator.Calculator; +import seedu.dietbook.calculator.Calculator; import seedu.dietbook.list.FoodList; import seedu.dietbook.person.Gender; import seedu.dietbook.person.ActivityLevel; diff --git a/src/main/java/seedu/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java similarity index 98% rename from src/main/java/seedu/calculator/Calculator.java rename to src/main/java/seedu/dietbook/calculator/Calculator.java index fe7c288242..bcd6208c32 100644 --- a/src/main/java/seedu/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -1,4 +1,4 @@ -package seedu.calculator; +package seedu.dietbook.calculator; import seedu.dietbook.food.Food; diff --git a/src/test/java/seedu/calculator/CalculatorTest.java b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java similarity index 98% rename from src/test/java/seedu/calculator/CalculatorTest.java rename to src/test/java/seedu/dietbook/calculator/CalculatorTest.java index 3c4502b25f..576c6e3995 100644 --- a/src/test/java/seedu/calculator/CalculatorTest.java +++ b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java @@ -1,4 +1,4 @@ -package seedu.calculator; +package seedu.dietbook.calculator; import org.junit.jupiter.api.Test; import seedu.dietbook.food.Food; From d93f653c54725768771199cdd6ef186a632ef042 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Sat, 24 Oct 2020 04:32:49 +0800 Subject: [PATCH 124/271] Major OOP Update - created the entire command class -> 11 commands - shift parse -> manager (renamed to manage) - removed divider line from main - main execution --- src/main/java/seedu/dietbook/DietBook.java | 7 +- src/main/java/seedu/dietbook/Manager.java | 53 ++++++++++- .../seedu/dietbook/command/AddCommand.java | 18 ++++ .../dietbook/command/CalculateCommand.java | 41 +++++++++ .../seedu/dietbook/command/ClearCommand.java | 12 +++ .../java/seedu/dietbook/command/Command.java | 9 ++ .../seedu/dietbook/command/DataCommand.java | 13 +++ .../seedu/dietbook/command/DeleteCommand.java | 23 +++++ .../seedu/dietbook/command/ExitCommand.java | 13 +++ .../seedu/dietbook/command/HelpCommand.java | 11 +++ .../seedu/dietbook/command/InfoCommand.java | 20 +++++ .../seedu/dietbook/command/ListCommand.java | 11 +++ .../seedu/dietbook/command/NameCommand.java | 20 +++++ .../dietbook/command/UserinfoCommand.java | 11 +++ .../{ => exception}/DietException.java | 2 +- .../seedu/dietbook/{ => parser}/Parser.java | 89 ++----------------- 16 files changed, 266 insertions(+), 87 deletions(-) create mode 100644 src/main/java/seedu/dietbook/command/AddCommand.java create mode 100644 src/main/java/seedu/dietbook/command/CalculateCommand.java create mode 100644 src/main/java/seedu/dietbook/command/ClearCommand.java create mode 100644 src/main/java/seedu/dietbook/command/Command.java create mode 100644 src/main/java/seedu/dietbook/command/DataCommand.java create mode 100644 src/main/java/seedu/dietbook/command/DeleteCommand.java create mode 100644 src/main/java/seedu/dietbook/command/ExitCommand.java create mode 100644 src/main/java/seedu/dietbook/command/HelpCommand.java create mode 100644 src/main/java/seedu/dietbook/command/InfoCommand.java create mode 100644 src/main/java/seedu/dietbook/command/ListCommand.java create mode 100644 src/main/java/seedu/dietbook/command/NameCommand.java create mode 100644 src/main/java/seedu/dietbook/command/UserinfoCommand.java rename src/main/java/seedu/dietbook/{ => exception}/DietException.java (85%) rename src/main/java/seedu/dietbook/{ => parser}/Parser.java (66%) diff --git a/src/main/java/seedu/dietbook/DietBook.java b/src/main/java/seedu/dietbook/DietBook.java index 347ca85aa8..4da58f94c2 100644 --- a/src/main/java/seedu/dietbook/DietBook.java +++ b/src/main/java/seedu/dietbook/DietBook.java @@ -4,6 +4,8 @@ import java.io.IOException; import seedu.dietbook.database.DataBase; import seedu.dietbook.list.FoodList; +import seedu.dietbook.exception.DietException; +import seedu.dietbook.command.Command; public class DietBook { private FoodList foodList; @@ -22,11 +24,10 @@ public static void main(String[] args) throws FileNotFoundException { while (!isExit) { try { String userInput = dietBook.manager.readCommand(); - Parser.parse(userInput, dietBook.manager, dietBook.ui); + Command c = dietBook.manager.manage(userInput); + c.execute(dietBook.manager, dietBook.ui); } catch (DietException e) { dietBook.ui.printErrorMessage(e.getMessage()); - } finally { - System.out.println("__________________"); } } } diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 439b788e06..0e33b62f1d 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -1,16 +1,17 @@ package seedu.dietbook; +import seedu.dietbook.command.*; import seedu.dietbook.list.FoodList; import seedu.dietbook.person.ActivityLevel; import seedu.dietbook.person.Person; import seedu.calculator.Calculator; import seedu.dietbook.database.DataBase; import seedu.dietbook.person.Gender; - +import seedu.dietbook.exception.DietException; +import seedu.dietbook.parser.Parser; import java.util.Scanner; - public class Manager { private Person person; private FoodList foodList; @@ -19,6 +20,18 @@ public class Manager { private Calculator calculator; private static Scanner s = new Scanner(System.in); + public static final String COMMAND_ADD = "add"; + public static final String COMMAND_CALCULATE = "calculate"; + public static final String COMMAND_CLEAR = "clear"; + public static final String COMMAND_DATA = "data"; + public static final String COMMAND_DELETE = "delete"; + public static final String COMMAND_EXIT = "exit"; + public static final String COMMAND_HELP = "help"; + public static final String COMMAND_INFO = "info"; + public static final String COMMAND_LIST = "list"; + public static final String COMMAND_NAME = "name"; + public static final String COMMAND_USERINFO = "userinfo"; + public Manager(FoodList foodlist, DataBase dataBase) { this.name = "John Doe"; this.person = new Person(this.name, Gender.MALE, 0,0,0,0, ActivityLevel.LOW); @@ -64,4 +77,40 @@ public void setName(String name) { this.name = name; } + /** + * Makes sense of the user input and carries out the functions according to the command given. + * @param userInput user input. + * @throws DietException when the program does not recognize the command given. + */ + public Command manage(String userInput) throws DietException { + Calculator calculator = this.calculator; + switch (Parser.getCommand(userInput)) { + case COMMAND_ADD: + return new AddCommand(Parser.getProcessedAdd(userInput, getFoodList())); + case COMMAND_CALCULATE: + return new CalculateCommand(calculator.calculateCalorie(), calculator.calculateCarb(), + calculator.calculateProtein(), calculator.calculateFat(), Parser.getCommandParam(userInput)); + case COMMAND_CLEAR: + return new ClearCommand(); + case COMMAND_DATA: + return new DataCommand(); + case COMMAND_DELETE: + return new DeleteCommand(Parser.getCommandIndex(userInput)); + case COMMAND_EXIT: + return new ExitCommand(); + case COMMAND_HELP: + return new HelpCommand(); + case COMMAND_INFO: + return new InfoCommand(userInput); + case COMMAND_LIST: + return new ListCommand(); + case COMMAND_NAME: + return new NameCommand(Parser.getCommandParam(userInput)); + case COMMAND_USERINFO: + return new UserinfoCommand(); + default: + throw new DietException("There's no such command!"); + } + } + } diff --git a/src/main/java/seedu/dietbook/command/AddCommand.java b/src/main/java/seedu/dietbook/command/AddCommand.java new file mode 100644 index 0000000000..6a7b6a7524 --- /dev/null +++ b/src/main/java/seedu/dietbook/command/AddCommand.java @@ -0,0 +1,18 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class AddCommand extends Command { + String foodName; + + public AddCommand(String foodName) { + this.foodName = foodName; + } + + @Override + public void execute(Manager manager, Ui ui) { + ui.printNewFood(this.foodName); + manager.setCalculator(); + } +} diff --git a/src/main/java/seedu/dietbook/command/CalculateCommand.java b/src/main/java/seedu/dietbook/command/CalculateCommand.java new file mode 100644 index 0000000000..6884bf315b --- /dev/null +++ b/src/main/java/seedu/dietbook/command/CalculateCommand.java @@ -0,0 +1,41 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class CalculateCommand extends Command { + int calorie; + int carb; + int protein; + int fat; + String param; + + public CalculateCommand(int calorie, int carb, int protein, int fat, String param) { + this.calorie = calorie; + this.carb = carb; + this.protein = protein; + this.fat = fat; + this.param = param; + } + + @Override + public void execute(Manager manager, Ui ui) { + manager.setCalculator(); + switch (this.param) { + case "all": + ui.printAllNutrientIntake(this.calorie, this.carb, this.protein, this.fat); + break; + case "calorie": + ui.printCalorieIntake(this.calorie); + break; + case "carbohydrate": + ui.printCarbohydrateIntake(this.carb); + break; + case "protein": + ui.printProteinIntake(this.protein); + break; + default: + ui.printFatIntake(this.fat); + } + } +} diff --git a/src/main/java/seedu/dietbook/command/ClearCommand.java b/src/main/java/seedu/dietbook/command/ClearCommand.java new file mode 100644 index 0000000000..b07f6dda71 --- /dev/null +++ b/src/main/java/seedu/dietbook/command/ClearCommand.java @@ -0,0 +1,12 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class ClearCommand extends Command { + @Override + public void execute(Manager manager, Ui ui) { + ui.printClearFoodListMessage(); + manager.getFoodList().clear(); + } +} diff --git a/src/main/java/seedu/dietbook/command/Command.java b/src/main/java/seedu/dietbook/command/Command.java new file mode 100644 index 0000000000..a5a9e58636 --- /dev/null +++ b/src/main/java/seedu/dietbook/command/Command.java @@ -0,0 +1,9 @@ +package seedu.dietbook.command; + +import seedu.dietbook.exception.DietException; +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public abstract class Command { + public abstract void execute(Manager manager, Ui ui) throws DietException; +} diff --git a/src/main/java/seedu/dietbook/command/DataCommand.java b/src/main/java/seedu/dietbook/command/DataCommand.java new file mode 100644 index 0000000000..12db1c7202 --- /dev/null +++ b/src/main/java/seedu/dietbook/command/DataCommand.java @@ -0,0 +1,13 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class DataCommand extends Command { + + @Override + public void execute(Manager manager, Ui ui) { + manager.getDataBase().init(); + ui.printDatabase(manager.getDataBase().getFoodList()); + } +} diff --git a/src/main/java/seedu/dietbook/command/DeleteCommand.java b/src/main/java/seedu/dietbook/command/DeleteCommand.java new file mode 100644 index 0000000000..260635b297 --- /dev/null +++ b/src/main/java/seedu/dietbook/command/DeleteCommand.java @@ -0,0 +1,23 @@ +package seedu.dietbook.command; + +import seedu.dietbook.exception.DietException; +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class DeleteCommand extends Command { + int index; + + public DeleteCommand(int index) { + this.index = index; + } + + @Override + public void execute(Manager manager, Ui ui) throws DietException { + try { + ui.printDeletedFood(manager.getFoodList().delete(this.index)); + manager.setCalculator(); + } catch (IndexOutOfBoundsException e) { + throw new DietException("No such index!"); + } + } +} diff --git a/src/main/java/seedu/dietbook/command/ExitCommand.java b/src/main/java/seedu/dietbook/command/ExitCommand.java new file mode 100644 index 0000000000..9f5b19d0dd --- /dev/null +++ b/src/main/java/seedu/dietbook/command/ExitCommand.java @@ -0,0 +1,13 @@ +package seedu.dietbook.command; + +import seedu.dietbook.DietBook; +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class ExitCommand extends Command { + @Override + public void execute(Manager manager, Ui ui) { + ui.printExitMessage(manager.getName()); + DietBook.isExit = true; + } +} diff --git a/src/main/java/seedu/dietbook/command/HelpCommand.java b/src/main/java/seedu/dietbook/command/HelpCommand.java new file mode 100644 index 0000000000..30a57a593f --- /dev/null +++ b/src/main/java/seedu/dietbook/command/HelpCommand.java @@ -0,0 +1,11 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class HelpCommand extends Command { + @Override + public void execute(Manager manager, Ui ui) { + ui.printTutorialMessage(); + } +} diff --git a/src/main/java/seedu/dietbook/command/InfoCommand.java b/src/main/java/seedu/dietbook/command/InfoCommand.java new file mode 100644 index 0000000000..c189c46be3 --- /dev/null +++ b/src/main/java/seedu/dietbook/command/InfoCommand.java @@ -0,0 +1,20 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; +import seedu.dietbook.parser.Parser; + +public class InfoCommand extends Command { + String userInput; + + public InfoCommand(String userInput) { + this.userInput = userInput; + } + + @Override + public void execute(Manager manager, Ui ui) throws DietException { + Parser.executeProcessedInfo(this.userInput, manager); + ui.printTutorialMessage(); + } +} diff --git a/src/main/java/seedu/dietbook/command/ListCommand.java b/src/main/java/seedu/dietbook/command/ListCommand.java new file mode 100644 index 0000000000..5e44014eec --- /dev/null +++ b/src/main/java/seedu/dietbook/command/ListCommand.java @@ -0,0 +1,11 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class ListCommand extends Command { + @Override + public void execute(Manager manager, Ui ui) { + ui.printFoodList(manager.getFoodList().toString()); + } +} diff --git a/src/main/java/seedu/dietbook/command/NameCommand.java b/src/main/java/seedu/dietbook/command/NameCommand.java new file mode 100644 index 0000000000..11f6d44e3a --- /dev/null +++ b/src/main/java/seedu/dietbook/command/NameCommand.java @@ -0,0 +1,20 @@ +package seedu.dietbook.command; + + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + + +public class NameCommand extends Command { + String name; + + public NameCommand(String name) { + this.name = name; + } + + @Override + public void execute(Manager manager, Ui ui) { + manager.setName(this.name); + ui.printAskForUserInfoMessage(manager.getName()); + } +} diff --git a/src/main/java/seedu/dietbook/command/UserinfoCommand.java b/src/main/java/seedu/dietbook/command/UserinfoCommand.java new file mode 100644 index 0000000000..40c8fca39b --- /dev/null +++ b/src/main/java/seedu/dietbook/command/UserinfoCommand.java @@ -0,0 +1,11 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; + +public class UserinfoCommand extends Command { + @Override + public void execute(Manager manager, Ui ui) { + ui.printPersonInfo(manager.getPerson().toString()); + } +} diff --git a/src/main/java/seedu/dietbook/DietException.java b/src/main/java/seedu/dietbook/exception/DietException.java similarity index 85% rename from src/main/java/seedu/dietbook/DietException.java rename to src/main/java/seedu/dietbook/exception/DietException.java index 922514bfa5..9f3dffc2d5 100644 --- a/src/main/java/seedu/dietbook/DietException.java +++ b/src/main/java/seedu/dietbook/exception/DietException.java @@ -1,4 +1,4 @@ -package seedu.dietbook; +package seedu.dietbook.exception; public class DietException extends Exception { public DietException(String message) { diff --git a/src/main/java/seedu/dietbook/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java similarity index 66% rename from src/main/java/seedu/dietbook/Parser.java rename to src/main/java/seedu/dietbook/parser/Parser.java index 8c2fd309df..195d4ea05b 100644 --- a/src/main/java/seedu/dietbook/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -1,23 +1,16 @@ -package seedu.dietbook; +package seedu.dietbook.parser; -import seedu.calculator.Calculator; import seedu.dietbook.list.FoodList; import seedu.dietbook.person.Gender; import seedu.dietbook.person.ActivityLevel; - -import java.io.FileNotFoundException; +import seedu.dietbook.exception.DietException; +import seedu.dietbook.Manager; public class Parser { public static final String COMMAND_NAME = "name"; - public static final String COMMAND_LIST = "list"; public static final String COMMAND_INFO = "info"; - public static final String COMMAND_EXIT = "exit"; public static final String COMMAND_ADD = "add"; - public static final String COMMAND_CLEAR = "clear"; - public static final String COMMAND_DELETE = "delete"; public static final String COMMAND_CALCULATE = "calculate"; - public static final String COMMAND_DATA = "data"; - public static final String COMMAND_USERINFO = "userinfo"; public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; public static final String[] PARAM_ADD = {"n/","x/","k/"}; @@ -28,7 +21,7 @@ public class Parser { * @param userInput which is user input. * @return First word which is the command of the user input. */ - private static String getCommand(String userInput) { + public static String getCommand(String userInput) { return userInput.split(" ")[0]; } @@ -38,7 +31,7 @@ private static String getCommand(String userInput) { * @return parameter part of the user input. * @throws DietException when the user input is of a wrong format. */ - private static String getCommandParam(String userInput) throws DietException { + public static String getCommandParam(String userInput) throws DietException { String command = getCommand(userInput); String[] input = {userInput}; @@ -83,7 +76,7 @@ private static String getCommandParam(String userInput) throws DietException { * @return name of the food that was added. * @throws DietException when the user input is of a wrong format. */ - private static String getProcessedAdd(String userInput, FoodList foodList) throws DietException { + public static String getProcessedAdd(String userInput, FoodList foodList) throws DietException { int portionSize = 1; String foodName = "Food Name"; int calorie = 0; @@ -131,7 +124,7 @@ private static String getProcessedAdd(String userInput, FoodList foodList) throw * @param manager the manager object. * @throws DietException when the user input is of a wrong format. */ - private static void executeProcessedInfo(String userInput, Manager manager) throws DietException { + public static void executeProcessedInfo(String userInput, Manager manager) throws DietException { Gender gender = Gender.MALE; ActivityLevel actLvl = ActivityLevel.NONE; int age = 0; @@ -193,7 +186,7 @@ private static void executeProcessedInfo(String userInput, Manager manager) thro * @return index part of the user input. * @throws DietException when the user input is of a wrong format. */ - private static int getCommandIndex(String userInput) throws DietException { + public static int getCommandIndex(String userInput) throws DietException { String command = getCommand(userInput); if (userInput.split(command).length < 2 || userInput.split(command)[1].equals(" ")) { @@ -205,70 +198,4 @@ private static int getCommandIndex(String userInput) throws DietException { throw new DietException("OOPS!!! No integer index detected!"); } } - - /** - * Makes sense of the user input and carries out the functions according to the command given. - * @param userInput user input. - * @throws DietException when the program does not recognize the command given. - */ - public static void parse(String userInput, Manager manager, Ui ui) throws DietException, FileNotFoundException { - Calculator calculator = manager.getCalculator(); - switch (getCommand(userInput)) { - case COMMAND_NAME: - manager.setName(getCommandParam(userInput)); - ui.printAskForUserInfoMessage(manager.getName()); - return; - case COMMAND_EXIT: - ui.printExitMessage(manager.getName()); - DietBook.isExit = true; - return; - case COMMAND_LIST: - ui.printFoodList(manager.getFoodList().toString()); - return; - case COMMAND_USERINFO: - ui.printPersonInfo(manager.getPerson().toString()); - return; - case COMMAND_DATA: - manager.getDataBase().init(); - ui.printDatabase(manager.getDataBase().getFoodList()); - return; - case COMMAND_DELETE: - try { - ui.printDeletedFood(manager.getFoodList().delete(getCommandIndex(userInput))); - manager.setCalculator(); - } catch (IndexOutOfBoundsException e) { - throw new DietException("No such index!"); - } - return; - case COMMAND_CLEAR: - ui.printClearFoodListMessage(); - manager.getFoodList().clear(); - return; - case COMMAND_CALCULATE: - manager.setCalculator(); - if (getCommandParam(userInput).equals("all")) { - ui.printAllNutrientIntake(calculator.calculateCalorie(), calculator.calculateCarb(), - calculator.calculateProtein(), calculator.calculateFat()); - } else if (getCommandParam(userInput).equals("calorie")) { - ui.printCalorieIntake(calculator.calculateCalorie()); - } else if (getCommandParam(userInput).equals("carbohydrate")) { - ui.printCarbohydrateIntake(calculator.calculateCarb()); - } else if (getCommandParam(userInput).equals("protein")) { - ui.printProteinIntake(calculator.calculateProtein()); - } else { - ui.printFatIntake(calculator.calculateFat()); - } - return; - case COMMAND_INFO: - executeProcessedInfo(userInput, manager); - ui.printTutorialMessage(); - return; - case COMMAND_ADD: - ui.printNewFood(getProcessedAdd(userInput, manager.getFoodList())); - manager.setCalculator(); - return; - default: - throw new DietException("There's no such command!"); - } - } } From 8eb6d3b7874655cd5a11e400fd32bc383301cad7 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Sat, 24 Oct 2020 13:31:47 +0800 Subject: [PATCH 125/271] Input Checker -Implemented input checker class --- src/main/java/META-INF/MANIFEST.MF | 2 +- src/main/java/seedu/dietbook/DietBook.java | 27 ++-- src/main/java/seedu/dietbook/Manager.java | 11 +- .../seedu/dietbook/checker/InputChecker.java | 153 ++++++++++++++++++ .../java/seedu/dietbook/command/Command.java | 8 + .../java/seedu/dietbook/parser/Parser.java | 83 +++++----- 6 files changed, 230 insertions(+), 54 deletions(-) create mode 100644 src/main/java/seedu/dietbook/checker/InputChecker.java diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF index 3d5a2c3351..d18cc0371f 100644 --- a/src/main/java/META-INF/MANIFEST.MF +++ b/src/main/java/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Main-Class: seedu.duke.DietBook +Main-Class: seedu.dietbook.DietBook diff --git a/src/main/java/seedu/dietbook/DietBook.java b/src/main/java/seedu/dietbook/DietBook.java index 4da58f94c2..4bcdbf404d 100644 --- a/src/main/java/seedu/dietbook/DietBook.java +++ b/src/main/java/seedu/dietbook/DietBook.java @@ -7,6 +7,13 @@ import seedu.dietbook.exception.DietException; import seedu.dietbook.command.Command; +/** + * Main class of the program. + * The DietBook program is an application which can store, display and check your daily dietary intake. + * + * @author tikimonarch + */ + public class DietBook { private FoodList foodList; private Ui ui; @@ -14,6 +21,16 @@ public class DietBook { private DataBase dataBase; public static boolean isExit = false; + /** + * Constructor for new DietBook. + */ + public DietBook() { + ui = new Ui(); + foodList = new FoodList(); + dataBase = new DataBase(); + manager = new Manager(foodList, dataBase); + } + /** * Main method to run the program. */ @@ -31,14 +48,4 @@ public static void main(String[] args) throws FileNotFoundException { } } } - - /** - * Constructor for new DietBook. - */ - public DietBook() { - ui = new Ui(); - foodList = new FoodList(); - dataBase = new DataBase(); - manager = new Manager(foodList, dataBase); - } } diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 0e33b62f1d..9f0bf2781b 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -12,6 +12,14 @@ import java.util.Scanner; +/** + * Manager class of the program. + * The manager class takes in the checked and processed input and carry out the command specified. + * Initialization of important classes such as FoodList and Person is done here. + * + * @author tikimonarch + */ + public class Manager { private Person person; private FoodList foodList; @@ -78,8 +86,9 @@ public void setName(String name) { } /** - * Makes sense of the user input and carries out the functions according to the command given. + * Takes in the user input and returns the command to be carried. * @param userInput user input. + * @return Command for the command specified. * @throws DietException when the program does not recognize the command given. */ public Command manage(String userInput) throws DietException { diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java new file mode 100644 index 0000000000..109d1340e8 --- /dev/null +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -0,0 +1,153 @@ +package seedu.dietbook.checker; + +import seedu.dietbook.exception.DietException; + +/** + * InputChecker class of the program. + * This class checks the validity of the user input and throws an exception if input is not as intended/expected. + * + * @author tikimonarch + */ + +public class InputChecker { + public static final int AGE_CAP = 125; + public static final int FOOD_CAP = 100000; + public static final int HEIGHT_CAP = 273; + public static final int WEIGHT_CAP = 443; + public static final String[] PARAM_ACTIVITY = {"1","2","3","4","5"}; + public static final String[] PARAM_ADD = {"n/","x/","k/"}; + public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; + public static final String[] PARAM_GENDER = {"M","F","O"}; + public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; + + /** + * Takes in user input and command to check for any expected parameters after the command. + * @param userInput user input. + * @param command command in user input. + * @throws DietException when at least one parameter is expected but not present. + */ + public static void checkEmpty(String userInput, String command) throws DietException { + if (userInput.split(command).length < 2 + || userInput.split(command)[1].equals(" ")) { + throw new DietException("Error! Missing command parameters!"); + } + } + + /** + * Takes in user input to check if the expected number and type of parameter for the add command is present. + * @param userInput user input. + * @throws DietException when expected parameters are missing. + */ + public static void checkAddParam(String userInput) throws DietException { + for (String param: PARAM_ADD) { + if (!userInput.contains(param)) { + throw new DietException("Missing or incorrect add statement"); + } + } + } + + /** + * Takes in user input to check if the expected number and type of parameter for the info command is present. + * @param userInput user input. + * @throws DietException when expected parameters are missing. + */ + public static void checkInfoParam(String userInput) throws DietException { + for (String param: PARAM_INFO) { + if (!userInput.contains(param)) { + throw new DietException("Missing or incorrect info statement"); + } + } + } + + /** + * Takes in an integer from food to check if the value is within the logical limit. + * @param foodValue integer value of attributes. + * @throws DietException when value is not within the limit. + */ + public static void checkFoodLimit(int foodValue) throws DietException { + if (foodValue < 0) { + throw new DietException("Input value cannot be less than 0!"); + } else if (foodValue > FOOD_CAP) { + throw new DietException("Input value cannot be more than 100,000!"); + } + } + + /** + * Takes in user input to check if the nutrient type is of the expected input. + * @param userInput user input. + * @throws DietException when it is not one of the expected nutrient type. + */ + public static void checkNutrientType(String userInput) throws DietException { + for (String param: PARAM_CALCULATE) { + if (!userInput.contains(param)) { + throw new DietException("Incorrect nutrient type!"); + } + } + } + + /** + * Takes in user input to check if the activity level is of the expected input. + * @param userInput user input. + * @throws DietException when it is not one of the expected activity level. + */ + public static void checkActivity(String userInput) throws DietException { + for (String param: PARAM_ACTIVITY) { + if (!userInput.contains(param)) { + throw new DietException("No such activity level!"); + } + } + } + + /** + * Takes in user input to check if the gender is of the expected input. + * @param userInput user input. + * @throws DietException when it is not one of the expected gender input. + */ + public static void checkGender(String userInput) throws DietException { + for (String param: PARAM_GENDER) { + if (!userInput.contains(param)) { + throw new DietException("Please key in the specified gender characters."); + } + } + } + + /** + * Takes in an integer age to check if the value is within the logical limit. + * @param age integer value of age. + * @throws DietException when value is not within the limit. + */ + public static void checkAgeLimit(int age) throws DietException { + if (age < 0) { + throw new DietException("Input value cannot be less than 0!"); + } else if (age > AGE_CAP) { + throw new DietException("Input value cannot be more than 125!"); + } + } + + /** + * Takes in an integer height to check if the value is within the logical limit. + * @param height integer value of height. + * @throws DietException when value is not within the limit. + */ + public static void checkHeightLimit(int height) throws DietException { + if (height < 0) { + throw new DietException("Input value cannot be less than 0!"); + } else if (height > HEIGHT_CAP) { + throw new DietException("Input value cannot be more than 273!"); + } + } + + /** + * Takes in an integer weight to check if the value is within the logical limit. + * @param weight integer value of weight. + * @throws DietException when value is not within the limit. + */ + public static void checkWeightLimit(int weight) throws DietException { + if (weight < 0) { + throw new DietException("Input value cannot be less than 0!"); + } else if (weight > WEIGHT_CAP) { + throw new DietException("Input value cannot be more than 443!"); + } + } + +} diff --git a/src/main/java/seedu/dietbook/command/Command.java b/src/main/java/seedu/dietbook/command/Command.java index a5a9e58636..5282fc1990 100644 --- a/src/main/java/seedu/dietbook/command/Command.java +++ b/src/main/java/seedu/dietbook/command/Command.java @@ -4,6 +4,14 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +/** + * The command parent class for all commands. + * All commands have an execute method that takes in objects Manager and Ui. + * Each child command class is self-explanatory. + * + * @author tikimonarch + */ + public abstract class Command { public abstract void execute(Manager manager, Ui ui) throws DietException; } diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 195d4ea05b..365b328f3d 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -5,15 +5,22 @@ import seedu.dietbook.person.ActivityLevel; import seedu.dietbook.exception.DietException; import seedu.dietbook.Manager; +import seedu.dietbook.checker.InputChecker; + +/** + * Parser class of the program. + * The parser class takes in user input and process it into command data that manager can use. + * + * @author tikimonarch + */ public class Parser { public static final String COMMAND_NAME = "name"; public static final String COMMAND_INFO = "info"; public static final String COMMAND_ADD = "add"; public static final String COMMAND_CALCULATE = "calculate"; - public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; - public static final String[] PARAM_ADD = {"n/","x/","k/"}; + /** @@ -33,40 +40,24 @@ public static String getCommand(String userInput) { */ public static String getCommandParam(String userInput) throws DietException { String command = getCommand(userInput); - String[] input = {userInput}; - if (userInput.split(command).length < 2 - || userInput.split(command)[1].equals(" ")) { - throw new DietException("Error! Missing command parameters!"); - } else { - switch (command) { - case COMMAND_NAME: - return userInput.split("name")[1].trim(); - case COMMAND_CALCULATE: - for (String param: PARAM_CALCULATE) { - if (userInput.contains(param)) { - return userInput.split("calculate")[1].trim(); - } - } - throw new DietException("Incorrect nutrient type"); - case COMMAND_ADD: - for (String param: PARAM_ADD) { - if (!userInput.contains(param)) { - throw new DietException("Missing or incorrect add statement"); - } - } - return userInput.substring(userInput.indexOf(' ') + 1); - case COMMAND_INFO: - for (String param: PARAM_INFO) { - if (!userInput.contains(param)) { - throw new DietException("Missing or incorrect info statement"); - } - } - return userInput.substring(userInput.indexOf(' ') + 1); - default: - return null; - } + InputChecker.checkEmpty(userInput, command); + switch (command) { + case COMMAND_NAME: + return userInput.split("name")[1].trim(); + case COMMAND_CALCULATE: + InputChecker.checkNutrientType(userInput); + return userInput.split("calculate")[1].trim(); + case COMMAND_ADD: + InputChecker.checkAddParam(userInput); + return userInput.substring(userInput.indexOf(' ') + 1); + case COMMAND_INFO: + InputChecker.checkInfoParam(userInput); + return userInput.substring(userInput.indexOf(' ') + 1); + default: + return null; } + } /** @@ -80,9 +71,9 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws int portionSize = 1; String foodName = "Food Name"; int calorie = 0; - int carb = 0; - int protein = 0; - int fat = 0; + int carb = -1; + int protein = -1; + int fat = -1; String trimmedParam; String[] processedParam; String[] paramList = {"x/", "n/", "k/", "c/", "p/", "f/"}; @@ -96,21 +87,26 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws switch (param) { case "x/": portionSize = Integer.parseInt(trimmedParam); + InputChecker.checkFoodLimit(portionSize); break; case "n/": foodName = trimmedParam; break; case "k/": calorie = Integer.parseInt(trimmedParam); + InputChecker.checkFoodLimit(calorie); break; case "c/": carb = Integer.parseInt(trimmedParam); + InputChecker.checkFoodLimit(carb); break; case "p/": protein = Integer.parseInt(trimmedParam); + InputChecker.checkFoodLimit(protein); break; default: fat = Integer.parseInt(trimmedParam); + InputChecker.checkFoodLimit(fat); break; } } @@ -133,8 +129,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw int tarWeight = 0; String trimmedParam; String[] processedParam; - String[] paramList = {"g/", "a/", "h/", "o/", "t/", "l/"}; - for (String param: paramList) { + for (String param: PARAM_INFO) { processedParam = getCommandParam(userInput).split(param); trimmedParam = processedParam[1].trim(); if (processedParam[1].contains("/")) { @@ -143,6 +138,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw switch (param) { case "g/": String processGender = trimmedParam; + InputChecker.checkGender(processGender); if (processGender.equals("M")) { gender = Gender.MALE; } else { @@ -151,18 +147,23 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw break; case "a/": age = Integer.parseInt(trimmedParam); + InputChecker.checkAgeLimit(age); break; case "h/": height = Integer.parseInt(trimmedParam); + InputChecker.checkHeightLimit(height); break; case "o/": orgWeight = Integer.parseInt(trimmedParam); + InputChecker.checkWeightLimit(orgWeight); break; case "t/": tarWeight = Integer.parseInt(trimmedParam); + InputChecker.checkWeightLimit(tarWeight); break; default: String processActLvl = trimmedParam; + InputChecker.checkActivity(processActLvl); if (processActLvl.equals("1")) { actLvl = ActivityLevel.NONE; } else if (processActLvl.equals("2")) { @@ -189,9 +190,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw public static int getCommandIndex(String userInput) throws DietException { String command = getCommand(userInput); - if (userInput.split(command).length < 2 || userInput.split(command)[1].equals(" ")) { - throw new DietException("OOPS!!! Missing index of duke.task!"); - } + InputChecker.checkEmpty(userInput, command); try { return Integer.parseInt(userInput.split(" ")[1]); } catch (NumberFormatException e) { From ad72b4d5f4808dc1aedbaaff0a0bcc1fc958dfcf Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Sat, 24 Oct 2020 15:16:11 +0800 Subject: [PATCH 126/271] New check, bug fixes ->fixed for acticity, gender, calculate type checks ->new check if an option is specified but with an empty field --- .../seedu/dietbook/checker/InputChecker.java | 42 ++++++++++++++++--- .../java/seedu/dietbook/parser/Parser.java | 2 + 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 109d1340e8..4c71a5f251 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -10,6 +10,9 @@ */ public class InputChecker { + /** + * The value limits are based on current limits observed in th world. + */ public static final int AGE_CAP = 125; public static final int FOOD_CAP = 100000; public static final int HEIGHT_CAP = 273; @@ -33,6 +36,21 @@ public static void checkEmpty(String userInput, String command) throws DietExcep } } + /** + * Takes in processed user input to check for options specified with an empty field. + * @param input user input. + * @throws DietException when an option is specified but its field is empty. + */ + public static void checkEmptyOption(String[] input) throws DietException { + try { + if (input[1].trim().charAt(1) == '/') { + throw new DietException("Error! Option specified with empty field!"); + } + } catch (IndexOutOfBoundsException e) { + throw new DietException("Error! Option specified with empty field!"); + } + } + /** * Takes in user input to check if the expected number and type of parameter for the add command is present. * @param userInput user input. @@ -78,11 +96,15 @@ public static void checkFoodLimit(int foodValue) throws DietException { * @throws DietException when it is not one of the expected nutrient type. */ public static void checkNutrientType(String userInput) throws DietException { + boolean checkContain = false; for (String param: PARAM_CALCULATE) { - if (!userInput.contains(param)) { - throw new DietException("Incorrect nutrient type!"); + if (userInput.contains(param)) { + checkContain = true; } } + if (!checkContain) { + throw new DietException("Incorrect nutrient type!"); + } } /** @@ -91,11 +113,15 @@ public static void checkNutrientType(String userInput) throws DietException { * @throws DietException when it is not one of the expected activity level. */ public static void checkActivity(String userInput) throws DietException { + boolean checkContain = false; for (String param: PARAM_ACTIVITY) { - if (!userInput.contains(param)) { - throw new DietException("No such activity level!"); + if (userInput.contains(param)) { + checkContain = true; } } + if (!checkContain) { + throw new DietException("No such activity level!"); + } } /** @@ -104,11 +130,15 @@ public static void checkActivity(String userInput) throws DietException { * @throws DietException when it is not one of the expected gender input. */ public static void checkGender(String userInput) throws DietException { + boolean checkContain = false; for (String param: PARAM_GENDER) { - if (!userInput.contains(param)) { - throw new DietException("Please key in the specified gender characters."); + if (userInput.contains(param)) { + checkContain = true; } } + if (!checkContain) { + throw new DietException("Please key in the specified gender characters."); + } } /** diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 365b328f3d..a75df37a6e 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -80,6 +80,7 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws for (String param: paramList) { if (getCommandParam(userInput).contains(param)) { processedParam = getCommandParam(userInput).split(param); + InputChecker.checkEmptyOption(processedParam); trimmedParam = processedParam[1].trim(); if (processedParam[1].contains("/")) { trimmedParam = processedParam[1].substring(0, processedParam[1].indexOf("/") - 2).trim(); @@ -131,6 +132,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw String[] processedParam; for (String param: PARAM_INFO) { processedParam = getCommandParam(userInput).split(param); + InputChecker.checkEmptyOption(processedParam); trimmedParam = processedParam[1].trim(); if (processedParam[1].contains("/")) { trimmedParam = processedParam[1].substring(0, processedParam[1].indexOf("/") - 2).trim(); From 609f8ea04430471ea53fc9d22de840d11f74dcf6 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Sat, 24 Oct 2020 15:21:09 +0800 Subject: [PATCH 127/271] Spacings --- src/main/java/seedu/dietbook/Manager.java | 1 + .../java/seedu/dietbook/checker/InputChecker.java | 11 +++++++++++ src/main/java/seedu/dietbook/parser/Parser.java | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 9f0bf2781b..be218c70a1 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -87,6 +87,7 @@ public void setName(String name) { /** * Takes in the user input and returns the command to be carried. + * * @param userInput user input. * @return Command for the command specified. * @throws DietException when the program does not recognize the command given. diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 4c71a5f251..53772478f4 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -25,6 +25,7 @@ public class InputChecker { /** * Takes in user input and command to check for any expected parameters after the command. + * * @param userInput user input. * @param command command in user input. * @throws DietException when at least one parameter is expected but not present. @@ -38,6 +39,7 @@ public static void checkEmpty(String userInput, String command) throws DietExcep /** * Takes in processed user input to check for options specified with an empty field. + * * @param input user input. * @throws DietException when an option is specified but its field is empty. */ @@ -53,6 +55,7 @@ public static void checkEmptyOption(String[] input) throws DietException { /** * Takes in user input to check if the expected number and type of parameter for the add command is present. + * * @param userInput user input. * @throws DietException when expected parameters are missing. */ @@ -66,6 +69,7 @@ public static void checkAddParam(String userInput) throws DietException { /** * Takes in user input to check if the expected number and type of parameter for the info command is present. + * * @param userInput user input. * @throws DietException when expected parameters are missing. */ @@ -79,6 +83,7 @@ public static void checkInfoParam(String userInput) throws DietException { /** * Takes in an integer from food to check if the value is within the logical limit. + * * @param foodValue integer value of attributes. * @throws DietException when value is not within the limit. */ @@ -92,6 +97,7 @@ public static void checkFoodLimit(int foodValue) throws DietException { /** * Takes in user input to check if the nutrient type is of the expected input. + * * @param userInput user input. * @throws DietException when it is not one of the expected nutrient type. */ @@ -109,6 +115,7 @@ public static void checkNutrientType(String userInput) throws DietException { /** * Takes in user input to check if the activity level is of the expected input. + * * @param userInput user input. * @throws DietException when it is not one of the expected activity level. */ @@ -126,6 +133,7 @@ public static void checkActivity(String userInput) throws DietException { /** * Takes in user input to check if the gender is of the expected input. + * * @param userInput user input. * @throws DietException when it is not one of the expected gender input. */ @@ -143,6 +151,7 @@ public static void checkGender(String userInput) throws DietException { /** * Takes in an integer age to check if the value is within the logical limit. + * * @param age integer value of age. * @throws DietException when value is not within the limit. */ @@ -156,6 +165,7 @@ public static void checkAgeLimit(int age) throws DietException { /** * Takes in an integer height to check if the value is within the logical limit. + * * @param height integer value of height. * @throws DietException when value is not within the limit. */ @@ -169,6 +179,7 @@ public static void checkHeightLimit(int height) throws DietException { /** * Takes in an integer weight to check if the value is within the logical limit. + * * @param weight integer value of weight. * @throws DietException when value is not within the limit. */ diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index a75df37a6e..59283b0353 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -25,6 +25,7 @@ public class Parser { /** * Returns the command of a user input. + * * @param userInput which is user input. * @return First word which is the command of the user input. */ @@ -34,6 +35,7 @@ public static String getCommand(String userInput) { /** * Returns the subsequent parameter after the command from the user input. + * * @param userInput user input. * @return parameter part of the user input. * @throws DietException when the user input is of a wrong format. @@ -62,6 +64,7 @@ public static String getCommandParam(String userInput) throws DietException { /** * Processes the parameters for add command of user input and adds a Food object. + * * @param userInput user input. * @param foodList the FoodList object. * @return name of the food that was added. @@ -117,6 +120,7 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws /** * Processes the parameters for info command of user input and updates the Person object. + * * @param userInput user input. * @param manager the manager object. * @throws DietException when the user input is of a wrong format. @@ -185,6 +189,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw /** * Returns the index after the command of a user input, e.g. delete 3. + * * @param userInput user input. * @return index part of the user input. * @throws DietException when the user input is of a wrong format. From e647a62e57ca55055b7d6bc3c0c30e768988f3fc Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Sat, 24 Oct 2020 19:32:54 +0800 Subject: [PATCH 128/271] checkstyle import --- src/main/java/seedu/dietbook/Manager.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index be218c70a1..ad4c9be9f9 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -1,6 +1,17 @@ package seedu.dietbook; -import seedu.dietbook.command.*; +import seedu.dietbook.command.AddCommand; +import seedu.dietbook.command.CalculateCommand; +import seedu.dietbook.command.ClearCommand; +import seedu.dietbook.command.Command; +import seedu.dietbook.command.DataCommand; +import seedu.dietbook.command.DeleteCommand; +import seedu.dietbook.command.ExitCommand; +import seedu.dietbook.command.HelpCommand; +import seedu.dietbook.command.InfoCommand; +import seedu.dietbook.command.ListCommand; +import seedu.dietbook.command.NameCommand; +import seedu.dietbook.command.UserinfoCommand; import seedu.dietbook.list.FoodList; import seedu.dietbook.person.ActivityLevel; import seedu.dietbook.person.Person; From 1b032b3891784edaee486010f38b9fdbf295066b Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 19:34:06 +0800 Subject: [PATCH 129/271] Provide an example for inputting name --- src/main/java/seedu/dietbook/Ui.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index eec8ede96c..a86655339d 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -35,7 +35,8 @@ public void printWelcomeMessage() { + "Hello! Welcome to DietBook!" + LINE_SEPARATOR + "I am Diet, your guide to using DietBook. What is your name?" + LINE_SEPARATOR + "Please input in the following format:" + LINE_SEPARATOR - + " name YOUR_NAME"); + + " name YOUR_NAME" + LINE_SEPARATOR + + " Example: name Jack"); } /** From 25209b806494d3169d9f883ff98ef4f1660946ed Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 19:40:20 +0800 Subject: [PATCH 130/271] Add others gender --- src/main/java/seedu/dietbook/person/Gender.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/person/Gender.java b/src/main/java/seedu/dietbook/person/Gender.java index b0bbe03e22..d19419da79 100644 --- a/src/main/java/seedu/dietbook/person/Gender.java +++ b/src/main/java/seedu/dietbook/person/Gender.java @@ -6,7 +6,8 @@ */ public enum Gender { FEMALE("female"), - MALE("male"); + MALE("male"), + OTHERS("others"); private final String description; From 1df44a13b2f683a9d9a3ddbaa5a09b7e8279ce6e Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 19:47:55 +0800 Subject: [PATCH 131/271] Add comments on organisation of Ui methods --- src/main/java/seedu/dietbook/Ui.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index a86655339d..24c4378971 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -21,6 +21,11 @@ public class Ui { public Ui() { } + // Methods in the Ui class are organised according to their function in the order of: system related, + // database related, person related, food list related, calculator related and other helper methods. + + // Methods required to print system related commands or messages. + /** * Prints the welcome message from DietBook when it is fist booted up. */ From ee69fb2011e512e93afb161abf432cceb8429687 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 20:51:22 +0800 Subject: [PATCH 132/271] Organise related methods together --- src/main/java/seedu/dietbook/Ui.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 24c4378971..cf2f29d43e 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -177,7 +177,13 @@ public void printDatabase(String foodDatabase) { } /** - * Prints all the information related to the user. + * Prints a message to show that the food list has been successfully cleared and is now empty. + */ + public void printClearFoodListMessage() { + print("All previous data has been deleted..." + LINE_SEPARATOR + + "DietBook is now empty."); + } + * * @param personInfo The user's personal information. */ From 26bf7071b123b21dc52a2ac73a40b04edd756f25 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 20:52:31 +0800 Subject: [PATCH 133/271] Add getSystemRelatedCommands method --- src/main/java/seedu/dietbook/Ui.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index cf2f29d43e..eb4c971b48 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -253,6 +253,16 @@ public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, in + "Total carbohydrate intake: " + carbohydrateIntake + "g" + LINE_SEPARATOR + "Total protein intake: " + proteinIntake + "g" + LINE_SEPARATOR + "Total fat intake: " + fatIntake + "g"); + // Helper methods for system related commands or messages + + /** + * Returns a string representation of a list of system related commands that users can input. + * + * @return A string representation of a list of system related commands that users can input. + */ + private String getSystemRelatedCommands() { + return " To view a list of valid commands: help" + LINE_SEPARATOR + + " To exit DietBook: exit"; } /** From 3222b997d34c92cf08ba7d5a5700e785043e552a Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 20:54:55 +0800 Subject: [PATCH 134/271] Update printAskForUserInfoMessage method --- src/main/java/seedu/dietbook/Ui.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index eb4c971b48..a070ebf6d9 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -59,11 +59,14 @@ public void printAskForUserInfoMessage(String name) { + "accurate calculations for you :). Therefore, could you please share with me the " + "following:" + LINE_SEPARATOR + "- Your gender either F for " + Gender.FEMALE.getDescription() + " or M for " - + Gender.MALE.getDescription() + "." + LINE_SEPARATOR + + Gender.MALE.getDescription() + " or O for " + Gender.OTHERS.getDescription() + "." + + LINE_SEPARATOR + "- Your age which is a positive integer." + LINE_SEPARATOR + "- Your height in cm." + LINE_SEPARATOR - + "- Your original weight in kg." + LINE_SEPARATOR - + "- Your target weight in kg, or your original weight if that is also your target weight." + + "- Your original weight in kg, the weight when you first started using DietBook or " + + "you current weight." + LINE_SEPARATOR + + "- Your current weight in kg." + LINE_SEPARATOR + + "- Your target weight in kg, or your current weight if that is also your target weight." + LINE_SEPARATOR + "- Your activity level, represented by a number from 1 to 5." + LINE_SEPARATOR + " 1 = " + ActivityLevel.NONE.getDescription() + LINE_SEPARATOR @@ -72,9 +75,11 @@ public void printAskForUserInfoMessage(String name) { + " 4 = " + ActivityLevel.HIGH.getDescription() + LINE_SEPARATOR + " 5 = " + ActivityLevel.EXTREME.getDescription() + LINE_SEPARATOR + LINE_SEPARATOR + "Please input your details in the following format:" + LINE_SEPARATOR - + " info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT t/TARGET_WEIGHT l/ACTIVITY_LEVEL" - + LINE_SEPARATOR - + " Example: info g/F a/21 h/165 o/65 t/55 l/2"); + + " info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT c/CURRENT_WEIGHT t/TARGET_WEIGHT " + + "l/ACTIVITY_LEVEL" + LINE_SEPARATOR + + " Example: info g/F a/21 h/165 o/65 c/65 t/55 l/2"); + } + } /** From 168e6ac49283a6d8e89d2abeddf3fba568e1bd01 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 20:57:38 +0800 Subject: [PATCH 135/271] Change initialisation completed message --- src/main/java/seedu/dietbook/Ui.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index a070ebf6d9..9033e7cd98 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -106,7 +106,14 @@ public void printTutorialMessage() { } /** - * Prints a message to show that the food specified has been added to the food list. + * Prints a message that notifies the user that DietBook has been initialised. + */ + public void printInitialisationCompleteMessage() { + print("Thank you! DietBook has been initialised and you may start by entering any valid commands. " + + LINE_SEPARATOR + + "If you require a list of valid commands, you can enter: help"); + } + * * @param newFood The string representation of the new food item that was added to the food list. */ From f2f9560f4735d4267821bd40b2dc654b7e54869c Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 20:59:11 +0800 Subject: [PATCH 136/271] Update printTutorialMessage method --- src/main/java/seedu/dietbook/Ui.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 9033e7cd98..67d7ba28d7 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -86,23 +86,6 @@ public void printAskForUserInfoMessage(String name) { * Prints a message that notifies the user that DietBook has been initialised and shows a list of user * commands that the user can input. */ - public void printTutorialMessage() { - print("Thank you! DietBook has been initialised and you may start by entering any of the commands " - + "listed below." + LINE_SEPARATOR + LINE_SEPARATOR - + "To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE" + LINE_SEPARATOR - + "To view all food in the database: data" + LINE_SEPARATOR - + "To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] " - + "[p/PROTEIN] [f/FAT]" + LINE_SEPARATOR - + "To view all food in DietBook: list" + LINE_SEPARATOR - + "To delete a food from DietBook: delete INDEX" + LINE_SEPARATOR - + "To delete all food items from the DietBook: clear" + LINE_SEPARATOR - + "To show user information: userinfo" + LINE_SEPARATOR - + "To calculate carbohydrate intake: calculate carbohydrate" + LINE_SEPARATOR - + "To calculate calorie intake: calculate calorie" + LINE_SEPARATOR - + "To calculate protein intake: calculate protein" + LINE_SEPARATOR - + "To calculate fat intake: calculate fat" + LINE_SEPARATOR - + "To calculate all nutritional intake: calculate all" + LINE_SEPARATOR - + "To exit DietBook: exit"); } /** From e0315fbb7a708b4fd7bf483674df7fa84851ed10 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:00:10 +0800 Subject: [PATCH 137/271] Add getCalculatorRelatedCommands method --- src/main/java/seedu/dietbook/Ui.java | 39 ++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 67d7ba28d7..e7bf70ad88 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -261,16 +261,39 @@ private String getSystemRelatedCommands() { } /** - * Prints a message to show that the food specified has been deleted from the food list. + * Returns a string representation of a list of nutritional intake and recommendation related commands + * that users can input. * - * @param deletedFood The string representation of the food that was deleted from the food list. + * @return A string representation of a list of nutritional intake and recommendation related commands + * that users can input. */ - public void printDeletedFood(String deletedFood) { - assert deletedFood != null : "String representation of the food that was deleted should not be null"; - assert trimStringGetLength(deletedFood) > 0 : "String representation of the food that was deleted should" - + " not be an empty string"; - print("Noted. I've removed this food item:" + LINE_SEPARATOR - + " " + trimString(deletedFood)); + private String getCalculatorRelatedCommands() { + return " To get recommended calorie intake: recommend" + LINE_SEPARATOR + LINE_SEPARATOR + + " To calculate carbohydrate intake: calculate carbohydrate" + LINE_SEPARATOR + + " To calculate carbohydrate intake within a time period: calculate carbohydrate " + + "yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + + " To calculate carbohydrate intake from a certain date until now: calculate carbohydrate " + + "yyy-mm-ddTHH:mm" + LINE_SEPARATOR + LINE_SEPARATOR + + " To calculate calorie intake: calculate calorie" + LINE_SEPARATOR + + " To calculate calorie intake within a time period: calculate calorie yyyy-mm-ddTHH:mm " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + + " To calculate calorie intake from a certain date until now: calculate calorie " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + LINE_SEPARATOR + + " To calculate protein intake: calculate protein" + LINE_SEPARATOR + + " To calculate protein intake within a time period: calculate protein yyyy-mm-ddTHH:mm " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + + " To calculate protein intake from a certain date until now: calculate protein " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + LINE_SEPARATOR + + " To calculate fat intake: calculate fat" + LINE_SEPARATOR + + " To calculate fat intake within a time period: calculate fat yyyy-mm-ddTHH:mm " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + + " To calculate fat intake from a certain date until now: calculate fat " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + LINE_SEPARATOR + + " To calculate all nutritional intake: calculate all" + LINE_SEPARATOR + + " To calculate all nutritional intake within a time period: calculate all " + + "yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + + " To calculate all nutritional intake from a certain date until now: calculate all " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR; } /** From ee501adbf76c20c90019a25bbdd198c443f8611a Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:00:57 +0800 Subject: [PATCH 138/271] Add getUserRelatedCommands method --- src/main/java/seedu/dietbook/Ui.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index e7bf70ad88..863510d440 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -297,11 +297,15 @@ private String getCalculatorRelatedCommands() { } /** - * Prints a message to show that the food list has been successfully cleared and is now empty. + * Returns a string representation of a list of user information related commands that users can input. + * + * @return A string representation of a list of user information related commands that users can input. */ - public void printClearFoodListMessage() { - print("All previous data has been deleted..." + LINE_SEPARATOR - + "DietBook is now empty."); + private String getUserRelatedCommands() { + return " To show user information: userinfo" + LINE_SEPARATOR + + " To edit user information: editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] " + + "[o/ORIGINAL_WEIGHT] [c/CURRENT_WEIGHT] [t/TARGET_WEIGHT] [l/ACTIVITY_LEVEL]" + + LINE_SEPARATOR; } /** From 29618c87b423c2dc872c8702a36c65a9119948ab Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:01:38 +0800 Subject: [PATCH 139/271] Add getFoodListRelatedCommands method --- src/main/java/seedu/dietbook/Ui.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 863510d440..22ed842560 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -309,14 +309,20 @@ private String getUserRelatedCommands() { } /** - * Prints an exit message when DietBook is closed. + * Returns a string representation of a list of food list related commands that users can input. * - * @param name The name of the user. + * @return A string representation of a list of food list related commands that users can input. */ - public void printExitMessage(String name) { - assert name != null : "Name should not be null"; - assert trimStringGetLength(name) > 0 : "Name should not be an empty string"; - print("Bye " + trimString(name) + "! Hope to see you again soon!"); + private String getFoodListRelatedCommands() { + return " To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] " + + "[p/PROTEIN] [f/FAT]" + LINE_SEPARATOR + + " To view all food in DietBook: list" + LINE_SEPARATOR + + " To view all food in DietBook recorded within a time period: list yyyy-mm-ddTHH:mm " + + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + + " To view all food in DietBook recorded from a certain date until now: list " + + "yyyy-mm-ddTHH:mm " + LINE_SEPARATOR + + " To delete a food from DietBook: delete INDEX" + LINE_SEPARATOR + + " To delete all food items from the DietBook: clear" + LINE_SEPARATOR; } /** From 5927bccf19d8abe469c562b1d54624028863de35 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:08:15 +0800 Subject: [PATCH 140/271] Update Ui.java --- src/main/java/seedu/dietbook/Ui.java | 620 +++++++++++++++++++++++---- 1 file changed, 527 insertions(+), 93 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 22ed842560..64e20166f0 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -51,8 +51,8 @@ public void printWelcomeMessage() { * @param name The name of the user. */ public void printAskForUserInfoMessage(String name) { - assert name != null : "Name should not be null"; - assert trimStringGetLength(name) > 0 : "Name should not be an empty string"; + performAssertionsForStringInputs(name, "Name"); + print("Hi " + trimString(name) + "!" + LINE_SEPARATOR + "Before we get started, I would like to know about about you so that I can make more " + LINE_SEPARATOR @@ -80,12 +80,25 @@ public void printAskForUserInfoMessage(String name) { + " Example: info g/F a/21 h/165 o/65 c/65 t/55 l/2"); } + /** + * Prints an exit message when DietBook is closed. + * + * @param name The name of the user. + */ + public void printExitMessage(String name) { + performAssertionsForStringInputs(name, "Name"); + print("Bye " + trimString(name) + "! Hope to see you again soon!"); } /** - * Prints a message that notifies the user that DietBook has been initialised and shows a list of user - * commands that the user can input. + * Prints an error message given what or where the error is. + * + * @param errorMessage Message detailing what or where the error is. */ + public void printErrorMessage(String errorMessage) { + performAssertionsForStringInputs(errorMessage,"Error message"); + + print(":( " + trimString(errorMessage)); } /** @@ -97,17 +110,85 @@ public void printInitialisationCompleteMessage() { + "If you require a list of valid commands, you can enter: help"); } + /** + * Prints a string representation of a list of the commands that users can use. + */ + public void printHelpCommandMessage() { + print("Listed below are the valid commands for DietBook:" + LINE_SEPARATOR + LINE_SEPARATOR + + "For database related commands" + LINE_SEPARATOR + + getDatabaseRelatedCommands() + LINE_SEPARATOR + + "For food list related commands" + LINE_SEPARATOR + + getFoodListRelatedCommands() + LINE_SEPARATOR + + "For user information related commands" + LINE_SEPARATOR + + getUserRelatedCommands() + LINE_SEPARATOR + + "For nutritional intake and recommendation related commands" + LINE_SEPARATOR + + getCalculatorRelatedCommands() + LINE_SEPARATOR + + "For other system related commands" + LINE_SEPARATOR + + getSystemRelatedCommands()); + } + + // Methods required to print database related commands or messages. + + /** + * Prints all the food in the database sorted by the canteen and then the store it is found. * - * @param newFood The string representation of the new food item that was added to the food list. + * @param foodDatabase The string representation of all the food items stored in the database. */ - public void printNewFood(String newFood) { - assert newFood != null : "String representation of the food that was added should not be null"; - assert trimStringGetLength(newFood) > 0 : "String representation of the food that was added should not " - + "be an empty string"; - print("Got it! I've added this food item:" + LINE_SEPARATOR - + " " + trimString(newFood)); + public void printDatabase(String foodDatabase) { + performAssertionsForStringInputs(foodDatabase, + "Food database"); + + print("Here are the food items in the database:" + LINE_SEPARATOR + foodDatabase); } + /** + * Prints the food items in the database containing the food name of the food that user wants to + * add sorted by the canteen and then the store it is found. + * This method is only used if more than one food item in the database contains the food name given. + * + * @param matchingFoodDatabase The string representation of the food items stored in the + * database containing the food name given. + */ + public void printMatchingFoodsInDatabase(String matchingFoodDatabase) { + performAssertionsForStringInputs(matchingFoodDatabase, + "Matching food database"); + + print("Here are the matching food items in the database:" + LINE_SEPARATOR + + matchingFoodDatabase + LINE_SEPARATOR + LINE_SEPARATOR + + "Please re-enter with the full name of the food item above in the following format:" + + LINE_SEPARATOR + " add n/FOOD_NAME x/PORTION_SIZE"); + } + + // Methods required to print user information related commands and messages. + + /** + * Prints all the information related to the user. + * + * @param personInfo The user's personal information. + */ + public void printPersonInfo(String personInfo) { + performAssertionsForStringInputs(personInfo, + "Person information"); + + print("Here is your information:" + LINE_SEPARATOR + + personInfo); + } + + /** + * Prints all the updated information related to the user. + * + * @param personInfo The user's personal information. + */ + public void printEditedPersonInfo(String personInfo) { + performAssertionsForStringInputs(personInfo, + "Updated person information"); + + print("Here is your updated information:" + LINE_SEPARATOR + + personInfo); + } + + // Methods required for printing FoodList related commands and messages. + /** * Prints all the food items in the food list in the order that they were added or a message stating * that the food list is empty if there are no food items. @@ -115,11 +196,13 @@ assert trimStringGetLength(newFood) > 0 : "String representation of the food tha * @param allFood The string representation of all the food items in the food list. */ public void printFoodList(String allFood) { - assert allFood != null : "String representation of all food in food list should not be null"; + performAssertionsForNullStringInputs(allFood, + "String representation of all food in food list"); + if (trimStringGetLength(allFood) < 1) { print("DietBook is currently empty."); } else { - print("Here are the food items in DietBook:" + LINE_SEPARATOR + trimString(allFood)); + print("Here are the food items in DietBook:" + LINE_SEPARATOR + allFood); } } @@ -132,43 +215,44 @@ public void printFoodList(String allFood) { * @param start Starting date time of the time period given. * @param end Ending date time of the time period given. */ - public void printFoodListGivenTimePeriod(String foods, LocalDateTime start, LocalDateTime end) { - assert foods != null : "String representation of food items in the food list recorded during the " - + "time period given should not be null"; - assert start != null : "Starting date time of the time period should not be null"; - assert end != null : "Ending date time of the time period should not be null"; - assert !start.isAfter(end) : "Starting date time should not be later than ending date time " - + "of the time period"; - String stringStart = stringDateTime(start); - String stringEnd = stringDateTime(end); + public void printFoodList(String foods, LocalDateTime start, LocalDateTime end) { + performAssertionsForNullStringInputs(foods, + "String representation of food items in the food list recorded during the time " + + "period given"); + performAssertionsForTimePeriod(start, end); + if (trimStringGetLength(foods) < 1) { - print("No food item was recorded in DietBook between " + stringStart + " and " + stringEnd + "."); + print("No food item was recorded in DietBook" + stringDateTimePeriod(start, end) + "."); } else { - print("Here are the food items recorded in DietBook between " + stringStart + " and " + stringEnd - + " :" + LINE_SEPARATOR + trimString(foods)); + print("Here are the food items recorded in DietBook" + stringDateTimePeriod(start, end) + ":" + + LINE_SEPARATOR + foods); } } /** - * Returns a string representation of the date time in the format dd MMM yyyy HHmm. + * Prints a message to show that the food specified has been added to the food list. * - * @param dateTime The date time that needs to be converted into a String. - * @return Returns a string representation of the date and time in the format dd MMM yyyy HHmm. + * @param newFood The string representation of the new food item that was added to the food list. */ - public String stringDateTime(LocalDateTime dateTime) { - assert dateTime != null : "Date time to be converted into string should not be null"; - return dateTime.format(DateTimeFormatter.ofPattern("dd MMM yyyy HHmm")); + public void printNewFood(String newFood) { + performAssertionsForStringInputs(newFood, + "String representation of the food that was added"); + + print("Got it! I've added this food item:" + LINE_SEPARATOR + + " " + trimString(newFood)); } /** - * Prints all the food in the database sorted by the canteen and then the store it is found. + * Prints a message to show that the food specified has been deleted from the food list. * - * @param foodDatabase The string representation of all the food items stored in the database. + * @param deletedFood The string representation of the food that was deleted from the food list. */ - public void printDatabase(String foodDatabase) { - assert foodDatabase != null : "Food database should not be null"; - assert trimStringGetLength(foodDatabase) > 0 : "Food database should not be empty"; - print("Here are the food items in the database:" + LINE_SEPARATOR + trimString(foodDatabase)); + public void printDeletedFood(String deletedFood) { + performAssertionsForStringInputs(deletedFood, + "String representation of the food that was deleted"); + + print("Noted. I've removed this food item:" + LINE_SEPARATOR + + " " + trimString(deletedFood)); } /** @@ -179,75 +263,227 @@ public void printClearFoodListMessage() { + "DietBook is now empty."); } + // Methods required to print nutritional intake and recommendation related commands and messages. + + /** + * Prints the daily recommended calorie intake of the user based on the user's personal information. + * + * @param calorieRecommendation The daily recommended calorie intake of the user. + */ + public void printCalorieRecommendation(String name, int calorieRecommendation) { + performAssertionsForStringInputs(name, "Name"); + performAssertionsForCalorieRecommendation(calorieRecommendation); + + print("Hi " + trimString(name) + "!" + LINE_SEPARATOR + + "Here is your daily recommended calorie intake: " + calorieRecommendation + "kcal"); + } + + /** + * Prints the total amount of carbohydrates consumed by the user and the list of food items which had + * their nutritional information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total carbohydrate intake. * - * @param personInfo The user's personal information. + * @param carbIntake The total amount of carbohydrates of all the food in the food list. + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. */ - public void printPersonInfo(String personInfo) { - assert personInfo != null : "Person information should not be null"; - assert trimStringGetLength(personInfo) > 0 : "Person information should not be an empty string"; - print("Here is your information:" + LINE_SEPARATOR - + trimString(personInfo)); + public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods) { + print(stringOneIntakeAndFoodsWithoutTime(carbIntake,"carbohydrate", + "g", recalculatedFoods)); } /** - * Prints the total amount of carbohydrates consumed by the user. + * Prints the total amount of carbohydrates consumed by the user within a given time period and a list of + * the foods recorded into the food list during the same time period which had their nutritional + * information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total carbohydrate + * intake within a given time period. * - * @param carbohydrateIntake The total amount of carbohydrates of all the food in the food list. + * @param carbIntake The total amount of carbohydrates of food in the food list recorded during the + * time period given. + * @param recalculatedFoods The list of food items recorded during the given time period which had their + * nutritional information recalculated by DietBook. + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. */ - public void printCarbohydrateIntake(int carbohydrateIntake) { - assert carbohydrateIntake >= 0 : "Total carbohydrate intake should be equals to or greater than 0"; - print("Total carbohydrate intake: " + carbohydrateIntake + "g"); + public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods, + LocalDateTime start, LocalDateTime end) { + String carbIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(carbIntake, + "carbohydrate", "g", recalculatedFoods); + print(stringIntakeAndFoodsWithTime(carbIntakeAndFoodsWithoutTime, start, end)); } /** - * Prints the total amount of calories consumed by the user. + * Prints the total amount of calories consumed by the user and the list of food items which had + * their nutritional information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total calorie intake. * * @param calorieIntake The total amount of calories of all the food in the food list. + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. + */ + public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoods) { + print(stringOneIntakeAndFoodsWithoutTime(calorieIntake,"calorie","kcal", + recalculatedFoods)); + } + + /** + * Prints the total amount of calories consumed by the user within a given time period and a list of + * the foods recorded into the food list during the same time period which had their nutritional + * information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total calorie + * intake within a given time period. + * + * @param calorieIntake The total amount of calories of food in the food list recorded during the + * time period given. + * @param recalculatedFoods The list of food items recorded during the given time period which had their + * nutritional information recalculated by DietBook. + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. */ - public void printCalorieIntake(int calorieIntake) { - assert calorieIntake >= 0 : "Total calorie intake should be equals to or greater than 0"; - print("Total calorie intake: " + calorieIntake + "kcal"); + public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoods, + LocalDateTime start, LocalDateTime end) { + String calorieIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(calorieIntake, + "calorie", "kcal", recalculatedFoods); + print(stringIntakeAndFoodsWithTime(calorieIntakeAndFoodsWithoutTime, start, end)); } /** - * Prints the total amount of proteins consumed by the user. + * Prints the total amount of proteins consumed by the user and the list of food items which had + * their nutritional information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total protein intake. * * @param proteinIntake The total amount of proteins of all the food in the food list. + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. + */ + public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoods) { + print(stringOneIntakeAndFoodsWithoutTime(proteinIntake,"protein","g", + recalculatedFoods)); + } + + /** + * Prints the total amount of proteins consumed by the user within a given time period and a list of + * the foods recorded into the food list during the same time period which had their nutritional + * information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total protein + * intake within a given time period. + * + * @param proteinIntake The total amount of proteins of food in the food list recorded during the + * time period given. + * @param recalculatedFoods The list of food items recorded during the given time period which had their + * nutritional information recalculated by DietBook. + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. */ - public void printProteinIntake(int proteinIntake) { - assert proteinIntake >= 0 : "Total protein intake should be equals to or greater than 0 "; - print("Total protein intake: " + proteinIntake + "g"); + public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoods, + LocalDateTime start, LocalDateTime end) { + String proteinIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(proteinIntake, + "protein", "g", recalculatedFoods); + print(stringIntakeAndFoodsWithTime(proteinIntakeAndFoodsWithoutTime, start, end)); } /** - * Prints the total amount of fats consumed by the user. + * Prints the total amount of fats consumed by the user and the list of food items which had + * their nutritional information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total fat intake. * * @param fatIntake The total amount of fats of all the food in the food list. + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. + */ + public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods) { + print(stringOneIntakeAndFoodsWithoutTime(fatIntake,"fat","g", + recalculatedFoods)); + } + + /** + * Prints the total amount of fats consumed by the user within a given time period and a list of + * the foods recorded into the food list during the same time period which had their nutritional + * information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total fat + * intake within a given time period. + * + * @param fatIntake The total amount of fats of food in the food list recorded during the + * time period given. + * @param recalculatedFoods The list of food items recorded during the given time period which had their + * nutritional information recalculated by DietBook. + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. */ - public void printFatIntake(int fatIntake) { - assert fatIntake >= 0 : "Total fat intake should be equals to or greater than 0"; - print("Total fat intake: " + fatIntake + "g"); + public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, + LocalDateTime start, LocalDateTime end) { + String fatIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(fatIntake, + "fat", "g", recalculatedFoods); + print(stringIntakeAndFoodsWithTime(fatIntakeAndFoodsWithoutTime, start, end)); } /** - * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user. + * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and the + * list of food items which had their nutritional information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating the individual intakes. * + * @param carbIntake The total amount of carbohydrates of all the food in the food list. * @param calorieIntake The total amount of calories of all the food in the food list. - * @param carbohydrateIntake The total amount of carbohydrates of all the food in the food list. * @param proteinIntake The total amount of proteins of all the food in the food list. * @param fatIntake The total amount of fats of all the food in the food list. + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. + */ + public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake, String recalculatedFoods) { + print(stringAllIntakeAndFoodsWithoutTime(carbIntake, calorieIntake,proteinIntake, + fatIntake, recalculatedFoods)); + } + + /** + * Prints the total amount of total amount of calories, carbohydrates, fats and proteins consumed by + * the user within a given time period and a list of the foods recorded into the food list during the + * same time period which had their nutritional information recalculated by DietBook if any. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating the individual intake + * within a given time period. + * + * @param calorieIntake The total amount of calories of food in the food list recorded during the + * time period given. + * @param carbIntake The total amount of carbohydrates of food in the food list recorded during the + * time period given. + * @param proteinIntake The total amount of proteins of food in the food list recorded during the + * time period given. + * @param fatIntake The total amount of fats of food in the food list recorded during the + * time period given. + * @param recalculatedFoods The list of food items recorded during the given time period which had their + * nutritional information recalculated by DietBook. + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. */ - public void printAllNutrientIntake(int calorieIntake, int carbohydrateIntake, int proteinIntake, - int fatIntake) { - assert carbohydrateIntake >= 0 : "Total carbohydrate intake should be equals to or greater than 0"; - assert calorieIntake >= 0 : "Total calorie intake should be equals to or greater than 0"; - assert proteinIntake >= 0 : "Total protein intake should be equals to or greater than 0 "; - assert fatIntake >= 0 : "Total fat intake should be equals to or greater than 0"; - - print("Total calorie intake: " + calorieIntake + "kcal" + LINE_SEPARATOR - + "Total carbohydrate intake: " + carbohydrateIntake + "g" + LINE_SEPARATOR - + "Total protein intake: " + proteinIntake + "g" + LINE_SEPARATOR - + "Total fat intake: " + fatIntake + "g"); + public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake, String recalculatedFoods, + LocalDateTime start, LocalDateTime end) { + String allIntakeAndFoodsWithoutTime = stringAllIntakeAndFoodsWithoutTime(carbIntake, calorieIntake, + proteinIntake,fatIntake, recalculatedFoods); + print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); + } + // Helper methods for system related commands or messages /** @@ -326,16 +562,168 @@ private String getFoodListRelatedCommands() { } /** - * Prints an error message given what or where the error is. + * Returns a string representation of a list of database related commands that users can input. * - * @param errorMessage Message detailing what or where the error is. + * @return A string representation of a list of database related commands that users can input. */ - public void printErrorMessage(String errorMessage) { - assert errorMessage != null : "Error message should not be null"; - assert trimStringGetLength(errorMessage) > 0 : "Error message should not be an empty string"; - print(":( Oh no..." + trimString(errorMessage)); + private String getDatabaseRelatedCommands() { + return " To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE" + LINE_SEPARATOR + + " To view all food in the database: data" + LINE_SEPARATOR; } + // Helper methods for calculator related commands and messages + + /** + * Returns a string with a header and recalculatedFoods or a string stating that no food items had their + * nutritional information recalculated if calculatedFoods is an empty string. + * + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. + * @return A string with a header and recalculatedFoods or a string stating that no food items had their + * nutritional information recalculated if calculatedFoods is an empty string. + */ + private String recalculatedFoodsMessage(String recalculatedFoods) { + String message = "No food items had their nutritional information recalculated by DietBook."; + if (trimStringGetLength(recalculatedFoods) > 0) { + message = "Food items which had their nutritional information recalculated by DietBook: " + + LINE_SEPARATOR + recalculatedFoods; + } + return message; + } + + /** + * Return a string representation of the amount of a nutrient consumed by the user which can be either + * the total amount consumed or amount consumed in a given time period. + * + * @param nutrientIntake The amount of a particular type of nutrient consumed. + * @param nutrientType A string representation of the type of nutrient consumed. + * @param nutrientUnit A string representation of the unit of the nutrient consumed. + * @return The amount of a nutrient consumed by the user which can be either the total amount consumed + * or amount consumed in a given time period. + */ + private String stringNutritionalIntake(int nutrientIntake, String nutrientType, String nutrientUnit) { + return "Total " + nutrientType + " intake: " + nutrientIntake + nutrientUnit; + } + + /** + * Returns a string representation of the total amount of a nutrient consumed by the user and + * the list of food items which had their nutritional information recalculated by DietBook if any. + * + * @param nutrientIntake The amount of a particular type of nutrient consumed. + * @param nutrientType A string representation of the type of nutrient consumed. + * @param nutrientUnit A string representation of the unit of the nutrient consumed. + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. + * @return A string representation of the the total amount of a nutrient consumed by the user and + * the list of food items which had their nutritional information recalculated by DietBook if any. + */ + private String stringOneIntakeAndFoodsWithoutTime(int nutrientIntake, String nutrientType, + String nutrientUnit, String recalculatedFoods) { + performAssertionsForStringInputs(nutrientType,"Nutrient Type"); + performAssertionsForStringInputs(nutrientUnit, "Nutrient Unit"); + performAssertionsForNutritionalIntake(nutrientIntake, nutrientType); + performAssertionsForNullStringInputs(recalculatedFoods, + "List of foods that had their nutritional information recalculated"); + + String stringNutrientIntake = stringNutritionalIntake(nutrientIntake, nutrientType, nutrientUnit); + String message = recalculatedFoodsMessage(recalculatedFoods); + return stringNutrientIntake + LINE_SEPARATOR + message; + } + + /** + * Returns a string representation of the total amount of a nutrient or all nutrientS consumed by the + * user during a given time period and the list of food items recorded during the same time period + * which had their nutritional information recalculated by DietBook if any. + * + * @param intakeAndFoodsWithoutTime A string representation of the the total amount of a nutrient or + * all nutrients consumed by the user and the list of food items which had their nutritional + * information recalculated by DietBook if any. + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. + * @return A string representation of the the total amount of a nutrient or all nutrient consumed by the + * user during a given time period and the list of food items recorded during the same time period + * which had their nutritional information recalculated by DietBook if any. + */ + private String stringIntakeAndFoodsWithTime(String intakeAndFoodsWithoutTime, + LocalDateTime start, LocalDateTime end) { + performAssertionsForTimePeriod(start, end); + + String timePeriod = "Time period:" + stringDateTimePeriod(start, end); + return timePeriod + LINE_SEPARATOR + LINE_SEPARATOR + intakeAndFoodsWithoutTime; + } + + /** + * Returns a string representation of the total amount of all nutrients consumed by the user and + * the list of food items which had their nutritional information recalculated by DietBook if any. + * + * @param carbIntake The total amount of carbohydrates of all the food in the food list. + * @param calorieIntake The total amount of calories of all the food in the food list. + * @param proteinIntake The total amount of proteins of all the food in the food list. + * @param fatIntake The total amount of fats of all the food in the food list. + * @param recalculatedFoods The list of food items which had their nutritional information recalculated by + * DietBook. + * @return A string representation of the total amount of all nutrients consumed by the user and + * the list of food items which had their nutritional information recalculated by DietBook if any. + */ + private String stringAllIntakeAndFoodsWithoutTime(int carbIntake, int calorieIntake, int proteinIntake, + int fatIntake, String recalculatedFoods) { + performAssertionsForNutritionalIntake(carbIntake, "carbohydrate"); + performAssertionsForNutritionalIntake(calorieIntake, "calorie"); + performAssertionsForNutritionalIntake(proteinIntake, "protein"); + performAssertionsForNutritionalIntake(fatIntake, "fat"); + performAssertionsForNullStringInputs(recalculatedFoods, + "List of foods that had their nutritional information recalculated"); + + String stringCarbIntake = stringNutritionalIntake(carbIntake,"carbohydrate", "g"); + String stringCalorieIntake = stringNutritionalIntake(calorieIntake,"calorie", + "kcal"); + String stringProteinIntake = stringNutritionalIntake(proteinIntake,"protein", "g"); + String stringFatIntake = stringNutritionalIntake(fatIntake,"fat", "g"); + String message = recalculatedFoodsMessage(recalculatedFoods); + + return stringCarbIntake + LINE_SEPARATOR + + stringCalorieIntake + LINE_SEPARATOR + + stringProteinIntake + LINE_SEPARATOR + + stringFatIntake + LINE_SEPARATOR + + message; + + } + + // Other helper methods + + /** + * Prints the given message to the user. + * + * @param message The message to show the user. + */ + private void print(String message) { + performAssertionsForStringInputs(message, "Message to print"); + String divider = + "__________________________________________________________________________________________" + + "___________________________________________"; + + System.out.println(divider + LINE_SEPARATOR + + trimString(message) + LINE_SEPARATOR + + divider); + + } + + /** + * Returns a string representation of the time period with date time in the format dd MMM yyyy HHmm. + * + * @param start Starting date time of the time period given that needs to be converted into a String. + * @param end Ending date time of the time period given that needs to be converted into a String. + * @return The string representation of time period with date time in the format dd MMM yyyy HHmm. + */ + public String stringDateTimePeriod(LocalDateTime start, LocalDateTime end) { + performAssertionsForTimePeriod(start, end); + + String stringStart = start.format(DateTimeFormatter.ofPattern("dd MMM yyyy HHmm")); + String stringEnd = end.format(DateTimeFormatter.ofPattern("dd MMM yyyy HHmm")); + return " between " + stringStart + " and " + stringEnd; + } + + /** * Returns an integer representing the length of the string after it has been trimmed for leading and * trailing spaces. @@ -345,7 +733,8 @@ public void printErrorMessage(String errorMessage) { * trailing spaces. */ public int trimStringGetLength(String string) { - assert string != null : "String to trim and have length determined should not be null"; + performAssertionsForNullStringInputs(string, "String to trim and have length determined"); + return trimString(string).length(); } @@ -355,26 +744,71 @@ public int trimStringGetLength(String string) { * @param string The string to be trimmed for leading and trailing spaces. * @return A string that has been trimmed for leading and trailing spaces. */ - public String trimString(String string) { - assert string != null : "String to trim should not be null"; + private String trimString(String string) { + performAssertionsForNullStringInputs(string, "String to trim"); + return string.trim(); } /** - * Prints the given message to the user. + * Performs assertions for the string inputs. * - * @param message The message to show the user. + * @param string The input value. + * @param stringDescription A description of what the input value represents. */ - public void print(String message) { - assert message != null : "Message to print should not be null"; - assert trimStringGetLength(message) > 0 : "Message to print should not be an empty string"; - String divider = - "__________________________________________________________________________________________" - + "____________________"; + private void performAssertionsForStringInputs(String string, String stringDescription) { + performAssertionsForNullStringInputs(string, stringDescription); + assert trimStringGetLength(string) > 0 : stringDescription + " should not be an empty string"; + } - System.out.println(divider + LINE_SEPARATOR - + trimString(message) + LINE_SEPARATOR - + divider); + /** + * Performs assertions for the time inputs. + * + * @param start Starting date time of the time period given. + * @param end Ending date time of the time period given. + */ + private void performAssertionsForTimePeriod(LocalDateTime start, LocalDateTime end) { + assert start != null : "Starting date time of the time period given should not be null"; + assert end != null : "Ending date time of the time period given should not be null"; + assert !start.isAfter(end) : "Starting date time should not be later than ending date time " + + "of the time period"; + assert start.isBefore(LocalDateTime.now()) : "Starting date time of the time period given should " + + "not be in the future"; + assert end.isBefore(LocalDateTime.now()) : "Ending date time of the time period given should not be" + + " in the future"; + } + + /** + * Performs assertions for null string inputs. + * + * @param string The input value. + * @param stringDescription A description of what the input value represents. + */ + private void performAssertionsForNullStringInputs(String string, String stringDescription) { + assert string != null : stringDescription + " should not be null"; + } + + /** + * Performs assertions for nutritional intake inputs. + * + * @param nutrientIntake The nutritional intake value. + * @param nutrientType The nutrient type. + */ + private void performAssertionsForNutritionalIntake(int nutrientIntake, String nutrientType) { + assert nutrientIntake >= 0 : "Total " + nutrientType + " intake should be equals to or greater than 0"; + } + /** + * Performs assertions for the calorie recommendation input. + * + * @param calorieRecommendation The recommended daily calorie intake for the user. + */ + private void performAssertionsForCalorieRecommendation(int calorieRecommendation) { + // A minimum daily intake of 1200 calorie is required to stay healthy. + assert calorieRecommendation >= 1200 : "Daily calorie recommendation should be equals to or greater" + + " than 1200"; + // Highest calorie intake for an athlete currently stands at 12000. + assert calorieRecommendation <= 12000 : "Daily calorie recommendation should be equals to or less " + + "than 12,000"; } } From 367c9cd7d67b4f24e7016646746cf0b911fa85e6 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:08:54 +0800 Subject: [PATCH 141/271] Update JUnit test for Ui class --- src/test/java/seedu/dietbook/UiTest.java | 72 +++++++++++++++--------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/src/test/java/seedu/dietbook/UiTest.java b/src/test/java/seedu/dietbook/UiTest.java index 35314fb5f5..b69ebcfbe3 100644 --- a/src/test/java/seedu/dietbook/UiTest.java +++ b/src/test/java/seedu/dietbook/UiTest.java @@ -18,69 +18,85 @@ public void setUp() { } @Test - void stringDateTime_nullInput_expectAssertionError() { - assertThrows(AssertionError.class, () -> ui.stringDateTime(null)); + void stringDateTimePeriod_startDateTimeIsNullInput_expectAssertionError() { + LocalDateTime end = LocalDateTime.parse("2020-10-21T23:59"); + assertThrows(AssertionError.class, () -> ui.stringDateTimePeriod(null, end)); } @Test - void stringDateTime_LocalDateTime_returnsStringOfLocalDateTime() { - LocalDateTime dateTime = LocalDateTime.parse("2020-10-21T23:59"); - assertEquals("21 Oct 2020 2359",ui.stringDateTime(dateTime)); + void stringDateTimePeriod_endDateTimeIsNullInput_expectAssertionError() { + LocalDateTime start = LocalDateTime.parse("2020-10-21T23:59"); + assertThrows(AssertionError.class, () -> ui.stringDateTimePeriod(start, null)); } @Test - void stringDateTime_LocalDateTimeWithSeconds_returnsStringOfLocalDateTimeWithoutSeconds() { - LocalDateTime dateTime = LocalDateTime.parse("2020-10-21T23:59:22"); - assertEquals("21 Oct 2020 2359",ui.stringDateTime(dateTime)); + void stringDateTimePeriod_endDateTimeIsBeforeStartTime_expectAssertionError() { + LocalDateTime start = LocalDateTime.parse("2020-10-21T23:59"); + LocalDateTime end = LocalDateTime.parse("2020-10-20T23:59"); + assertThrows(AssertionError.class, () -> ui.stringDateTimePeriod(start, end)); } @Test - void trimStringGetLength_nullInput_expectAssertionError() { - assertThrows(AssertionError.class, () -> ui.trimStringGetLength(null)); + void stringDateTimePeriod_endDateTimeIsInTheFuTure_expectAssertionError() { + LocalDateTime start = LocalDateTime.parse("2020-10-21T23:59"); + LocalDateTime end = LocalDateTime.now().plusDays(3); + assertThrows(AssertionError.class, () -> ui.stringDateTimePeriod(start, end)); } @Test - void trimStringGetLength_stringWithNoLeadingOrTrailingSpaces_returnsLengthFour() { - assertEquals(4, ui.trimStringGetLength("food")); + void stringDateTimePeriod_StartDateTimeIsInTheFuture_expectAssertionError() { + LocalDateTime start = LocalDateTime.now().plusDays(3); + LocalDateTime end = LocalDateTime.now().plusDays(5); + assertThrows(AssertionError.class, () -> ui.stringDateTimePeriod(start, end)); } + @Test - void trimStringGetLength_StringWithLeadingSpaces_returnsLengthFour() { - assertEquals(4, ui.trimStringGetLength(" food")); + void stringDateTimePeriod_sameStartAndEndDateTime_returnsStringOfTimePeriod() { + LocalDateTime start = LocalDateTime.parse("2020-10-21T23:59"); + LocalDateTime end = LocalDateTime.parse("2020-10-21T23:59"); + assertEquals(" between 21 Oct 2020 2359 and 21 Oct 2020 2359", + ui.stringDateTimePeriod(start, end)); } @Test - void trimStringGetLength_StringWithTrailingSpaces_returnsLengthFour() { - assertEquals(4, ui.trimStringGetLength("food ")); + void stringDateTimePeriod_validStartAndEndDateTime_returnsStringOfTimePeriod() { + LocalDateTime start = LocalDateTime.parse("2020-10-19T23:59"); + LocalDateTime end = LocalDateTime.parse("2020-10-21T23:59"); + assertEquals(" between 19 Oct 2020 2359 and 21 Oct 2020 2359", + ui.stringDateTimePeriod(start, end)); } @Test - void trimStringGetLength_StringWithLeadingAndTrailingSpaces_returnsLengthFour() { - assertEquals(4, ui.trimStringGetLength(" food ")); + void stringDateTimePeriod_validStartAndEndDateTimeWithSeconds_returnsStringOfTimePeriodWithoutSeconds() { + LocalDateTime start = LocalDateTime.parse("2020-10-19T23:59:22"); + LocalDateTime end = LocalDateTime.parse("2020-10-21T23:59:22"); + assertEquals(" between 19 Oct 2020 2359 and 21 Oct 2020 2359", + ui.stringDateTimePeriod(start, end)); } @Test - void trimString_nullInput_expectAssertionError() { - assertThrows(AssertionError.class, () -> ui.trimString(null)); + void trimStringGetLength_nullInput_expectAssertionError() { + assertThrows(AssertionError.class, () -> ui.trimStringGetLength(null)); } @Test - void trimString_StringWithLeadingSpaces_returnsStringWithoutLeadingSpaces() { - assertEquals("food", ui.trimString(" food")); + void trimStringGetLength_stringWithNoLeadingOrTrailingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength("food")); } @Test - void trimString_StringWithTrailingSpaces_returnsStringWithoutTrailingSpaces() { - assertEquals("food", ui.trimString("food ")); + void trimStringGetLength_StringWithLeadingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength(" food")); } @Test - void trimString_StringWithLeadingAndTrailingSpaces_returnsStringWithoutLeadingAndTrailingSpaces() { - assertEquals("food", ui.trimString(" food ")); + void trimStringGetLength_StringWithTrailingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength("food ")); } @Test - void trimString_StringWithNoLeadingAndTrailingSpaces_returnsString() { - assertEquals("food", ui.trimString("food")); + void trimStringGetLength_StringWithLeadingAndTrailingSpaces_returnsLengthFour() { + assertEquals(4, ui.trimStringGetLength(" food ")); } } From 1263c9953ec81b4f227d9d72da1261767d3656fb Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:19:30 +0800 Subject: [PATCH 142/271] Update Command Classes --- .../seedu/dietbook/command/CalculateCommand.java | 15 ++++++++++----- .../java/seedu/dietbook/command/DataCommand.java | 2 +- .../java/seedu/dietbook/command/HelpCommand.java | 2 +- .../java/seedu/dietbook/command/InfoCommand.java | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/dietbook/command/CalculateCommand.java b/src/main/java/seedu/dietbook/command/CalculateCommand.java index 6884bf315b..babeab4194 100644 --- a/src/main/java/seedu/dietbook/command/CalculateCommand.java +++ b/src/main/java/seedu/dietbook/command/CalculateCommand.java @@ -23,19 +23,24 @@ public void execute(Manager manager, Ui ui) { manager.setCalculator(); switch (this.param) { case "all": - ui.printAllNutrientIntake(this.calorie, this.carb, this.protein, this.fat); + //ui.printAllIntakeAndFoods(); + //ui.printAllNutrientIntake(this.calorie, this.carb, this.protein, this.fat); break; case "calorie": - ui.printCalorieIntake(this.calorie); + //ui.printCalorieIntakeAndFoods(); + //ui.printCalorieIntake(this.calorie); break; case "carbohydrate": - ui.printCarbohydrateIntake(this.carb); + //ui.printCarbIntakeAndFoods(); + //ui.printCarbohydrateIntake(this.carb); break; case "protein": - ui.printProteinIntake(this.protein); + //ui.printProteinIntakeAndFoods(); + //ui.printProteinIntake(this.protein); break; default: - ui.printFatIntake(this.fat); + //ui.printFatIntakeAndFoods(); + //ui.printFatIntake(this.fat); } } } diff --git a/src/main/java/seedu/dietbook/command/DataCommand.java b/src/main/java/seedu/dietbook/command/DataCommand.java index 12db1c7202..deb0767b9a 100644 --- a/src/main/java/seedu/dietbook/command/DataCommand.java +++ b/src/main/java/seedu/dietbook/command/DataCommand.java @@ -8,6 +8,6 @@ public class DataCommand extends Command { @Override public void execute(Manager manager, Ui ui) { manager.getDataBase().init(); - ui.printDatabase(manager.getDataBase().getFoodList()); + //ui.printDatabase(manager.getDataBase().getFoodList()); } } diff --git a/src/main/java/seedu/dietbook/command/HelpCommand.java b/src/main/java/seedu/dietbook/command/HelpCommand.java index 30a57a593f..733cb3e3bb 100644 --- a/src/main/java/seedu/dietbook/command/HelpCommand.java +++ b/src/main/java/seedu/dietbook/command/HelpCommand.java @@ -6,6 +6,6 @@ public class HelpCommand extends Command { @Override public void execute(Manager manager, Ui ui) { - ui.printTutorialMessage(); + ui.printHelpCommandMessage(); } } diff --git a/src/main/java/seedu/dietbook/command/InfoCommand.java b/src/main/java/seedu/dietbook/command/InfoCommand.java index c189c46be3..8a7f215b13 100644 --- a/src/main/java/seedu/dietbook/command/InfoCommand.java +++ b/src/main/java/seedu/dietbook/command/InfoCommand.java @@ -15,6 +15,6 @@ public InfoCommand(String userInput) { @Override public void execute(Manager manager, Ui ui) throws DietException { Parser.executeProcessedInfo(this.userInput, manager); - ui.printTutorialMessage(); + ui.printInitialisationCompleteMessage(); } } From e3dec2a1867cce23ba7740bb0bbee83fd5c12d78 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:28:47 +0800 Subject: [PATCH 143/271] Update I/O testing --- text-ui-test/EXPECTED.TXT | 32 ++++++++++++++++++++++++++++---- text-ui-test/input.txt | 2 ++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index f47f7db415..da9d65fe70 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,5 +1,5 @@ -________________________________________________________________________________________________________________________________________________ - _______ __ ______ ________ _______ ______ ______ __ __ +_____________________________________________________________________________________________________________________________________ +_______ __ ______ ________ _______ ______ ______ __ __ | __ \| | ___|__ __| __ \ / __ \ / __ \| | / / | | | | | |___ | | | |__| | | | | | | | |/ / | | | | | ___| | | | __ <| | | | | | | / @@ -10,5 +10,29 @@ Hello! Welcome to DietBook! I am Diet, your guide to using DietBook. What is your name? Please input in the following format: name YOUR_NAME -________________________________________________________________________________________________________________________________________________ -__________________ + Example: name Jack +_____________________________________________________________________________________________________________________________________ +_____________________________________________________________________________________________________________________________________ +Hi Jack! +Before we get started, I would like to know about about you so that I can make more +accurate calculations for you :). Therefore, could you please share with me the following: +- Your gender either F for female or M for male or O for others. +- Your age which is a positive integer. +- Your height in cm. +- Your original weight in kg, the weight when you first started using DietBook or you current weight. +- Your current weight in kg. +- Your target weight in kg, or your current weight if that is also your target weight. +- Your activity level, represented by a number from 1 to 5. + 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. + 2 = You engage in some form of light exercise or have a job that requires some physical activity. + 3 = You engage in moderate amount of exercise or have a job that requires moderate physical activity. + 4 = You engage in vigorous exercise or have a physically demanding job. + 5 = You engage in extremely vigorous exercise or have an extremely physically demanding job. + +Please input your details in the following format: + info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT c/CURRENT_WEIGHT t/TARGET_WEIGHT l/ACTIVITY_LEVEL + Example: info g/F a/21 h/165 o/65 c/65 t/55 l/2 +_____________________________________________________________________________________________________________________________________ +_____________________________________________________________________________________________________________________________________ +Bye Jack! Hope to see you again soon! +_____________________________________________________________________________________________________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..002f71500b 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,2 @@ +name Jack +exit \ No newline at end of file From 77776c385dcd4fcd6e660e9897d61f2014b859e3 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:41:08 +0800 Subject: [PATCH 144/271] Update I/O testing --- text-ui-test/EXPECTED.TXT | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index da9d65fe70..61ea9ffb41 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -14,8 +14,8 @@ Please input in the following format: _____________________________________________________________________________________________________________________________________ _____________________________________________________________________________________________________________________________________ Hi Jack! -Before we get started, I would like to know about about you so that I can make more -accurate calculations for you :). Therefore, could you please share with me the following: +Before we get started, I would like to know about about you. +Therefore, could you please share with me the following so I can make more accurate calculations for you :) - Your gender either F for female or M for male or O for others. - Your age which is a positive integer. - Your height in cm. From e8f0c5d2137aae7a63ad9ed21e87dbf59e78e5a8 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 21:53:58 +0800 Subject: [PATCH 145/271] Update I/O testing --- text-ui-test/EXPECTED.TXT | 23 +---------------------- text-ui-test/input.txt | 1 - 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 61ea9ffb41..01a5413702 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -13,26 +13,5 @@ Please input in the following format: Example: name Jack _____________________________________________________________________________________________________________________________________ _____________________________________________________________________________________________________________________________________ -Hi Jack! -Before we get started, I would like to know about about you. -Therefore, could you please share with me the following so I can make more accurate calculations for you :) -- Your gender either F for female or M for male or O for others. -- Your age which is a positive integer. -- Your height in cm. -- Your original weight in kg, the weight when you first started using DietBook or you current weight. -- Your current weight in kg. -- Your target weight in kg, or your current weight if that is also your target weight. -- Your activity level, represented by a number from 1 to 5. - 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. - 2 = You engage in some form of light exercise or have a job that requires some physical activity. - 3 = You engage in moderate amount of exercise or have a job that requires moderate physical activity. - 4 = You engage in vigorous exercise or have a physically demanding job. - 5 = You engage in extremely vigorous exercise or have an extremely physically demanding job. - -Please input your details in the following format: - info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT c/CURRENT_WEIGHT t/TARGET_WEIGHT l/ACTIVITY_LEVEL - Example: info g/F a/21 h/165 o/65 c/65 t/55 l/2 -_____________________________________________________________________________________________________________________________________ -_____________________________________________________________________________________________________________________________________ -Bye Jack! Hope to see you again soon! +Bye John Doe! Hope to see you again soon! _____________________________________________________________________________________________________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 002f71500b..ae3bc0a936 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,2 +1 @@ -name Jack exit \ No newline at end of file From 5ca5ddc47ad88b40e0f9b65f8f5647b06bef0cf8 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Sat, 24 Oct 2020 22:38:31 +0800 Subject: [PATCH 146/271] Update Gender --- src/main/java/seedu/dietbook/parser/Parser.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 59283b0353..1e505e4fc9 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -145,10 +145,10 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw case "g/": String processGender = trimmedParam; InputChecker.checkGender(processGender); - if (processGender.equals("M")) { - gender = Gender.MALE; - } else { + if (processGender.equals("F")) { gender = Gender.FEMALE; + } else { + gender = Gender.OTHERS; } break; case "a/": From 9a9069e0db94e2d7d6a9f8b073cfa4af1aa2bb6e Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 23:47:59 +0800 Subject: [PATCH 147/271] Update person related code in manager --- src/main/java/seedu/dietbook/Manager.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index ad4c9be9f9..a5885bddfb 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -53,7 +53,8 @@ public class Manager { public Manager(FoodList foodlist, DataBase dataBase) { this.name = "John Doe"; - this.person = new Person(this.name, Gender.MALE, 0,0,0,0, ActivityLevel.LOW); + this.person = new Person(this.name, Gender.MALE, 1,1,1,1, + 1, ActivityLevel.LOW); this.foodList = foodlist; this.dataBase = dataBase; this.calculator = new Calculator(foodList.getFoods()); @@ -71,9 +72,9 @@ public Person getPerson() { return this.person; } - public void setPerson(String name, Gender gender, int age,int height,int orgWeight, + public void setPerson(String name, Gender gender, int age,int height,int orgWeight, int currWeight, int targWeight, ActivityLevel actLvl) { - this.person = new Person(name, gender, age, height, orgWeight, targWeight, actLvl); + this.person = new Person(name, gender, age, height, orgWeight, currWeight, targWeight, actLvl); } public Calculator getCalculator() { From a8a61538ce9d397cf7fd624fb62b3d7aba701597 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 23:48:32 +0800 Subject: [PATCH 148/271] Commented out a line that requires changes --- src/main/java/seedu/dietbook/parser/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 59283b0353..3c90078293 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -184,7 +184,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw break; } } - manager.setPerson(manager.getName(), gender, age, height, orgWeight, tarWeight, actLvl); + //manager.setPerson(manager.getName(), gender, age, height, orgWeight, tarWeight, actLvl); } /** From e3b0935c1f0fd86ab3139dd3448ff09fa387e747 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 23:49:05 +0800 Subject: [PATCH 149/271] Update printExitMessage method --- src/main/java/seedu/dietbook/Ui.java | 6 ++---- src/main/java/seedu/dietbook/command/ExitCommand.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 64e20166f0..1cde8236f3 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -83,11 +83,9 @@ public void printAskForUserInfoMessage(String name) { /** * Prints an exit message when DietBook is closed. * - * @param name The name of the user. */ - public void printExitMessage(String name) { - performAssertionsForStringInputs(name, "Name"); - print("Bye " + trimString(name) + "! Hope to see you again soon!"); + public void printExitMessage() { + print("Bye! Hope to see you again soon!"); } /** diff --git a/src/main/java/seedu/dietbook/command/ExitCommand.java b/src/main/java/seedu/dietbook/command/ExitCommand.java index 9f5b19d0dd..31b14601e7 100644 --- a/src/main/java/seedu/dietbook/command/ExitCommand.java +++ b/src/main/java/seedu/dietbook/command/ExitCommand.java @@ -7,7 +7,7 @@ public class ExitCommand extends Command { @Override public void execute(Manager manager, Ui ui) { - ui.printExitMessage(manager.getName()); + ui.printExitMessage(); DietBook.isExit = true; } } From 3ce5776def429e353a594dcc0ac9cce4f87a0cbc Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sat, 24 Oct 2020 23:50:11 +0800 Subject: [PATCH 150/271] Change the maximum age a person can have --- src/main/java/seedu/dietbook/checker/InputChecker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 53772478f4..8741b69586 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -13,7 +13,7 @@ public class InputChecker { /** * The value limits are based on current limits observed in th world. */ - public static final int AGE_CAP = 125; + public static final int AGE_CAP = 123; public static final int FOOD_CAP = 100000; public static final int HEIGHT_CAP = 273; public static final int WEIGHT_CAP = 443; From 988229693f433f55277d020d6d6b4ac10f1a2594 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 00:07:45 +0800 Subject: [PATCH 151/271] Add current weight parameter and did refactoring --- .../java/seedu/dietbook/person/Person.java | 184 +++++++++++++++--- 1 file changed, 154 insertions(+), 30 deletions(-) diff --git a/src/main/java/seedu/dietbook/person/Person.java b/src/main/java/seedu/dietbook/person/Person.java index eb85de0f98..fa695a9cf3 100644 --- a/src/main/java/seedu/dietbook/person/Person.java +++ b/src/main/java/seedu/dietbook/person/Person.java @@ -8,8 +8,10 @@ public class Person { /* The height of the person in cm */ private int height; - /* The original weight of the person in kg */ + /* The original weight of the person when he or she first started using DietBook in kg */ private int originalWeight; + /* The current weight of the person in kg */ + private int currentWeight; /* The target weight of the person in kg */ private int targetWeight; private int age; @@ -18,42 +20,60 @@ public class Person { private String name; /** - * Constructs a Person with the given name, gender, age, height, original weight, target - * weight and activity level. + * Constructs a Person with the given name, gender, age, height, activity level, original, + * current and target weight. * * @param name The name of the person. * @param gender The gender of the person. * @param age The age of the person. * @param height The height of the person. - * @param originalWeight The original weight of the person. + * @param originalWeight The original weight of the person when he or she first started using DietBook. + * @param currentWeight The current weight of the person. * @param targetWeight The target/desired weight that the person wants to achieve. * @param activityLevel The activity level of the person or in other words, the amount of exercise the * person engages in. */ - public Person(String name, Gender gender, int age, int height, int originalWeight, int targetWeight, - ActivityLevel activityLevel) { - assert name != null : "Name of person should not be null"; - assert name.trim().length() > 0 : "Name of person should not be an empty string"; - assert gender != null : "Gender of person should not be null"; - assert age > 0 : "Age of person should be greater than 0"; - assert age < 125 : "Age of person should be less than 125"; - assert height > 0 : "Height of person should be greater than 0"; - assert height < 273 : "Height of person should be less than 273"; - assert originalWeight > 0 : "Original weight of person should be greater than 0"; - assert originalWeight < 443 : "Original weight of person should be less than 443"; - assert targetWeight > 0 : "Target weight of person should be greater than 0"; - assert targetWeight < 443 : "Target weight of person should be less than 443"; - assert activityLevel != null : "Activity level of person should not be null"; + public Person(String name, Gender gender, int age, int height, int originalWeight, + int currentWeight, int targetWeight, ActivityLevel activityLevel) { + performAssertionsForPerson(name, gender, age, height, originalWeight, currentWeight, + targetWeight, activityLevel); this.name = name.trim(); this.gender = gender; this.age = age; this.height = height; this.originalWeight = originalWeight; + this.currentWeight = currentWeight; this.targetWeight = targetWeight; this.activityLevel = activityLevel; } + /** + * Sets all the attributes of a person to the new attributes given. + * + * @param newName The new/revised name of the person. + * @param newGender The new/revised gender of the person. + * @param newAge The new/revised age of the person. + * @param newHeight The new/revised height of the person. + * @param newOriginalWeight The new/revised original weight of the person when he or she first started + * using DietBook. + * @param newCurrentWeight The new/revised current weight of the person. + * @param newTargetWeight The new/revised target weight that the person wants to achieve. + * @param newActivityLevel The new/revised activity level of the person or in other words, the amount + * of exercise the person engages in. + */ + public void setAll(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, + int newCurrentWeight, int newTargetWeight, ActivityLevel newActivityLevel) { + setName(newName); + setGender(newGender); + setAge(newAge); + setHeight(newHeight); + setOriginalWeight(newOriginalWeight); + setCurrentWeight(newCurrentWeight); + setTargetWeight(newTargetWeight); + setActivityLevel(newActivityLevel); + } + /** * Returns the name of the person. * @@ -69,8 +89,7 @@ public String getName() { * @param newName The new/revised name of the person. */ public void setName(String newName) { - assert newName != null : "The revised name of person should not be null"; - assert newName.trim().length() > 0 : "The revised name of person should not be an empty string"; + performAssertionsForNameInput(newName); name = newName.trim(); } @@ -89,7 +108,7 @@ public Gender getGender() { * @param newGender The new/revised gender of the person. */ public void setGender(Gender newGender) { - assert newGender != null : "The revised gender of person should not be null"; + performAssertionsForGenderInput(newGender); gender = newGender; } @@ -108,8 +127,7 @@ public int getAge() { * @param newAge The new/revised age of the person. */ public void setAge(int newAge) { - assert newAge > 0 : "The revised age of person should be greater than 0"; - assert newAge < 125 : "The revised age of person should be lesser than 125"; + performAssertionsForAgeInput(newAge); age = newAge; } @@ -128,8 +146,7 @@ public int getHeight() { * @param newHeight The new/revised height of the person. */ public void setHeight(int newHeight) { - assert newHeight > 0 : "The revised height of person should be greater than 0"; - assert newHeight < 273 : "The revised height of person should be lesser than 273"; + performAssertionsForHeight(newHeight); height = newHeight; } @@ -148,11 +165,29 @@ public int getOriginalWeight() { * @param newOriginalWeight The new/revised original weight of the person. */ public void setOriginalWeight(int newOriginalWeight) { - assert newOriginalWeight > 0 : "The revised original weight of person should be greater than 0"; - assert newOriginalWeight < 443 : "The revised original weight of person should be lesser than 443"; + performAssertionsForWeight(newOriginalWeight,"Original weight"); originalWeight = newOriginalWeight; } + /** + * Returns the current weight of the person when he or she first started using DietBook. + * + * @return The current weight of the person when he or she first started using DietBook. + */ + public int getCurrentWeight() { + return currentWeight; + } + + /** + * Sets the current weight of the person to the new current weight given. + * + * @param newCurrentWeight The new/revised current weight of the person. + */ + public void setCurrentWeight(int newCurrentWeight) { + performAssertionsForWeight(newCurrentWeight, "Current weight"); + currentWeight = newCurrentWeight; + } + /** * Returns the target weight the person the person wants to achieve. * @@ -168,8 +203,7 @@ public int getTargetWeight() { * @param newTargetWeight The new/revised target weight of the person. */ public void setTargetWeight(int newTargetWeight) { - assert newTargetWeight > 0 : "The revised target weight of person should be greater than 0"; - assert newTargetWeight < 443 : "The revised target weight of person should be lesser than 443"; + performAssertionsForWeight(newTargetWeight, "Target weight"); targetWeight = newTargetWeight; } @@ -188,7 +222,7 @@ public ActivityLevel getActivityLevel() { * @param newActivityLevel The new/revised activity level of the person. */ public void setActivityLevel(ActivityLevel newActivityLevel) { - assert newActivityLevel != null : "The revised activity level of person should not be null"; + performAssertionsForActivityLevel(newActivityLevel); activityLevel = newActivityLevel; } @@ -205,8 +239,98 @@ public String toString() { + " Age: " + age + System.lineSeparator() + " Height: " + height + "cm" + System.lineSeparator() + " Original weight: " + originalWeight + "kg" + System.lineSeparator() + + " Current weight: " + currentWeight + "kg" + System.lineSeparator() + " Target weight: " + targetWeight + "kg" + System.lineSeparator() + " Activity level: " + activityLevel.getDescription(); return userInformation; } + + /** + * Performs assertions on all possible person inputs parameters. + * + * @param name The name of the person. + * @param gender The gender of the person. + * @param age The age of the person. + * @param height The height of the person. + * @param originalWeight The original weight of the person when he or she first started using DietBook. + * @param currentWeight The current weight of the person. + * @param targetWeight The target/desired weight that the person wants to achieve. + * @param activityLevel The activity level of the person or in other words, the amount of exercise the + * person engages in. + */ + private void performAssertionsForPerson(String name, Gender gender, int age, int height, + int originalWeight, int currentWeight, int targetWeight, + ActivityLevel activityLevel) { + performAssertionsForNameInput(name); + performAssertionsForGenderInput(gender); + performAssertionsForAgeInput(age); + performAssertionsForHeight(height); + performAssertionsForWeight(originalWeight, "Original weight"); + performAssertionsForWeight(currentWeight, "Current weight"); + performAssertionsForWeight(targetWeight, "Target weight"); + performAssertionsForActivityLevel(activityLevel); + } + + /** + * Performs assertion on the activity level input. + * + * @param activityLevel The activity level of the person or in other words, the amount of exercise the + * person engages in. + */ + private void performAssertionsForActivityLevel(ActivityLevel activityLevel) { + assert activityLevel != null : "Activity level of person should not be null"; + } + + /** + * Performs assertions the weight related inputs. + * + * @param weight Either the original, current or target weight of the person. + * @param weightType A string describing whether the weight given the original, current or target weight. + */ + private void performAssertionsForWeight(int weight, String weightType) { + assert weight > 0 : weightType + " of person should be greater than 0"; + // The heaviest person in the world has a weight of 442kg + assert weight < 443 : weightType + " of person should less than 443"; + } + + /** + * Performs assertions on the height input. + * + * @param height The height of the person. + */ + private void performAssertionsForHeight(int height) { + assert height > 0 : "Height of person should be greater than 0"; + // Tallest person in the world has a height of 272cm + assert height < 273 : "Height of person should be less than 273"; + } + + /** + * Performs assertion on the gender input. + * + * @param gender The gender of the person. + */ + private void performAssertionsForGenderInput(Gender gender) { + assert gender != null : "Gender of person should not be null"; + } + + /** + * Performs assertions on the name input. + * + * @param name The name of the person. + */ + private void performAssertionsForNameInput(String name) { + assert name != null : "The name of person should not be null"; + assert name.trim().length() > 0 : "The name of person should not be an empty string"; + } + + /** + * Performs assertions on the age input. + * + * @param age The age of the person. + */ + private void performAssertionsForAgeInput(int age) { + assert age > 0 : "The age of person should be greater than 0"; + // Oldest person to have ever lived, lived until 122 years and 164 days. + assert age < 123 : "The age of person should be lesser than 123"; + } } From 5fa10b93256717e23d85b758c6d9ddbcc99ebb7c Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 00:08:02 +0800 Subject: [PATCH 152/271] Update JUnit test for person class --- .../seedu/dietbook/person/PersonTest.java | 94 +++++++------------ 1 file changed, 34 insertions(+), 60 deletions(-) diff --git a/src/test/java/seedu/dietbook/person/PersonTest.java b/src/test/java/seedu/dietbook/person/PersonTest.java index ec5311d784..9e2a2c562c 100644 --- a/src/test/java/seedu/dietbook/person/PersonTest.java +++ b/src/test/java/seedu/dietbook/person/PersonTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class PersonTest { @@ -12,95 +13,68 @@ class PersonTest { @BeforeEach public void setUp() { person = new Person("Jack", Gender.MALE,21,165,75,65, - ActivityLevel.LOW); + 60, ActivityLevel.LOW); } @Test - void getName_person_returnsName() { - assertEquals("Jack", person.getName()); - } - - @Test - void setName_personWithNewName_returnNewName() { - person.setName("Jackie"); - assertEquals("Jackie", person.getName()); - } - - @Test - void gender_person_returnsGender() { - assertEquals(Gender.MALE, person.getGender()); - } - - @Test - void gender_personWithNewGender_returnsNewGender() { + void gender_setGenderToFemale_returnsCorrectGenderDescription() { person.setGender(Gender.FEMALE); - assertEquals(Gender.FEMALE, person.getGender()); + assertEquals("female", person.getGender().getDescription()); } @Test - void getAge_person_returnsAge() { - assertEquals(21, person.getAge()); + void gender_setGenderToMale_returnsCorrectGenderDescription() { + person.setGender(Gender.MALE); + assertEquals("male", person.getGender().getDescription()); } @Test - void setAge_personWithNewAge_returnsNewAge() { - person.setAge(24); - assertEquals(24, person.getAge()); + void gender_setGenderToOthers_returnsCorrectGenderDescription() { + person.setGender(Gender.OTHERS); + assertEquals("others", person.getGender().getDescription()); } - @Test - void getHeight_person_returnsHeight() { - assertEquals(165, person.getHeight()); + void gender_setGenderToNull_expectAssertionError() { + assertThrows(AssertionError.class, () -> person.setGender(null)); } @Test - void setHeight_personWithNewHeight_returnsNewHeight() { - person.setHeight(175); - assertEquals(175, person.getHeight()); + void setActivityLevel_setNewActivityLevelToNone_returnsCorrectActivityLevelDescription() { + person.setActivityLevel(ActivityLevel.NONE); + assertEquals("You hardly engage in any exercise or have a job that requires little to no " + + "physical activity.", person.getActivityLevel().getDescription()); } @Test - void getOriginalWeight_person_returnsOriginalWeight() { - assertEquals(75, person.getOriginalWeight()); + void setActivityLevel_setActivityLevelToLow_returnsCorrectActivityLevelDescription() { + person.setActivityLevel(ActivityLevel.LOW); + assertEquals("You engage in some form of light exercise or have a job that requires some " + + "physical activity.", person.getActivityLevel().getDescription()); } @Test - void setOriginalWeight_personWithNewOriginalWeight_returnsNewOriginalWeight() { - person.setOriginalWeight(70); - assertEquals(70, person.getOriginalWeight()); + void setActivityLevel_setActivityLevelToMedium_returnsCorrectActivityLevelDescription() { + person.setActivityLevel(ActivityLevel.MEDIUM); + assertEquals("You engage in moderate amount of exercise or have a job that requires moderate " + + "physical activity.", person.getActivityLevel().getDescription()); } @Test - void getTargetWeight_person_returnsTargetWeight() { - assertEquals(65, person.getTargetWeight()); - } - - @Test - void setTargetWeight_personWithNewTargetWeight_returnsNewTargetWeight() { - person.setTargetWeight(68); - assertEquals(68, person.getTargetWeight()); - } - - @Test - void getActivityLevel_person_returnsActivityLevel() { - assertEquals(ActivityLevel.LOW, person.getActivityLevel()); + void setActivityLevel_setActivityLevelToHigh_returnsCorrectActivityLevelDescription() { + person.setActivityLevel(ActivityLevel.HIGH); + assertEquals("You engage in vigorous exercise or have a physically demanding job.", + person.getActivityLevel().getDescription()); } @Test - void setActivityLevel_personWithNewActivityLevel_returnsNewActivityLevel() { - person.setActivityLevel(ActivityLevel.HIGH); - assertEquals(ActivityLevel.HIGH, person.getActivityLevel()); + void setActivityLevel_setActivityLevelToExtreme_returnsCorrectActivityLevelDescription() { + person.setActivityLevel(ActivityLevel.EXTREME); + assertEquals("You engage in extremely vigorous exercise or have an extremely physically " + + "demanding job.", person.getActivityLevel().getDescription()); } @Test - void toString_person_returnsStringRepresentationOfPersonInformation() { - assertEquals(" Name: Jack" + System.lineSeparator() - + " Gender: male" + System.lineSeparator() - + " Age: 21" + System.lineSeparator() - + " Height: 165cm" + System.lineSeparator() - + " Original weight: 75kg" + System.lineSeparator() - + " Target weight: 65kg" + System.lineSeparator() - + " Activity level: You engage in some form of light exercise or have a job that requires " - + "some physical activity.", person.toString()); + void setActivityLevel_setActivityLevelToNull_expectsAssertionErrors() { + assertThrows(AssertionError.class, () -> person.setActivityLevel(null)); } } From 0f6ea15c1be6c57167db663778e45a770ad0c850 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 00:08:15 +0800 Subject: [PATCH 153/271] Update I/O testing --- text-ui-test/EXPECTED.TXT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 01a5413702..d5c9bd655a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -13,5 +13,5 @@ Please input in the following format: Example: name Jack _____________________________________________________________________________________________________________________________________ _____________________________________________________________________________________________________________________________________ -Bye John Doe! Hope to see you again soon! +Bye! Hope to see you again soon! _____________________________________________________________________________________________________________________________________ From fe2018b4c87bb4b3113d99f235d7ced17397d926 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 00:08:23 +0800 Subject: [PATCH 154/271] Enable assertions --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8eee256504..a6c5d0226a 100644 --- a/build.gradle +++ b/build.gradle @@ -45,5 +45,5 @@ checkstyle { run{ standardInput = System.in - enableAssertions = false + enableAssertions = true } From 44c3209c07ccc03369aed3a665b57d742f466507 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 00:13:28 +0800 Subject: [PATCH 155/271] Fix checktyle error --- src/test/java/seedu/dietbook/person/PersonTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/seedu/dietbook/person/PersonTest.java b/src/test/java/seedu/dietbook/person/PersonTest.java index 9e2a2c562c..83207f1f82 100644 --- a/src/test/java/seedu/dietbook/person/PersonTest.java +++ b/src/test/java/seedu/dietbook/person/PersonTest.java @@ -33,6 +33,7 @@ void gender_setGenderToOthers_returnsCorrectGenderDescription() { person.setGender(Gender.OTHERS); assertEquals("others", person.getGender().getDescription()); } + @Test void gender_setGenderToNull_expectAssertionError() { assertThrows(AssertionError.class, () -> person.setGender(null)); From 5830442f3216720d9976fa776734a7c193052664 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:03:43 +0800 Subject: [PATCH 156/271] Change to less specific age, weight and height cap --- src/main/java/seedu/dietbook/checker/InputChecker.java | 6 +++--- src/main/java/seedu/dietbook/person/Person.java | 9 +++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 8741b69586..5eba1d1019 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -13,10 +13,10 @@ public class InputChecker { /** * The value limits are based on current limits observed in th world. */ - public static final int AGE_CAP = 123; + public static final int AGE_CAP = 150; public static final int FOOD_CAP = 100000; - public static final int HEIGHT_CAP = 273; - public static final int WEIGHT_CAP = 443; + public static final int HEIGHT_CAP = 300; + public static final int WEIGHT_CAP = 500; public static final String[] PARAM_ACTIVITY = {"1","2","3","4","5"}; public static final String[] PARAM_ADD = {"n/","x/","k/"}; public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; diff --git a/src/main/java/seedu/dietbook/person/Person.java b/src/main/java/seedu/dietbook/person/Person.java index fa695a9cf3..6fd3f52ebb 100644 --- a/src/main/java/seedu/dietbook/person/Person.java +++ b/src/main/java/seedu/dietbook/person/Person.java @@ -289,8 +289,7 @@ private void performAssertionsForActivityLevel(ActivityLevel activityLevel) { */ private void performAssertionsForWeight(int weight, String weightType) { assert weight > 0 : weightType + " of person should be greater than 0"; - // The heaviest person in the world has a weight of 442kg - assert weight < 443 : weightType + " of person should less than 443"; + assert weight < 500 : weightType + " of person should less than 500"; } /** @@ -300,8 +299,7 @@ private void performAssertionsForWeight(int weight, String weightType) { */ private void performAssertionsForHeight(int height) { assert height > 0 : "Height of person should be greater than 0"; - // Tallest person in the world has a height of 272cm - assert height < 273 : "Height of person should be less than 273"; + assert height < 300 : "Height of person should be less than 300"; } /** @@ -330,7 +328,6 @@ private void performAssertionsForNameInput(String name) { */ private void performAssertionsForAgeInput(int age) { assert age > 0 : "The age of person should be greater than 0"; - // Oldest person to have ever lived, lived until 122 years and 164 days. - assert age < 123 : "The age of person should be lesser than 123"; + assert age < 150 : "The age of person should be lesser than 150"; } } From ab7d99aaa23d16d60bdc0c58e72fd453d3c3c536 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:05:02 +0800 Subject: [PATCH 157/271] Refactor out logo --- src/main/java/seedu/dietbook/Ui.java | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 1cde8236f3..7e6a50e48a 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -30,12 +30,7 @@ public Ui() { * Prints the welcome message from DietBook when it is fist booted up. */ public void printWelcomeMessage() { - String logo = " _______ __ ______ ________ _______ ______ ______ __ __" + LINE_SEPARATOR - + "| __ \\| | ___|__ __| __ \\ / __ \\ / __ \\| | / /" + LINE_SEPARATOR - + "| | | | | |___ | | | |__| | | | | | | | |/ /" + LINE_SEPARATOR - + "| | | | | ___| | | | __ <| | | | | | | /" + LINE_SEPARATOR - + "| |__| | | |___ | | | |__| | |__| | | | | |\\ \\" + LINE_SEPARATOR - + "|_______/|__|______| |__| |_______/ \\______/ \\______/|__| \\__\\" + LINE_SEPARATOR; + String logo = getLogo(); print(logo + LINE_SEPARATOR + "Hello! Welcome to DietBook!" + LINE_SEPARATOR + "I am Diet, your guide to using DietBook. What is your name?" + LINE_SEPARATOR @@ -484,6 +479,21 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei // Helper methods for system related commands or messages + /** + * Returns the string representation of the logo. + * + * @return The string representation of the logo. + */ + private String getLogo() { + String logo = " _______ __ ______ ________ _______ ______ ______ __ __" + LINE_SEPARATOR + + "| __ \\| | ___|__ __| __ \\ / __ \\ / __ \\| | / /" + LINE_SEPARATOR + + "| | | | | |___ | | | |__| | | | | | | | |/ /" + LINE_SEPARATOR + + "| | | | | ___| | | | __ <| | | | | | | /" + LINE_SEPARATOR + + "| |__| | | |___ | | | |__| | |__| | | | | |\\ \\" + LINE_SEPARATOR + + "|_______/|__|______| |__| |_______/ \\______/ \\______/|__| \\__\\" + LINE_SEPARATOR; + return logo; + } + /** * Returns a string representation of a list of system related commands that users can input. * From 91a917747fad0aeba53b6d040edf61044e9f3631 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:05:41 +0800 Subject: [PATCH 158/271] Refactor out getStartMessage method --- src/main/java/seedu/dietbook/Ui.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 7e6a50e48a..7a3a9a2896 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -494,6 +494,17 @@ private String getLogo() { return logo; } + /** + * Returns a string stating that DietBook is ready for use. + * + * @return A string stating that DietBook is ready for use. + */ + private String getStartMessage() { + return "and you may start by entering any valid commands. " + + LINE_SEPARATOR + + "If you require a list of valid commands, you can enter: help"; + } + /** * Returns a string representation of a list of system related commands that users can input. * From 79b2f55b54f31ce41edcf15daa7bf9e712e05886 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:07:15 +0800 Subject: [PATCH 159/271] Add printWelcomeBackMessage method --- src/main/java/seedu/dietbook/Ui.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 7a3a9a2896..5401047330 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -98,9 +98,20 @@ public void printErrorMessage(String errorMessage) { * Prints a message that notifies the user that DietBook has been initialised. */ public void printInitialisationCompleteMessage() { - print("Thank you! DietBook has been initialised and you may start by entering any valid commands. " - + LINE_SEPARATOR - + "If you require a list of valid commands, you can enter: help"); + print("Thank you! DietBook has been initialised " + getStartMessage()); + } + + + /** + * Prints the welcome back message when user reboots up DietBook after the first initialisation. + * + * @param name The name of the user. + */ + public void printWelcomeBackMessage(String name) { + performAssertionsForStringInputs(name, "Name"); + + print(getLogo() + LINE_SEPARATOR + "Welcome back to DietBook " + trimString(name) + "!" + LINE_SEPARATOR + + "All your previous data has been successfully loaded " + getStartMessage()); } /** From 00fdbc092ed0d443ac18a40f07677c363594bd3d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:08:12 +0800 Subject: [PATCH 160/271] Update printEditedPersonInfo method --- src/main/java/seedu/dietbook/Ui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 5401047330..8af66267a2 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -187,7 +187,7 @@ public void printEditedPersonInfo(String personInfo) { performAssertionsForStringInputs(personInfo, "Updated person information"); - print("Here is your updated information:" + LINE_SEPARATOR + print("Got it! I've updated your personal information:" + LINE_SEPARATOR + personInfo); } From 28da147313e1868a3e22811ad4f206f95a47c4d4 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:10:05 +0800 Subject: [PATCH 161/271] Shorten JavaDocs for several methods --- src/main/java/seedu/dietbook/Ui.java | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 8af66267a2..61a0750a91 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -299,9 +299,8 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods) { } /** - * Prints the total amount of carbohydrates consumed by the user within a given time period and a list of - * the foods recorded into the food list during the same time period which had their nutritional - * information recalculated by DietBook if any. + * Prints the total amount of carbohydrates consumed by the user and a list of the foods which had + * their nutritional information recalculated by DietBook if any, given a certain time period. * Some food items only have partial nutritional information as users did not provide all the * information when the food items were added. Hence, DietBook does an internal calculation for the * the missing information and these calculated values are used when tabulating total carbohydrate @@ -338,9 +337,8 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo } /** - * Prints the total amount of calories consumed by the user within a given time period and a list of - * the foods recorded into the food list during the same time period which had their nutritional - * information recalculated by DietBook if any. + * Prints the total amount of calories consumed by the user and a list of the foods which had their + * nutritional information recalculated by DietBook if any, given a certain time period. * Some food items only have partial nutritional information as users did not provide all the * information when the food items were added. Hence, DietBook does an internal calculation for the * the missing information and these calculated values are used when tabulating total calorie @@ -377,9 +375,8 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo } /** - * Prints the total amount of proteins consumed by the user within a given time period and a list of - * the foods recorded into the food list during the same time period which had their nutritional - * information recalculated by DietBook if any. + * Prints the total amount of proteins consumed by the user and a list of the foods which had their + * nutritional information recalculated by DietBook if any, given a certain time period. * Some food items only have partial nutritional information as users did not provide all the * information when the food items were added. Hence, DietBook does an internal calculation for the * the missing information and these calculated values are used when tabulating total protein @@ -416,9 +413,8 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods) { } /** - * Prints the total amount of fats consumed by the user within a given time period and a list of - * the foods recorded into the food list during the same time period which had their nutritional - * information recalculated by DietBook if any. + * Prints the total amount of fats consumed by the user and a list of the foods which had their + * nutritional information recalculated by DietBook if any, given a certain time period. * Some food items only have partial nutritional information as users did not provide all the * information when the food items were added. Hence, DietBook does an internal calculation for the * the missing information and these calculated values are used when tabulating total fat @@ -459,12 +455,12 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei } /** - * Prints the total amount of total amount of calories, carbohydrates, fats and proteins consumed by - * the user within a given time period and a list of the foods recorded into the food list during the - * same time period which had their nutritional information recalculated by DietBook if any. + * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and a + * list of the foods which had their nutritional information recalculated by DietBook if any, given a + * certain time period. * Some food items only have partial nutritional information as users did not provide all the * information when the food items were added. Hence, DietBook does an internal calculation for the - * the missing information and these calculated values are used when tabulating the individual intake + * the missing information and these calculated values are used when tabulating the individual intakes * within a given time period. * * @param calorieIntake The total amount of calories of food in the food list recorded during the From 08d0349a0a6aae94a5a8dfd1b0ff4fc8b0dcd8bd Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:11:27 +0800 Subject: [PATCH 162/271] Remove bug caused by wrong input order --- src/main/java/seedu/dietbook/Ui.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 61a0750a91..662dcecfc9 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -450,7 +450,7 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, */ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int proteinIntake, int fatIntake, String recalculatedFoods) { - print(stringAllIntakeAndFoodsWithoutTime(carbIntake, calorieIntake,proteinIntake, + print(stringAllIntakeAndFoodsWithoutTime(calorieIntake, carbIntake, proteinIntake, fatIntake, recalculatedFoods)); } @@ -479,8 +479,8 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int proteinIntake, int fatIntake, String recalculatedFoods, LocalDateTime start, LocalDateTime end) { - String allIntakeAndFoodsWithoutTime = stringAllIntakeAndFoodsWithoutTime(carbIntake, calorieIntake, - proteinIntake,fatIntake, recalculatedFoods); + String allIntakeAndFoodsWithoutTime = stringAllIntakeAndFoodsWithoutTime(calorieIntake, + carbIntake, proteinIntake, fatIntake, recalculatedFoods); print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); } @@ -691,7 +691,7 @@ private String stringIntakeAndFoodsWithTime(String intakeAndFoodsWithoutTime, * @return A string representation of the total amount of all nutrients consumed by the user and * the list of food items which had their nutritional information recalculated by DietBook if any. */ - private String stringAllIntakeAndFoodsWithoutTime(int carbIntake, int calorieIntake, int proteinIntake, + private String stringAllIntakeAndFoodsWithoutTime(int calorieIntake, int carbIntake, int proteinIntake, int fatIntake, String recalculatedFoods) { performAssertionsForNutritionalIntake(carbIntake, "carbohydrate"); performAssertionsForNutritionalIntake(calorieIntake, "calorie"); @@ -707,8 +707,8 @@ private String stringAllIntakeAndFoodsWithoutTime(int carbIntake, int calorieInt String stringFatIntake = stringNutritionalIntake(fatIntake,"fat", "g"); String message = recalculatedFoodsMessage(recalculatedFoods); - return stringCarbIntake + LINE_SEPARATOR - + stringCalorieIntake + LINE_SEPARATOR + return stringCalorieIntake + LINE_SEPARATOR + + stringCarbIntake + LINE_SEPARATOR + stringProteinIntake + LINE_SEPARATOR + stringFatIntake + LINE_SEPARATOR + message; From 76705fa46735ea7996699b1b434e89fa58deeb1d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:12:39 +0800 Subject: [PATCH 163/271] Add methods to calculate nutrient given start date --- src/main/java/seedu/dietbook/Ui.java | 118 ++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 662dcecfc9..d1865e5922 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -320,6 +320,26 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods, print(stringIntakeAndFoodsWithTime(carbIntakeAndFoodsWithoutTime, start, end)); } + /** + * Prints the total amount of carbohydrates consumed by the user and a list of the foods which had + * their nutritional information recalculated by DietBook if any, given a start date. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total carbohydrate + * intake given a start date. + * + * @param carbIntake The total amount of carbohydrates of food in the food list recorded from the + * start date till now. + * @param recalculatedFoods The list of food items recorded from the start date till now which had + * their nutritional information recalculated by DietBook. + * @param start Starting date time to calculate from. + */ + public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods, + LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printCarbIntakeAndFoods(carbIntake, recalculatedFoods, start, end); + } + /** * Prints the total amount of calories consumed by the user and the list of food items which had * their nutritional information recalculated by DietBook if any. @@ -358,6 +378,26 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo print(stringIntakeAndFoodsWithTime(calorieIntakeAndFoodsWithoutTime, start, end)); } + /** + * Prints the total amount of calories consumed by the user and a list of the foods which had their + * nutritional information recalculated by DietBook if any, given a start date. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total calorie intake, + * given a start date. + * + * @param calorieIntake The total amount of calories of food in the food list recorded from the + * start date till now. + * @param recalculatedFoods The list of food items recorded from the start date till now which had + * their nutritional information recalculated by DietBook. + * @param start Starting date time to calculate from. + */ + public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoods, + LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printCalorieIntakeAndFoods(calorieIntake, recalculatedFoods, start, end); + } + /** * Prints the total amount of proteins consumed by the user and the list of food items which had * their nutritional information recalculated by DietBook if any. @@ -396,6 +436,26 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo print(stringIntakeAndFoodsWithTime(proteinIntakeAndFoodsWithoutTime, start, end)); } + /** + * Prints the total amount of proteins consumed by the user and a list of the foods which had their + * nutritional information recalculated by DietBook if any, given a start date. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total protein intake, + * given a start date. + * + * @param proteinIntake The total amount of proteins of food in the food list recorded from the + * start date till now. + * @param recalculatedFoods The list of food items recorded from the start date till now which had + * their nutritional information recalculated by DietBook. + * @param start Starting date time to calculate from. + */ + public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoods, + LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printProteinIntakeAndFoods(proteinIntake, recalculatedFoods, start, end); + } + /** * Prints the total amount of fats consumed by the user and the list of food items which had * their nutritional information recalculated by DietBook if any. @@ -434,6 +494,26 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, print(stringIntakeAndFoodsWithTime(fatIntakeAndFoodsWithoutTime, start, end)); } + /** + * Prints the total amount of fats consumed by the user and a list of the foods which had their + * nutritional information recalculated by DietBook if any, given a start date. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating total fat intake, + * given a start date. + * + * @param fatIntake The total amount of fats of food in the food list recorded from the start date till + * now. + * @param recalculatedFoods The list of food items recorded from the start date till now which had + * their nutritional information recalculated by DietBook. + * @param start Starting date time to calculate from. + */ + public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, + LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printFatIntakeAndFoods(fatIntake, recalculatedFoods, start, end); + } + /** * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and the * list of food items which had their nutritional information recalculated by DietBook if any. @@ -484,6 +564,35 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); } + /** + * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and a + * list of the foods which had their nutritional information recalculated by DietBook if any, given a + * start date. + * Some food items only have partial nutritional information as users did not provide all the + * information when the food items were added. Hence, DietBook does an internal calculation for the + * the missing information and these calculated values are used when tabulating the individual intakes, + * given a start date. + * + * @param calorieIntake The total amount of calories of food in the food list recorded from the start + * date till now. + * @param carbIntake The total amount of carbohydrates of food in the food list recorded from the start + * date till now. + * @param proteinIntake The total amount of proteins of food in the food list recorded from the start + * date till now. + * @param fatIntake The total amount of fats of food in the food list recorded from the start date till + * now. + * @param recalculatedFoods The list of food items recorded from the start date till now which had + * their nutritional information recalculated by DietBook. + * @param start Starting date time to calculate from. + */ + public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake, String recalculatedFoods, + LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printAllIntakeAndFoods(calorieIntake, carbIntake, proteinIntake, fatIntake, recalculatedFoods, start, + end); + } + // Helper methods for system related commands or messages /** @@ -794,14 +903,15 @@ private void performAssertionsForStringInputs(String string, String stringDescri * @param end Ending date time of the time period given. */ private void performAssertionsForTimePeriod(LocalDateTime start, LocalDateTime end) { + LocalDateTime now = LocalDateTime.now(); assert start != null : "Starting date time of the time period given should not be null"; assert end != null : "Ending date time of the time period given should not be null"; assert !start.isAfter(end) : "Starting date time should not be later than ending date time " + "of the time period"; - assert start.isBefore(LocalDateTime.now()) : "Starting date time of the time period given should " - + "not be in the future"; - assert end.isBefore(LocalDateTime.now()) : "Ending date time of the time period given should not be" - + " in the future"; + assert !start.isAfter(now) : "Starting date time of the time period given should " + + "not be in the future" + start + LocalDateTime.now(); + assert !end.isAfter(now) : "Ending date time of the time period given should not be" + + " in the future" + end + LocalDateTime.now(); } /** From 6d5178b8b60df0491556a414b798fedbf5f31a02 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Sun, 25 Oct 2020 14:29:18 +0800 Subject: [PATCH 164/271] Fix checkstyle error --- src/main/java/seedu/dietbook/Ui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index d1865e5922..cff308b02e 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -903,11 +903,11 @@ private void performAssertionsForStringInputs(String string, String stringDescri * @param end Ending date time of the time period given. */ private void performAssertionsForTimePeriod(LocalDateTime start, LocalDateTime end) { - LocalDateTime now = LocalDateTime.now(); assert start != null : "Starting date time of the time period given should not be null"; assert end != null : "Ending date time of the time period given should not be null"; assert !start.isAfter(end) : "Starting date time should not be later than ending date time " + "of the time period"; + LocalDateTime now = LocalDateTime.now(); assert !start.isAfter(now) : "Starting date time of the time period given should " + "not be in the future" + start + LocalDateTime.now(); assert !end.isAfter(now) : "Ending date time of the time period given should not be" From 4cf65bfc5c47a6fa709530a69b185bb3bd68d146 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Mon, 26 Oct 2020 00:05:03 +0800 Subject: [PATCH 165/271] Recommendation of daily calorie intake calculation is added --- .../seedu/dietbook/calculator/Calculator.java | 62 +++++++++++++++++++ .../dietbook/calculator/CalculatorTest.java | 12 ++++ 2 files changed, 74 insertions(+) diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index bcd6208c32..246983b3d6 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -1,6 +1,8 @@ package seedu.dietbook.calculator; import seedu.dietbook.food.Food; +import seedu.dietbook.person.Gender; +import seedu.dietbook.person.Person; import java.util.ArrayList; @@ -64,4 +66,64 @@ public int calculateProtein() { public int calculateFat() { return totalFat; } + + /** + * Returns an int type variable containing the value of recommended daily calorie intake. + * It is calculated based on the gender, activity level, age, height, original weight, + * and targeted weight. + * + * @param person person whose recommended daily calorie intake are to return. + * @return the value of recommended daily calorie intake. + */ + public int calculateRecomendation(Person person) { + double requirement = 0; + int recomendation; + double activityScore; + switch (person.getActivityLevel()) { + case NONE: + activityScore = 1; + break; + case LOW: + if (person.getGender() == Gender.MALE) { + activityScore = 1.11; + } else { + activityScore = 1.12; + } + break; + case MEDIUM: + if (person.getGender() == Gender.MALE) { + activityScore = 1.26; + } else { + activityScore = 1.27; + } + break; + case HIGH: + default: + if (person.getGender() == Gender.MALE) { + activityScore = 1.48; + } else { + activityScore = 1.45; + } + break; + } + + switch (person.getGender()) { + case MALE: + requirement = 662 - 9.53 * person.getAge() + 15.91 * activityScore * person.getOriginalWeight() + + 539.6 * person.getHeight() / 100; + break; + case FEMALE: + requirement = 354 - 6.91 * person.getAge() + 9.36 * activityScore * person.getOriginalWeight() + + 726 * person.getHeight() / 100; + break; + default: + } + + if (person.getOriginalWeight() > person.getTargetWeight()) { + recomendation = (int) requirement - 300; + } else { + recomendation = (int) requirement + 100; + } + return recomendation; + } } diff --git a/src/test/java/seedu/dietbook/calculator/CalculatorTest.java b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java index 576c6e3995..ea25a7aa09 100644 --- a/src/test/java/seedu/dietbook/calculator/CalculatorTest.java +++ b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java @@ -2,6 +2,9 @@ import org.junit.jupiter.api.Test; import seedu.dietbook.food.Food; +import seedu.dietbook.person.ActivityLevel; +import seedu.dietbook.person.Gender; +import seedu.dietbook.person.Person; import java.util.ArrayList; @@ -50,4 +53,13 @@ void calculateFat_foodListOfThreeItems_sumOfFat() { Calculator calculator = new Calculator(foodList); assertEquals(0, calculator.calculateFat()); } + + @Test + void calculateRecomendedCalorieIntake_aPerson_recomendationOfCalorieIntake() { + Person Harry = new Person("Harry", Gender.MALE, 19, 182, 66, 75, ActivityLevel.LOW); + Person Erica = new Person("Erica", Gender.FEMALE, 20, 168, 52, 45, ActivityLevel.MEDIUM); + Calculator calculator = new Calculator(new ArrayList()); + assertEquals(2728, calculator.calculateRecomendation(Harry)); + assertEquals(1752, calculator.calculateRecomendation(Erica)); + } } From 249af2a545272121a342fc76d5cef4271e2a1ed2 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 26 Oct 2020 11:15:09 +0800 Subject: [PATCH 166/271] Reorder the outputs --- src/main/java/seedu/dietbook/Ui.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index cff308b02e..270286cef7 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -119,12 +119,12 @@ public void printWelcomeBackMessage(String name) { */ public void printHelpCommandMessage() { print("Listed below are the valid commands for DietBook:" + LINE_SEPARATOR + LINE_SEPARATOR + + "For user information related commands" + LINE_SEPARATOR + + getUserRelatedCommands() + LINE_SEPARATOR + "For database related commands" + LINE_SEPARATOR + getDatabaseRelatedCommands() + LINE_SEPARATOR + "For food list related commands" + LINE_SEPARATOR + getFoodListRelatedCommands() + LINE_SEPARATOR - + "For user information related commands" + LINE_SEPARATOR - + getUserRelatedCommands() + LINE_SEPARATOR + "For nutritional intake and recommendation related commands" + LINE_SEPARATOR + getCalculatorRelatedCommands() + LINE_SEPARATOR + "For other system related commands" + LINE_SEPARATOR From 8dc7572c4b8e4b24b80dd931a29aaf6e4e2d83e7 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 26 Oct 2020 11:19:14 +0800 Subject: [PATCH 167/271] Change word --- src/main/java/seedu/dietbook/Ui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 270286cef7..de395c1d5f 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -673,7 +673,7 @@ private String getCalculatorRelatedCommands() { * @return A string representation of a list of user information related commands that users can input. */ private String getUserRelatedCommands() { - return " To show user information: userinfo" + LINE_SEPARATOR + return " To view user information: userinfo" + LINE_SEPARATOR + " To edit user information: editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] " + "[o/ORIGINAL_WEIGHT] [c/CURRENT_WEIGHT] [t/TARGET_WEIGHT] [l/ACTIVITY_LEVEL]" + LINE_SEPARATOR; From 123f982eaa9283dd93e15b6a48c102ce17582111 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 26 Oct 2020 12:38:40 +0800 Subject: [PATCH 168/271] Update parser to add current weight parameter --- src/main/java/seedu/dietbook/Manager.java | 2 +- src/main/java/seedu/dietbook/parser/Parser.java | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index a5885bddfb..dc35b3075a 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -74,7 +74,7 @@ public Person getPerson() { public void setPerson(String name, Gender gender, int age,int height,int orgWeight, int currWeight, int targWeight, ActivityLevel actLvl) { - this.person = new Person(name, gender, age, height, orgWeight, currWeight, targWeight, actLvl); + this.person.setAll(name, gender, age, height, orgWeight, currWeight, targWeight, actLvl); } public Calculator getCalculator() { diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 3c90078293..777e4fffff 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -19,7 +19,7 @@ public class Parser { public static final String COMMAND_INFO = "info"; public static final String COMMAND_ADD = "add"; public static final String COMMAND_CALCULATE = "calculate"; - public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; + public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/","c/"}; @@ -131,6 +131,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw int age = 0; int height = 0; int orgWeight = 0; + int currWeight = 0; int tarWeight = 0; String trimmedParam; String[] processedParam; @@ -163,6 +164,10 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw orgWeight = Integer.parseInt(trimmedParam); InputChecker.checkWeightLimit(orgWeight); break; + case "c/": + currWeight = Integer.parseInt(trimmedParam); + InputChecker.checkWeightLimit(currWeight); + break; case "t/": tarWeight = Integer.parseInt(trimmedParam); InputChecker.checkWeightLimit(tarWeight); @@ -184,7 +189,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw break; } } - //manager.setPerson(manager.getName(), gender, age, height, orgWeight, tarWeight, actLvl); + manager.setPerson(manager.getName(), gender, age, height, orgWeight, currWeight, tarWeight, actLvl); } /** From f53491979ed1fa0c458a760e4f776c6f3a5aa3c8 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 26 Oct 2020 12:39:18 +0800 Subject: [PATCH 169/271] Update parser to support others gender --- src/main/java/seedu/dietbook/parser/Parser.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 777e4fffff..695774dbc2 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -148,8 +148,10 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw InputChecker.checkGender(processGender); if (processGender.equals("M")) { gender = Gender.MALE; - } else { + } else if (processGender.equals("F")) { gender = Gender.FEMALE; + } else { + gender = Gender.OTHERS; } break; case "a/": From 561990431d33320abbd99d4a260e81c1cb1c0c7e Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 26 Oct 2020 12:43:38 +0800 Subject: [PATCH 170/271] Fix bug for checking of empty inputs --- src/main/java/seedu/dietbook/checker/InputChecker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 5eba1d1019..91986e54e9 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -45,7 +45,7 @@ public static void checkEmpty(String userInput, String command) throws DietExcep */ public static void checkEmptyOption(String[] input) throws DietException { try { - if (input[1].trim().charAt(1) == '/') { + if (input[1].charAt(0) == ' ') { throw new DietException("Error! Option specified with empty field!"); } } catch (IndexOutOfBoundsException e) { From bafdc7d148e7e254eee580b880fa5f12f50de2a5 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 26 Oct 2020 13:12:27 +0800 Subject: [PATCH 171/271] Revert "Fix bug for checking of empty inputs" This reverts commit 561990431d33320abbd99d4a260e81c1cb1c0c7e. --- src/main/java/seedu/dietbook/checker/InputChecker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 91986e54e9..5eba1d1019 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -45,7 +45,7 @@ public static void checkEmpty(String userInput, String command) throws DietExcep */ public static void checkEmptyOption(String[] input) throws DietException { try { - if (input[1].charAt(0) == ' ') { + if (input[1].trim().charAt(1) == '/') { throw new DietException("Error! Option specified with empty field!"); } } catch (IndexOutOfBoundsException e) { From 24df057fa69f499b2decec0e0822703d2aaed983 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Mon, 26 Oct 2020 18:18:08 +0800 Subject: [PATCH 172/271] Update user guide --- docs/UserGuide.md | 143 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 133 insertions(+), 10 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..0189022c3d 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,21 +1,144 @@ -# User Guide +# DietBook User Guide ## Introduction -{Give a product intro} - +DietBook is a desktop application targeting NUS students optimized for use via a **Command Line Interface**. Not only can DietBook track and show the user's food and nutritional intake, it also provides users with a list of commonly eaten food items around and outside NUS. + ## 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). +1. Download the latest version of `dietbook.jar` from [here](https://github.com/AY2021S1-CS2113-T14-4/tp/releases). +1. Copy the file to the folder you want to use as the home folder for your DietBook. +1. Either double-click the jar file to start the application or navigate to the folder containing the jar file on command prompt and run the command `java -jar dietbook.jar`. ## Features -{Give detailed description of each feature} - -### Adding a todo: `todo` +Notes about the command format: + +* Words in `UPPER_CASE` are parameters to be supplied by the user.
+e.g. For `delete INDEX`, `delete 1`would be a valid command. + +* Parameters in square brackets are optional. However, if all parameters are optional, at least one parameter needs to be given. In such cases, any one of the parameters would be valid.
+e.g. For `add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT]`, `add x/1 n/Toast k/120`, `add x/1 n/Toast k/120 c/18`, `add x/1 n/Toast k/120 c/18 p/3`, `add x/1 n/Toast k/120 + c/18 p/3 f/4` are all valid commands. + +* For commands with multiple parameters, the parameters can be in any order.
+e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` and `add x/1 n/mee` are both valid. + +* Command words and parameter indicators are case-sensitive.
+e.g. `help` is a valid command but `Help` is not.
+e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` is valid but `add N/mee x/1` is not. + +* Spaces to separate command words, parameters, command word and parameters are important.
+e.g. For `calculate all`, `calculate all` is valid but `calculateall` is not.
+e.g. For `delete INDEX`, `delete 1` is valid if there is a food item with index 1 but`delete1` is not.
+e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` is valid but `add n/meex/1` is not.
+ +### Features related to user information + +#### Viewing user information: `userinfo` + +Shows the user information stored in DietBook. + +Format: `userinfo` + +Output example: +``` +Here is your information: + Name: Jack + Gender: male + Age: 21 + Height: 175cm + Original weight: 85kg + Current weight: 85kg + Target weight: 75kg + Activity level: You engage in some form of light exercise or have a job that requires some physical activity. +``` + +#### Editing user information: `editinfo` + +Edits the user information stored in DietBook. + +Format: `editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/CURRENT_WEIGHT] [t/TARGET_WEIGHT] [l/ACTIVITY_LEVEL]` + +* Although all parameters are listed as optional, **at least one of the optional fields needs to be provided**. In this case, any one of the parameters would work. +* If more than one parameter is given, they can be in any order. +* Existing values will be updated to the input values. +* The name must not be empty. +* The gender must be either **`M` for male, `F` for female or `O` for others**. +* The age must be a positive integer **between 0 and 150**. +* The height must be a positive integer **between 0 and 300**. +* The original, current and target weight must be a positive integer **between 0 and 500**. +* The activity level must be a positive integer **from 1 to 5, inclusive**. + * 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. + * 2 = You engage in some form of light exercise or have a job that requires some physical activity. + * 3 = You engage in moderate amount of exercise or have a job that requires moderate physical activity. + * 4 = You engage in vigorous exercise or have a physically demanding job. + * 5 = You engage in extremely vigorous exercise or have an extremely physically demanding job. + +Input examples: + +* `editinfo n/John` edits the updated the name stored in DietBook. +* Both `editinfo c/75 l/4` and `editinfo l/4 c/75` edits the current weight and activity level of the + user to be `75` and `You engage in vigorous exercise or have a physically demanding job.` respectively. + +Output example for input example 2: +``` +Got it! I've updated your personal information: + Name: Jack + Gender: male + Age: 21 + Height: 175cm + Original weight: 85kg + Current weight: 75kg + Target weight: 75kg + Activity level: You engage in vigorous exercise or have a physically demanding job. +``` + +### Features related to the food database + +To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE +To view all food in the database: data + +### Features related to the food list + +To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT] +To view all food in DietBook: list +To view all food in DietBook recorded within a time period: list yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm +To view all food in DietBook recorded from a certain date until now: list yyyy-mm-ddTHH:mm +To delete a food from DietBook: delete INDEX +To delete all food items from the DietBook: clear + +### Features related to nutritional intake and recommendation + +To get recommended calorie intake: recommend + + To calculate carbohydrate intake: calculate carbohydrate + To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm + + To calculate calorie intake: calculate calorie + To calculate calorie intake within a time period: calculate calorie yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate calorie intake from a certain date until now: calculate calorie yyyy-mm-ddTHH:mm + + To calculate protein intake: calculate protein + To calculate protein intake within a time period: calculate protein yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate protein intake from a certain date until now: calculate protein yyyy-mm-ddTHH:mm + + To calculate fat intake: calculate fat + To calculate fat intake within a time period: calculate fat yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate fat intake from a certain date until now: calculate fat yyyy-mm-ddTHH:mm + + To calculate all nutritional intake: calculate all + To calculate all nutritional intake within a time period: calculate all yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate all nutritional intake from a certain date until now: calculate all yyyy-mm-ddTHH:mm + +### Other features + + To view a list of valid commands: help + To exit DietBook: exit + Saving + +#### Adding a todo: `todo` Adds a new item to the list of todo items. Format: `todo n/TODO_NAME d/DEADLINE` From 3531f413786aac4d198a36183261dc2271340b33 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 26 Oct 2020 18:22:26 +0800 Subject: [PATCH 173/271] add date filtering - FoodList returns List for public methods. Tweak to calculator to accept List instead of ArrayList made. - date filtering functions added (to filter between a range or just after a date) - List function class added to contain constantly reused FP methods on lists. --- .../java/seedu/calculator/Calculator.java | 4 +- src/main/java/seedu/duke/list/FoodList.java | 68 ++++++++++++++++--- .../java/seedu/duke/list/FoodListManager.java | 44 ++++++++---- .../java/seedu/duke/list/ListFunction.java | 34 ++++++++++ .../java/seedu/duke/list/FoodListTest.java | 24 ++++++- 5 files changed, 148 insertions(+), 26 deletions(-) create mode 100644 src/main/java/seedu/duke/list/ListFunction.java diff --git a/src/main/java/seedu/calculator/Calculator.java b/src/main/java/seedu/calculator/Calculator.java index dfbd8a221c..0201fd79ca 100644 --- a/src/main/java/seedu/calculator/Calculator.java +++ b/src/main/java/seedu/calculator/Calculator.java @@ -3,6 +3,7 @@ import seedu.duke.food.Food; import java.util.ArrayList; +import java.util.List; /** * Represents a calculator of food items in foodList. @@ -19,7 +20,7 @@ public class Calculator { * * @param foodList foodList containing food items to calculate. */ - public Calculator(ArrayList foodList) { + public Calculator(List foodList) { assert foodList != null : "the foodList should not be null."; for (int i = 0; i < foodList.size(); i++) { totalCalorie += foodList.get(i).getCalorie(); @@ -29,6 +30,7 @@ public Calculator(ArrayList foodList) { } } + /** * Returns an int type variable containing the value of total calorie. * diff --git a/src/main/java/seedu/duke/list/FoodList.java b/src/main/java/seedu/duke/list/FoodList.java index a334418f87..42c5311cc3 100644 --- a/src/main/java/seedu/duke/list/FoodList.java +++ b/src/main/java/seedu/duke/list/FoodList.java @@ -1,7 +1,9 @@ package seedu.duke.list; import java.util.ArrayList; +import java.util.List; import seedu.duke.food.Food; +import java.time.LocalDateTime; /** @@ -20,7 +22,7 @@ public FoodList() { } /** - * Convenience constructor mainly for testing purposes. + * Convenience constructor for testing purposes. */ protected FoodList(ArrayList entries) { this.foodEntries = entries; @@ -35,9 +37,9 @@ protected FoodList(ArrayList entries) { * @return string representation of the food object added */ public String addFood(int portionSize, Food food) { - FoodEntry toAdd = new FoodEntry(portionSize, food); - foodEntries.add(toAdd); - return toAdd.toString(); + FoodEntry entry = new DatedFoodEntry(portionSize, food); + foodEntries.add(entry); + return entry.toString(); } /** @@ -45,11 +47,12 @@ public String addFood(int portionSize, Food food) { */ public String addFood(int portionSize, String name, int calorie, int carbohydrate, int protein, int fat) { - FoodEntry toAdd = new FoodEntry(portionSize, name, calorie, carbohydrate, protein, fat); - foodEntries.add(toAdd); - return toAdd.toString(); + FoodEntry entry = new DatedFoodEntry(portionSize, name, calorie, carbohydrate, protein, fat); + foodEntries.add(entry); + return entry.toString(); } + /** * Food database search functionality support. * Not expected to function. Added for completeness. @@ -63,6 +66,20 @@ public String addFood(int portionSize, String name) throws FoodNotFoundException throw new FoodNotFoundException(); } + + /** + * Add add method for baglogged entries. + * Allows specificiation of time via LocalDateTime param. + * @param dateTime User specified time for backlogged entry. + */ + public String addFoodAtDateTime(int portionSize, String name, int calorie, + int carbohydrate, int protein, int fat, LocalDateTime dateTime) { + + FoodEntry entry = new DatedFoodEntry(portionSize, name, calorie, carbohydrate, protein, fat, dateTime); + foodEntries.add(entry); + return entry.toString(); + } + /** * Deletes the the entry of the list at the provided index. * index starts from 1 (not 0). i.e. is User's understanding of index. @@ -83,22 +100,55 @@ public boolean clear() { return true; } + /** * Obtain the food objects in Foodlist as an ArrayList. * For other classes that wish to operate on the Food items directly. * @return Arraylist of ordered Food objects in Foodlist's foodEntries. */ - public ArrayList getFoods() { + public List getFoods() { return FoodListManager.listToFoods(foodEntries); } /** * Obtain list of food objects in FoodList, scaled to portion size. */ - public ArrayList getPortionedFoods() { + public List getPortionedFoods() { return FoodListManager.listToPortionedFoods(foodEntries); } + /** + * Obtain list of foods consumed after specified timing. + */ + public List getFoodsAfterDateTime(LocalDateTime dateTime) { + List entriesAfterDateTime = FoodListManager.filterListByDate(foodEntries, dateTime); + return FoodListManager.listToFoods(entriesAfterDateTime); + } + + /** + * Obtain list of foods consumed after specified timing, scaled to portion size. + */ + public List getPortionedFoodsAfterDateTime(LocalDateTime dateTime) { + List entriesAfterDateTime = FoodListManager.filterListByDate(foodEntries, dateTime); + return FoodListManager.listToFoods(entriesAfterDateTime); + } + + /** + * Obtain list of foods consumed within the range of a specified timing. + */ + public List getFoodsInDateTimeRange(LocalDateTime start, LocalDateTime end) { + List entriesInRange = FoodListManager.filterListByDate(foodEntries, start, end); + return FoodListManager.listToFoods(entriesInRange); + } + + /** + * Obtain list of foods consumed within the range of a specified timing, scaled to portion size. + */ + public List getPortionedFoodsInDateTimeRange(LocalDateTime start, LocalDateTime end) { + List entriesInRange = FoodListManager.filterListByDate(foodEntries, start, end); + return FoodListManager.listToPortionedFoods(entriesInRange); + } + @Override public String toString() { return FoodListManager.listToString(foodEntries); diff --git a/src/main/java/seedu/duke/list/FoodListManager.java b/src/main/java/seedu/duke/list/FoodListManager.java index 45b9a5373f..cf6c2ced0b 100644 --- a/src/main/java/seedu/duke/list/FoodListManager.java +++ b/src/main/java/seedu/duke/list/FoodListManager.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.function.Function; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.time.LocalDateTime; /** * Class with static methods to execute "complex commands" on FoodList. @@ -18,7 +20,7 @@ public class FoodListManager { * Internal helper method to convert the items in the arraylist into enumed strings. * Primarily used to obtain String representations of the entire list. */ - protected static String listToString(ArrayList list) { + protected static String listToString(List list) { String listString = ""; for (int i = 1; i <= list.size(); i++) { @@ -46,7 +48,7 @@ protected static FoodEntry deleteEntry(List list, int index) throws I */ protected static List listToStrings(List list) { Function function = x -> x.toString(); - return applyFunctionToList(list, function); + return ListFunction.applyFunctionToList(list, function); } /** @@ -54,9 +56,9 @@ protected static List listToStrings(List list) { * @param list list of foodEntries * @return arraylist of Food objects. */ - protected static ArrayList listToFoods(List list) { + protected static List listToFoods(List list) { Function function = x -> x.getFood(); - return applyFunctionToList(list, function); + return ListFunction.applyFunctionToList(list, function); } /** @@ -65,7 +67,7 @@ protected static ArrayList listToFoods(List list) { * @param list list of FoodEntries * @return arraylist of Food objects */ - protected static ArrayList listToPortionedFoods(List list) { + protected static List listToPortionedFoods(List list) { Function function = x -> { Food baseFood = x.getFood(); /** Explicitly getting return type of getPortionSize() is avoided. @@ -78,22 +80,34 @@ protected static ArrayList listToPortionedFoods(List list) { baseFood.getProtein() * x.getPortionSize(), baseFood.getFat() * x.getPortionSize()); }; - return applyFunctionToList(list, function); + return ListFunction.applyFunctionToList(list, function); } /** - * Generic method to map a function across a list. - * @param list list to operate on - * @param function function to be mapped across list - * @return list of mapped items under provided function + * Obtain only food entries after a specified dateTime. */ - protected static ArrayList applyFunctionToList(List list, Function function) { - ArrayList appliedList = new ArrayList<>(); - Consumer addResultToAppliedList = x -> appliedList.add(function.apply(x)); - list.forEach(addResultToAppliedList); - return appliedList; + protected static List filterListByDate(List list, LocalDateTime dateTime) { + Predicate predicate = x -> { + assert (x instanceof DatedFoodEntry) : "A FoodEntry without a date was unexpectedly added and found"; + DatedFoodEntry datedEntry = (DatedFoodEntry) x; + return dateTime.isBefore(datedEntry.getDateTime()); + }; + return ListFunction.filterList(list, predicate); } + /** + * Obtain only food entries within a specified range of dateTimes. + */ + protected static List filterListByDate(List list, LocalDateTime start, LocalDateTime end) { + Predicate predicate = x -> { + assert (x instanceof DatedFoodEntry) : "A FoodEntry without a date was unexpectedly added and found"; + DatedFoodEntry datedEntry = (DatedFoodEntry) x; + return start.isBefore(datedEntry.getDateTime()) && end.isAfter(datedEntry.getDateTime()); + }; + return ListFunction.filterList(list, predicate); + } + + } // Potential future work: create a functional interface for the functions instead: diff --git a/src/main/java/seedu/duke/list/ListFunction.java b/src/main/java/seedu/duke/list/ListFunction.java new file mode 100644 index 0000000000..929066355c --- /dev/null +++ b/src/main/java/seedu/duke/list/ListFunction.java @@ -0,0 +1,34 @@ +package seedu.duke.list; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; + + +/** + * Functional programming support methods for Lists. + */ +public class ListFunction { + /** + * Maps a function across a list. + * @param list list to operate on + * @param function function to be mapped across list + * @return list of mapped items under provided function + */ + protected static ArrayList applyFunctionToList(List list, Function function) { + ArrayList appliedList = new ArrayList<>(); + Consumer addResultToAppliedList = x -> appliedList.add(function.apply(x)); + list.forEach(addResultToAppliedList); + return appliedList; + } + + /** + * Filters the list by the given predicate. + */ + protected static List filterList(List list, Predicate predicate) { + return list.stream().filter(predicate).collect(Collectors.toList()); + } +} diff --git a/src/test/java/seedu/duke/list/FoodListTest.java b/src/test/java/seedu/duke/list/FoodListTest.java index e0e056a79b..1c011fbe86 100644 --- a/src/test/java/seedu/duke/list/FoodListTest.java +++ b/src/test/java/seedu/duke/list/FoodListTest.java @@ -46,7 +46,7 @@ void foodPortionScaling_standardList_scaledFoodList() { void deleteItemTest() { Food food = new Food("Kobe Beef", 480,50,40,30); FoodEntry entry = new FoodEntry(3, food); - assertEquals(list.delete(1), entry.toString()); + assertEquals(entry.toString(), list.delete(1)); } @Test @@ -58,4 +58,26 @@ void dateComparisonTest() { } + @Test + void dateFilterAfterTest() { + LocalDateTime timeNow = LocalDateTime.now(); + + assertTrue(list.getFoodsAfterDateTime(timeNow).size() == 0); + assertEquals(list.getFoodsAfterDateTime(LocalDateTime.MIN).toString(), + list.getFoods().toString()); + + // add new entries too: + list.addFood(1, food); + assertEquals(food.toString(), list.getFoodsAfterDateTime(timeNow).get(0).toString()); + + } + + @Test + void dateFilterRangeTest() { + LocalDateTime timeNow = LocalDateTime.now(); + assertTrue(list.getFoodsInDateTimeRange(timeNow, LocalDateTime.MAX).size() == 0); + assertEquals(list.getPortionedFoodsInDateTimeRange(LocalDateTime.MIN, timeNow).toString(), + list.getPortionedFoods().toString()); + } + } From aa20da5b4dabd4dd025d8802ad3a9c62194ef1fe Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 26 Oct 2020 18:45:37 +0800 Subject: [PATCH 174/271] update FoodListTest time test Some computers execute too quickly such that there is not neglible difference in time elapsed. Added a short 1 second sleep to prevent this from causing errors. --- src/test/java/seedu/duke/list/FoodListTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/seedu/duke/list/FoodListTest.java b/src/test/java/seedu/duke/list/FoodListTest.java index 1c011fbe86..5bf8129a2f 100644 --- a/src/test/java/seedu/duke/list/FoodListTest.java +++ b/src/test/java/seedu/duke/list/FoodListTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.LocalDateTime; +import java.util.concurrent.TimeUnit; import seedu.duke.food.Food; @@ -67,6 +68,13 @@ void dateFilterAfterTest() { list.getFoods().toString()); // add new entries too: + if (! LocalDateTime.now().isAfter(timeNow)) { // Execution is too fast that now() = timeNow. + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + System.out.println("Unexpected Interruption"); + } + } list.addFood(1, food); assertEquals(food.toString(), list.getFoodsAfterDateTime(timeNow).get(0).toString()); From 4c223c95129ffbd063f92fb0ed0385f109b31656 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Mon, 26 Oct 2020 19:08:44 +0800 Subject: [PATCH 175/271] update FoodListTest to run slower Executing too quickly affects use of LocalDateTime.now() in tests. --- src/test/java/seedu/duke/list/FoodListTest.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/duke/list/FoodListTest.java b/src/test/java/seedu/duke/list/FoodListTest.java index 5bf8129a2f..e7bf197d88 100644 --- a/src/test/java/seedu/duke/list/FoodListTest.java +++ b/src/test/java/seedu/duke/list/FoodListTest.java @@ -67,7 +67,7 @@ void dateFilterAfterTest() { assertEquals(list.getFoodsAfterDateTime(LocalDateTime.MIN).toString(), list.getFoods().toString()); - // add new entries too: + // add new entries: if (! LocalDateTime.now().isAfter(timeNow)) { // Execution is too fast that now() = timeNow. try { TimeUnit.SECONDS.sleep(1); @@ -83,7 +83,18 @@ void dateFilterAfterTest() { @Test void dateFilterRangeTest() { LocalDateTime timeNow = LocalDateTime.now(); + + if (! LocalDateTime.now().isAfter(timeNow)) { // Execution is too fast that now() = timeNow. + try { + TimeUnit.SECONDS.sleep(1); + timeNow = LocalDateTime.now(); + } catch (InterruptedException e) { + System.out.println("Unexpected Interruption"); + } + } + assertTrue(list.getFoodsInDateTimeRange(timeNow, LocalDateTime.MAX).size() == 0); + assertEquals(list.getPortionedFoodsInDateTimeRange(LocalDateTime.MIN, timeNow).toString(), list.getPortionedFoods().toString()); } From 1b966fd6a3d0b352538c8aebca9a442638d40fab Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Tue, 27 Oct 2020 01:37:57 +0800 Subject: [PATCH 176/271] Bug Fixes and new sub-features Bug Fixes: -activity lvl .equal to prevent 22 from being accepted - info -> when last option input is a single char New Features: - name and info can only be accepted once - cant use other command if name and info not entered - name first then info ,,, fixed order --- src/main/java/seedu/dietbook/Manager.java | 2 ++ .../java/seedu/dietbook/checker/InputChecker.java | 12 +++++++----- src/main/java/seedu/dietbook/command/AddCommand.java | 8 +++++++- .../seedu/dietbook/command/CalculateCommand.java | 8 +++++++- .../java/seedu/dietbook/command/ClearCommand.java | 8 +++++++- src/main/java/seedu/dietbook/command/Command.java | 1 + .../java/seedu/dietbook/command/DataCommand.java | 8 +++++++- .../java/seedu/dietbook/command/DeleteCommand.java | 5 +++++ .../java/seedu/dietbook/command/HelpCommand.java | 8 +++++++- .../java/seedu/dietbook/command/InfoCommand.java | 7 +++++++ .../java/seedu/dietbook/command/ListCommand.java | 8 +++++++- .../java/seedu/dietbook/command/NameCommand.java | 7 ++++++- .../java/seedu/dietbook/command/UserinfoCommand.java | 10 +++++++++- 13 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index ad4c9be9f9..2b5bdf9dcc 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -1,5 +1,6 @@ package seedu.dietbook; +import seedu.dietbook.checker.InputChecker; import seedu.dietbook.command.AddCommand; import seedu.dietbook.command.CalculateCommand; import seedu.dietbook.command.ClearCommand; @@ -35,6 +36,7 @@ public class Manager { private Person person; private FoodList foodList; private String name; + private int commandCount = 1; private DataBase dataBase; private Calculator calculator; private static Scanner s = new Scanner(System.in); diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 53772478f4..c6f85f3680 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -44,11 +44,13 @@ public static void checkEmpty(String userInput, String command) throws DietExcep * @throws DietException when an option is specified but its field is empty. */ public static void checkEmptyOption(String[] input) throws DietException { - try { - if (input[1].trim().charAt(1) == '/') { - throw new DietException("Error! Option specified with empty field!"); + if (input.length > 1) { + if (input[1].length() > 1) { + if (input[1].trim().charAt(1) == '/') { + throw new DietException("Error! Option specified with empty field!"); + } } - } catch (IndexOutOfBoundsException e) { + } else { throw new DietException("Error! Option specified with empty field!"); } } @@ -122,7 +124,7 @@ public static void checkNutrientType(String userInput) throws DietException { public static void checkActivity(String userInput) throws DietException { boolean checkContain = false; for (String param: PARAM_ACTIVITY) { - if (userInput.contains(param)) { + if (userInput.equals(param)) { checkContain = true; } } diff --git a/src/main/java/seedu/dietbook/command/AddCommand.java b/src/main/java/seedu/dietbook/command/AddCommand.java index 6a7b6a7524..d5a6e1da9a 100644 --- a/src/main/java/seedu/dietbook/command/AddCommand.java +++ b/src/main/java/seedu/dietbook/command/AddCommand.java @@ -2,6 +2,7 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; public class AddCommand extends Command { String foodName; @@ -11,7 +12,12 @@ public AddCommand(String foodName) { } @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } ui.printNewFood(this.foodName); manager.setCalculator(); } diff --git a/src/main/java/seedu/dietbook/command/CalculateCommand.java b/src/main/java/seedu/dietbook/command/CalculateCommand.java index babeab4194..890aaa643f 100644 --- a/src/main/java/seedu/dietbook/command/CalculateCommand.java +++ b/src/main/java/seedu/dietbook/command/CalculateCommand.java @@ -2,6 +2,7 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; public class CalculateCommand extends Command { int calorie; @@ -19,7 +20,12 @@ public CalculateCommand(int calorie, int carb, int protein, int fat, String para } @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } manager.setCalculator(); switch (this.param) { case "all": diff --git a/src/main/java/seedu/dietbook/command/ClearCommand.java b/src/main/java/seedu/dietbook/command/ClearCommand.java index b07f6dda71..41f7939ab3 100644 --- a/src/main/java/seedu/dietbook/command/ClearCommand.java +++ b/src/main/java/seedu/dietbook/command/ClearCommand.java @@ -2,10 +2,16 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; public class ClearCommand extends Command { @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } ui.printClearFoodListMessage(); manager.getFoodList().clear(); } diff --git a/src/main/java/seedu/dietbook/command/Command.java b/src/main/java/seedu/dietbook/command/Command.java index 5282fc1990..43ff34400e 100644 --- a/src/main/java/seedu/dietbook/command/Command.java +++ b/src/main/java/seedu/dietbook/command/Command.java @@ -13,5 +13,6 @@ */ public abstract class Command { + public static int commandCount = 1; public abstract void execute(Manager manager, Ui ui) throws DietException; } diff --git a/src/main/java/seedu/dietbook/command/DataCommand.java b/src/main/java/seedu/dietbook/command/DataCommand.java index deb0767b9a..a5a708d898 100644 --- a/src/main/java/seedu/dietbook/command/DataCommand.java +++ b/src/main/java/seedu/dietbook/command/DataCommand.java @@ -2,11 +2,17 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; public class DataCommand extends Command { @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } manager.getDataBase().init(); //ui.printDatabase(manager.getDataBase().getFoodList()); } diff --git a/src/main/java/seedu/dietbook/command/DeleteCommand.java b/src/main/java/seedu/dietbook/command/DeleteCommand.java index 260635b297..4236acecab 100644 --- a/src/main/java/seedu/dietbook/command/DeleteCommand.java +++ b/src/main/java/seedu/dietbook/command/DeleteCommand.java @@ -13,6 +13,11 @@ public DeleteCommand(int index) { @Override public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } try { ui.printDeletedFood(manager.getFoodList().delete(this.index)); manager.setCalculator(); diff --git a/src/main/java/seedu/dietbook/command/HelpCommand.java b/src/main/java/seedu/dietbook/command/HelpCommand.java index 733cb3e3bb..75b081d4bd 100644 --- a/src/main/java/seedu/dietbook/command/HelpCommand.java +++ b/src/main/java/seedu/dietbook/command/HelpCommand.java @@ -2,10 +2,16 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; public class HelpCommand extends Command { @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } ui.printHelpCommandMessage(); } } diff --git a/src/main/java/seedu/dietbook/command/InfoCommand.java b/src/main/java/seedu/dietbook/command/InfoCommand.java index 8a7f215b13..98defd4e61 100644 --- a/src/main/java/seedu/dietbook/command/InfoCommand.java +++ b/src/main/java/seedu/dietbook/command/InfoCommand.java @@ -2,6 +2,7 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.checker.InputChecker; import seedu.dietbook.exception.DietException; import seedu.dietbook.parser.Parser; @@ -14,7 +15,13 @@ public InfoCommand(String userInput) { @Override public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount != 2) { + throw new DietException("Basic information has already been input!"); + } Parser.executeProcessedInfo(this.userInput, manager); + commandCount++; ui.printInitialisationCompleteMessage(); } } diff --git a/src/main/java/seedu/dietbook/command/ListCommand.java b/src/main/java/seedu/dietbook/command/ListCommand.java index 5e44014eec..d3e7e44541 100644 --- a/src/main/java/seedu/dietbook/command/ListCommand.java +++ b/src/main/java/seedu/dietbook/command/ListCommand.java @@ -2,10 +2,16 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; public class ListCommand extends Command { @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } ui.printFoodList(manager.getFoodList().toString()); } } diff --git a/src/main/java/seedu/dietbook/command/NameCommand.java b/src/main/java/seedu/dietbook/command/NameCommand.java index 11f6d44e3a..181e1084da 100644 --- a/src/main/java/seedu/dietbook/command/NameCommand.java +++ b/src/main/java/seedu/dietbook/command/NameCommand.java @@ -3,6 +3,7 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; public class NameCommand extends Command { @@ -13,7 +14,11 @@ public NameCommand(String name) { } @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount != 1) { + throw new DietException("Name has already been entered!"); + } + commandCount++; manager.setName(this.name); ui.printAskForUserInfoMessage(manager.getName()); } diff --git a/src/main/java/seedu/dietbook/command/UserinfoCommand.java b/src/main/java/seedu/dietbook/command/UserinfoCommand.java index 40c8fca39b..fe2bb1f786 100644 --- a/src/main/java/seedu/dietbook/command/UserinfoCommand.java +++ b/src/main/java/seedu/dietbook/command/UserinfoCommand.java @@ -2,10 +2,18 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; + +import java.io.DataInput; public class UserinfoCommand extends Command { @Override - public void execute(Manager manager, Ui ui) { + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } ui.printPersonInfo(manager.getPerson().toString()); } } From 7c604096db2f9d0c0a2816017d321a453d116ce0 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Tue, 27 Oct 2020 01:40:01 +0800 Subject: [PATCH 177/271] redundant import --- src/main/java/seedu/dietbook/Manager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 2b5bdf9dcc..a4e11aeed7 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -1,6 +1,5 @@ package seedu.dietbook; -import seedu.dietbook.checker.InputChecker; import seedu.dietbook.command.AddCommand; import seedu.dietbook.command.CalculateCommand; import seedu.dietbook.command.ClearCommand; From a9fdcf3cbf587d2327d30bfa10fbe3ba37eac5c3 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Tue, 27 Oct 2020 01:44:24 +0800 Subject: [PATCH 178/271] checkstyle --- src/main/java/seedu/dietbook/command/Command.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/seedu/dietbook/command/Command.java b/src/main/java/seedu/dietbook/command/Command.java index 43ff34400e..03a2d4d3ef 100644 --- a/src/main/java/seedu/dietbook/command/Command.java +++ b/src/main/java/seedu/dietbook/command/Command.java @@ -14,5 +14,6 @@ public abstract class Command { public static int commandCount = 1; + public abstract void execute(Manager manager, Ui ui) throws DietException; } From 1f4604153c01944483ebf03629b90c5963741dd4 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 02:21:05 +0800 Subject: [PATCH 179/271] Update faq and command summary section --- docs/UserGuide.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 0189022c3d..def08b3611 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -156,10 +156,11 @@ Example of usage: **Q**: How do I transfer my data to another computer? -**A**: {your answer here} +**A**: Either download `dietbook.jar` on the other computer and overwrite the empty data files with the data files from your previous computer or copy the whole DietBook home folder from the previous computer to the new computer. ## Command Summary -{Give a 'cheat sheet' of commands here} - -* Add todo `todo n/TODO_NAME d/DEADLINE` +Action | Format, Examples +---- | ---- +userinfo | `userinfo` +editinfo | `[n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/CURRENT_WEIGHT] [t/TARGET_WEIGHT] [l/ACTIVITY_LEVEL]`
e.g.,`editinfo c/75 l/4` From 338a94ad1a422952408d203e50664931070dc4f2 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 02:21:29 +0800 Subject: [PATCH 180/271] Update quick start and features section --- docs/UserGuide.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index def08b3611..1f75db48a1 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -9,6 +9,11 @@ DietBook is a desktop application targeting NUS students optimized for use via a 1. Download the latest version of `dietbook.jar` from [here](https://github.com/AY2021S1-CS2113-T14-4/tp/releases). 1. Copy the file to the folder you want to use as the home folder for your DietBook. 1. Either double-click the jar file to start the application or navigate to the folder containing the jar file on command prompt and run the command `java -jar dietbook.jar`. +1. For first time users: + 1. A CLI similar to the one shown on the picture below should appear within a few seconds. +1. For existing user: + 1. A CLI similar to the one shown on the picture below should appear within a few seconds. +1. Refer to the Features section below for more details of each command. ## Features @@ -75,13 +80,12 @@ Format: `editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/ * 4 = You engage in vigorous exercise or have a physically demanding job. * 5 = You engage in extremely vigorous exercise or have an extremely physically demanding job. -Input examples: +Example of usage: -* `editinfo n/John` edits the updated the name stored in DietBook. -* Both `editinfo c/75 l/4` and `editinfo l/4 c/75` edits the current weight and activity level of the - user to be `75` and `You engage in vigorous exercise or have a physically demanding job.` respectively. +* `editinfo n/John` edits the name of the user to be `John`. +* Both `editinfo c/75 l/4` and `editinfo l/4 c/75` edits the current weight and activity level of the user to be `75` and `You engage in vigorous exercise or have a physically demanding job.` respectively. -Output example for input example 2: +Output example for usage example 2: ``` Got it! I've updated your personal information: Name: Jack From 430fe4534a3e3351974b51b5f368cd0e2ae3180e Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 11:47:52 +0800 Subject: [PATCH 181/271] Shift readCommand method over to Ui --- src/main/java/seedu/dietbook/DietBook.java | 2 +- src/main/java/seedu/dietbook/Manager.java | 5 ----- src/main/java/seedu/dietbook/Ui.java | 15 +++++++++++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/dietbook/DietBook.java b/src/main/java/seedu/dietbook/DietBook.java index 4bcdbf404d..d9dec101b7 100644 --- a/src/main/java/seedu/dietbook/DietBook.java +++ b/src/main/java/seedu/dietbook/DietBook.java @@ -40,7 +40,7 @@ public static void main(String[] args) throws FileNotFoundException { while (!isExit) { try { - String userInput = dietBook.manager.readCommand(); + String userInput = dietBook.ui.readCommand(); Command c = dietBook.manager.manage(userInput); c.execute(dietBook.manager, dietBook.ui); } catch (DietException e) { diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 856760e0c0..2445486059 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -38,7 +38,6 @@ public class Manager { private int commandCount = 1; private DataBase dataBase; private Calculator calculator; - private static Scanner s = new Scanner(System.in); public static final String COMMAND_ADD = "add"; public static final String COMMAND_CALCULATE = "calculate"; @@ -61,10 +60,6 @@ public Manager(FoodList foodlist, DataBase dataBase) { this.calculator = new Calculator(foodList.getFoods()); } - public String readCommand() { - return s.nextLine(); - } - public FoodList getFoodList() { return this.foodList; } diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index de395c1d5f..c5ff4030ec 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -5,15 +5,17 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.Scanner; /** * Represents a text user interface. - * A Ui objects deals with user interaction by showing users the appropriate messages after a - * valid command is executed or when an error occurs. + * A Ui objects deals with user interaction by taking in user inputs and showing users the + * appropriate messages after a valid command is executed or when an error occurs. */ public class Ui { private static final String LINE_SEPARATOR = System.lineSeparator(); + private static Scanner scanner = new Scanner(System.in); /** * Constructs a Ui object. @@ -26,6 +28,15 @@ public Ui() { // Methods required to print system related commands or messages. + /** + * Reads in and returns the user input. + * + * @return The user input. + */ + public String readCommand() { + return scanner.nextLine(); + } + /** * Prints the welcome message from DietBook when it is fist booted up. */ From aeba42fcb718a23a708bc29a39ca8111b4fa3c9f Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Tue, 27 Oct 2020 14:43:48 +0800 Subject: [PATCH 182/271] Resolve merge conflicts Pulled changes from master to resolve conflicts --- .../java/seedu/dietbook/FoodListTest.java | 19 ------------------- .../java/seedu/dietbook/food/FoodTest.java | 1 - .../seedu/dietbook/list/FoodListTest.java | 4 ++-- 3 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 src/test/java/seedu/dietbook/FoodListTest.java diff --git a/src/test/java/seedu/dietbook/FoodListTest.java b/src/test/java/seedu/dietbook/FoodListTest.java deleted file mode 100644 index 1d3858913a..0000000000 --- a/src/test/java/seedu/dietbook/FoodListTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package seedu.dietbook; - -import seedu.dietbook.list.FoodList; -import seedu.dietbook.food.Food; -import org.junit.jupiter.api.Test; - - -class FoodListTest { - public static void main(String[] args) { - Food food = new Food("Kobe Beef", 480,50,40,30); - FoodList foodList = new FoodList(); - - System.out.println(foodList.addFood(3, food)); - System.out.println(foodList.addFood(2, "Sashimi", 100, 0, 30, 10)); - System.out.println(foodList); - System.out.println(foodList.delete(1)); - System.out.println(foodList); - } -} \ No newline at end of file diff --git a/src/test/java/seedu/dietbook/food/FoodTest.java b/src/test/java/seedu/dietbook/food/FoodTest.java index dea27acfa4..5e711152f0 100644 --- a/src/test/java/seedu/dietbook/food/FoodTest.java +++ b/src/test/java/seedu/dietbook/food/FoodTest.java @@ -1,6 +1,5 @@ package seedu.dietbook.food; -import seedu.dietbook.food.Food; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/seedu/dietbook/list/FoodListTest.java b/src/test/java/seedu/dietbook/list/FoodListTest.java index 99779fe16e..62c7f08ffc 100644 --- a/src/test/java/seedu/dietbook/list/FoodListTest.java +++ b/src/test/java/seedu/dietbook/list/FoodListTest.java @@ -1,10 +1,10 @@ -package seedu.duke.list; +package seedu.dietbook.list; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; import static org.junit.jupiter.api.Assertions.assertEquals; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; class FoodListTest { From 0876b11678055935ec188ef0e4928decafe6f99c Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Tue, 27 Oct 2020 15:17:08 +0800 Subject: [PATCH 183/271] Resolve merge conflicts --- src/main/java/seedu/dietbook/list/DatedFoodEntry.java | 4 ++-- src/main/java/seedu/dietbook/list/FoodList.java | 4 ++-- src/main/java/seedu/dietbook/list/FoodListManager.java | 2 -- src/main/java/seedu/dietbook/list/ListFunction.java | 2 +- src/test/java/seedu/dietbook/list/FoodListTest.java | 4 ++-- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/dietbook/list/DatedFoodEntry.java b/src/main/java/seedu/dietbook/list/DatedFoodEntry.java index ad2c3f9395..484449ae52 100644 --- a/src/main/java/seedu/dietbook/list/DatedFoodEntry.java +++ b/src/main/java/seedu/dietbook/list/DatedFoodEntry.java @@ -1,6 +1,6 @@ -package seedu.duke.list; +package seedu.dietbook.list; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.time.LocalDateTime; public class DatedFoodEntry extends FoodEntry implements Comparable { diff --git a/src/main/java/seedu/dietbook/list/FoodList.java b/src/main/java/seedu/dietbook/list/FoodList.java index 42c5311cc3..bb646606b3 100644 --- a/src/main/java/seedu/dietbook/list/FoodList.java +++ b/src/main/java/seedu/dietbook/list/FoodList.java @@ -1,9 +1,9 @@ -package seedu.duke.list; +package seedu.dietbook.list; import java.util.ArrayList; import java.util.List; -import seedu.duke.food.Food; import java.time.LocalDateTime; +import seedu.dietbook.food.Food; /** diff --git a/src/main/java/seedu/dietbook/list/FoodListManager.java b/src/main/java/seedu/dietbook/list/FoodListManager.java index d3b660717e..2c35f45dc2 100644 --- a/src/main/java/seedu/dietbook/list/FoodListManager.java +++ b/src/main/java/seedu/dietbook/list/FoodListManager.java @@ -1,10 +1,8 @@ package seedu.dietbook.list; import seedu.dietbook.food.Food; -import java.util.ArrayList; import java.util.List; import java.util.function.Function; -import java.util.function.Consumer; import java.util.function.Predicate; import java.time.LocalDateTime; diff --git a/src/main/java/seedu/dietbook/list/ListFunction.java b/src/main/java/seedu/dietbook/list/ListFunction.java index 929066355c..2d6174dded 100644 --- a/src/main/java/seedu/dietbook/list/ListFunction.java +++ b/src/main/java/seedu/dietbook/list/ListFunction.java @@ -1,4 +1,4 @@ -package seedu.duke.list; +package seedu.dietbook.list; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/seedu/dietbook/list/FoodListTest.java b/src/test/java/seedu/dietbook/list/FoodListTest.java index e7bf197d88..586eb5e811 100644 --- a/src/test/java/seedu/dietbook/list/FoodListTest.java +++ b/src/test/java/seedu/dietbook/list/FoodListTest.java @@ -1,4 +1,4 @@ -package seedu.duke.list; +package seedu.dietbook.list; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; @@ -7,8 +7,8 @@ import java.time.LocalDateTime; import java.util.concurrent.TimeUnit; +import seedu.dietbook.food.Food; -import seedu.duke.food.Food; class FoodListTest { From fe6f73068f73bd53fd1545dbc1cd491ba3837dfa Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Tue, 27 Oct 2020 16:23:09 +0800 Subject: [PATCH 184/271] Repeated option checker --- .../seedu/dietbook/checker/InputChecker.java | 22 ++++++++++++++++++- .../java/seedu/dietbook/parser/Parser.java | 2 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index c5ad3a2ab8..b2dcc729c5 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -19,9 +19,10 @@ public class InputChecker { public static final int WEIGHT_CAP = 500; public static final String[] PARAM_ACTIVITY = {"1","2","3","4","5"}; public static final String[] PARAM_ADD = {"n/","x/","k/"}; + public static final String[] FULL_PARAM_ADD = {"n/","x/","k/","c/","p/","f/"}; public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; public static final String[] PARAM_GENDER = {"M","F","O"}; - public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; + public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/","c/"}; /** * Takes in user input and command to check for any expected parameters after the command. @@ -55,6 +56,25 @@ public static void checkEmptyOption(String[] input) throws DietException { } } + /** + * Takes in processed user input to check for options specified with an empty field. + * + * @param options option part of user input command. + * @throws DietException when an option is specified but its field is empty. + */ + public static void checkRepeatedOption(String command, String options) throws DietException { + String[] paramList = FULL_PARAM_ADD; + if (command.equals("info")) { + paramList = PARAM_INFO; + } + for (String param: paramList) { + int countOccurrence = options.length() - options.replace(param, "").length(); + if (countOccurrence > 2) { + throw new DietException("There are repeated options!"); + } + } + } + /** * Takes in user input to check if the expected number and type of parameter for the add command is present. * diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index cbda06f42a..99bfdcc386 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -80,6 +80,7 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws String trimmedParam; String[] processedParam; String[] paramList = {"x/", "n/", "k/", "c/", "p/", "f/"}; + InputChecker.checkRepeatedOption(getCommand(userInput), getCommandParam(userInput)); for (String param: paramList) { if (getCommandParam(userInput).contains(param)) { processedParam = getCommandParam(userInput).split(param); @@ -135,6 +136,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw int tarWeight = 0; String trimmedParam; String[] processedParam; + InputChecker.checkRepeatedOption(getCommand(userInput), getCommandParam(userInput)); for (String param: PARAM_INFO) { processedParam = getCommandParam(userInput).split(param); InputChecker.checkEmptyOption(processedParam); From 3a41a0543b2ec9fa3919ff3df84cd9af41ab5138 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Tue, 27 Oct 2020 17:47:33 +0800 Subject: [PATCH 185/271] Update InputChecker.java --- src/main/java/seedu/dietbook/checker/InputChecker.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index b2dcc729c5..669256a4a3 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -57,10 +57,11 @@ public static void checkEmptyOption(String[] input) throws DietException { } /** - * Takes in processed user input to check for options specified with an empty field. + * Takes in user input to check for repeated options. * + * @param command command part of user input. * @param options option part of user input command. - * @throws DietException when an option is specified but its field is empty. + * @throws DietException when there are options repeatedly specified. */ public static void checkRepeatedOption(String command, String options) throws DietException { String[] paramList = FULL_PARAM_ADD; From 3547101f93701fcfd2220cc363d913bb8a38ebc4 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 19:44:57 +0800 Subject: [PATCH 186/271] updated calculation of recommended daily calorie intake. assertion about the empty name. --- .../seedu/dietbook/calculator/Calculator.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index 246983b3d6..b01eddcc6d 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -22,8 +22,11 @@ public class Calculator { * @param foodList foodList containing food items to calculate. */ public Calculator(ArrayList foodList) { - assert foodList != null : "the foodList should not be null."; + assert foodList != null : "The foodList should not be null."; + for (int i = 0; i < foodList.size(); i++) { + assert foodList.get(i).getName().trim().length() != 0 : "Food names should not be empty."; + totalCalorie += foodList.get(i).getCalorie(); totalCarbohydrate += foodList.get(i).getCarbohydrate(); totalProtein += foodList.get(i).getProtein(); @@ -86,23 +89,29 @@ public int calculateRecomendation(Person person) { case LOW: if (person.getGender() == Gender.MALE) { activityScore = 1.11; - } else { + } else if (person.getGender() == Gender.FEMALE) { activityScore = 1.12; + } else { + activityScore = 1.115; } break; case MEDIUM: if (person.getGender() == Gender.MALE) { activityScore = 1.26; - } else { + } else if (person.getGender() == Gender.FEMALE) { activityScore = 1.27; + } else { + activityScore = 1.265; } break; case HIGH: default: if (person.getGender() == Gender.MALE) { activityScore = 1.48; - } else { + } else if (person.getGender() == Gender.FEMALE) { activityScore = 1.45; + } else { + activityScore = 1.465; } break; } @@ -117,6 +126,8 @@ public int calculateRecomendation(Person person) { + 726 * person.getHeight() / 100; break; default: + requirement = 508 - 8.22 * person.getAge() + 12.635 * activityScore * person.getOriginalWeight() + + 632.8 * person.getHeight() / 100; } if (person.getOriginalWeight() > person.getTargetWeight()) { From bdf49d8bff083936f53fbc7e7363bc8393adfed8 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 20:47:30 +0800 Subject: [PATCH 187/271] Update introduction for user guide --- docs/UserGuide.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 1f75db48a1..ea3880e4ff 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,9 +1,11 @@ # DietBook User Guide ## Introduction +DietBook is a desktop application targeting NUS students living on campus, optimized for use via a **Command Line Interface**. Not only can DietBook track and show the user's food and nutritional intake, it also provides users with a list of commonly eaten food items around and outside NUS. + +* Table of Contents +{:toc} -DietBook is a desktop application targeting NUS students optimized for use via a **Command Line Interface**. Not only can DietBook track and show the user's food and nutritional intake, it also provides users with a list of commonly eaten food items around and outside NUS. - ## Quick Start 1. Ensure that you have Java 11 or above installed. 1. Download the latest version of `dietbook.jar` from [here](https://github.com/AY2021S1-CS2113-T14-4/tp/releases). From c7cc3c0d6f3c3f16f7af1804645c113335d07131 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 20:48:13 +0800 Subject: [PATCH 188/271] Update quick start of the user guide --- docs/UserGuide.md | 8 ++++---- docs/images/DietBookWelcomeMessage.PNG | Bin 0 -> 23353 bytes 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 docs/images/DietBookWelcomeMessage.PNG diff --git a/docs/UserGuide.md b/docs/UserGuide.md index ea3880e4ff..c53bb4592d 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -12,10 +12,10 @@ DietBook is a desktop application targeting NUS students living on campus, optim 1. Copy the file to the folder you want to use as the home folder for your DietBook. 1. Either double-click the jar file to start the application or navigate to the folder containing the jar file on command prompt and run the command `java -jar dietbook.jar`. 1. For first time users: - 1. A CLI similar to the one shown on the picture below should appear within a few seconds. -1. For existing user: - 1. A CLI similar to the one shown on the picture below should appear within a few seconds. -1. Refer to the Features section below for more details of each command. + 1. A CLI, similar to the one shown below, should appear within a few seconds. Follow the instructions provided to setup DietBook or refer to [name](#Entering username: `name`) and [info](#Entering user information: `info`) for more detailed explanations.
+ ![DietBook Welcome Message](/images/DietBookWelcomeMessage.PNG) +1. Start using DietBook by typing any valid command and pressing Enter to execute it. +1. Refer to the [Features](#Features) section below for more details of each command. ## Features diff --git a/docs/images/DietBookWelcomeMessage.PNG b/docs/images/DietBookWelcomeMessage.PNG new file mode 100644 index 0000000000000000000000000000000000000000..483610d2e69bb9d38169e7faaad7e8c694e93471 GIT binary patch literal 23353 zcmeFZcUV(f*Ds3O!Ui_76_G7fMNmLQ=^Yy&y@nPbNbgARU_%6?C{4Q5kc5O9I>bir zB}6)iw1f~Tp@oE#sQcCTeEU21J@@(ky3bt?Wo4~3=Nfa&F~=Og-yAd1dOB*%j2w(~ zbac$>_wE|d(H+;MqdVgK`w8lmBF3N#)PF~O4AgGZA^Nyhs2`3w-qOBBM^}-+ba4MT z^)thRduBd#bf2co3+1;K_?7G->xf|Ez#H7yO zkdeC~Atx?waOCT0Iy&<_^}Dx>0m6Ss%*5QWA3+}-0!D!i3R#sX$_$roUK#^d^^hj@nZd+ z#DPq9G(~NxXGG<-nr$yDHZyo z@DeSjTqxeYoYXxgNfRsJEohO*6mF~XG zterdhy&rFGw;j#-eoFUNwc^Z=Q@1mkv}RC`|G|qZS5iGjaY!yk&dT>%^Id(;#45Ih zy6`u~A2SBn_F%bVD8!&>%Pr-QYl=(k{brmX0JGXDqGjOtU2l&4G3nhV-wlk6^#M&V z3o|TVy-}I1C}2hzFwDMr{MbY3z0U{UIxt6_k>XdD=siTJKF)$&yU?J&68&9Ey`b{zbqtY zs1o|Y*RYe8{L(rjJ(6AmC+MaVZ!D#WR0*t19NGgZ6FE9C6`OB zPU&YTY;tBx-k|$>qAVA5I((=nS{WLM@n`_QiGCEm{gP`ZXr;{S?Jmt~hTfQBU5`jZ z49gniB;27bFQjP2L~}tlCVc}RMT*b`!`WS~Hsv%meo*?UM)Nb8&rYKp`C zKi;K#E8i3lE?dwlUhEV>oW>f7)<$1AM_%QWUD_N1%|BeHr@qbNxeY}5X)U0P#J%sf zVS$&tK=+l=GaE#)C=nD-fQ8%90|H+EWkBuemxe!I_EzOe>VB)A%NYF0hG^!SgqqiX z(gj8a^oi0dr{@RV=pCuDJkEN{oTiW$KNa$z!p-1n+;IA`lL`o$9iOtGZ`CFo=xO37 z*kZ-1Yym#T`k^Q={Y+OA49#G(Y<9L0hqkwn@a$RyNa2^P)on?u0 z&FR0JL>+iOZzJj>cde`Fu&$i~IfLL?ULU=zc@R^fhevMjRBAb^z zbvC>COdgCDzwBbziNJ=MD6wuHj}T#}-tNfwHtpF}S9MGJbm^$v_17n#|9Ln6``z+o zm0=0;KyS>d=>+(2cLVcHBc(AB($t}1S7N*GhP|5Y!UfqrCGdsy$9w(0MHL^()L(tNYs{coOEY#`MvY0I7Bj~x{oxf}Z7yA@T6#S~GWImbVDxi@RK zASM7`9Kx9KT6FijA)HmC`S0^jJ|eR6qJbJPHL!dN=40r)ABE+<7ykU>Z2#+gGCBli z*gPq)$n--f;&-8bkGM9HoZb#lu6zQO*Xm(EKw41Wc%Ji(DK$7uJaRHzOl8w11LD}o z_*0MEdRJA>{s|Tz9E@o(lIIo{zOzAhxsC1N*7KqEBz7TP9FGg&{nOC*Kjff~De5?| zISbW&Q2tmHJ+3u6_oCxy)?X%cL+{3AG+B+$8iPGVj6VGooQYQ8F^9{iain<&M5?mr zw%A3M2R0T*zM3|ThRWz?YWN#2HEv}7OA*_1)Da;`mAmpr6yHj;?!o3a_a7(xPm|i@ zGulnsA%*ylL%@HG3x8e&Qgxk43>Jxc|E%=-aLaq|FlrC>uKq>e@@{vNxh=)B++yY{ z#+%&#i&@g9`&pOoCYkEgKE2pttsvU`lm>3xVh2n zt<^7tYUQ>bxI& zJ66Z)z_v5^vT0y8cAbxtTI!}MtubRaZ@$xTp?uu^n7^{BhQL4%C-XL>CkqCZTQmNk zGn>w3lC)p+LMN=g!JcHLO^34pT5CAfEhVx^PJ-ET{(U`164BfTb}@^s5{CW$Y+A>t zPd%*F|F44tTq=ur6lpua7Wv*2)OMtUdTtXLP8xqLGSBRk%Q_YGkaeE% zrhv73RuO|R6U?yotdN@x^#ycI2{wXas5j3zYW(4&R?s*%NaBxib#TqfRVk}Po4*mV zX}L!YdT4EZU@EoAK`Tc+ys!R`S^obMcKSb!5k9bpbd@dF?hmhh6(fDEcGAb3?4}}% z;4NXR_~}8z9?(4ZLz4xA=J;l#utOtlQ0Vwihr#mA(^)N+4BmQ4)OA@L>GvD@d6()= zsBN|~`8A^Zm-}V;?tX9n8o2E~`{A4Ezu&w)w}_pFJU7o=m%%?XClGcmn0*I;v@_*t48^+2(zh$e$h0l z+vqYqlx3!d!DD;Bgu#rh1`)E27UJMlqq}zOXcjSQ(ESXifRb_X)w3ffWylhJvL$ZR z-K55zQin}je*-0i{#9bq&ln{$o9-2-5b_ zh4=n#x>>eqSyZwU+7iAITBKeT@cQ?m{M;};$55+%SFY<6n)YI;uZn8+k??9MN>v=c zGWnG5t#FfHxZtG4lswxYG`gy~Q|w0J8)_-=uch>^5}*7EQ>ZX0kZ|DrZ)oP39W7GN z`YGXq3o%74sb7;EbPn`e8~ukBkJGT+yY8j5Hz%^u!WT7?9K#E$1Ws_$(8TIbH5RH= zjI{qdPNAD+wo*nNn=I66#$pGmA^T$EAE{cr7f<@BMQ5sz5OH$_+n8+=0$hjaok@db zZCRj;a$6(ZUei>; z*Qtoudu^!*^#k1ATl@zUz#mHmGZDUhT9%itmoa`}dd1hiAgkhR_rW{(+UgxVx#S7s z<+f|>Y2+*pk~F_4vYV)>+Vx`oJl_q9Lch<(*1_kzDovu(Sn+;wzd3o|#(gtltWxu^ zK6B}=a&FrFAf2(f%?+VlJFdD}?{8S-_d!HWSnWJYBSi26u$ zFkkva_C|kd`5XY&zzAd!*`2tH_!vdbIzieAwc&ywv#T!j!#VvkYxr~K`_Jdd|Nlvv zO8*0Wz7<&?Kb(??J14Kkc_{HMc%ot{VGnjq>1Hdf{rF)NqsW>5udH1DTG3L@{Zo*N#cGb-Q!Y%Nzc29+%V}wO99OfyU6h zYTpehJrabt%3LacQ#0+Fwi{CpYWS|`qKDPKOsrm?@~U#uZ#=>r<_6;tciXdBD@fH# z4JV+Dp1JWd-~`^``ziYCdP`43#Qa0NUVdHUAgmI~mYfd~_vN-cG^a*wi!IV_!*CV# zAm{DLg?&)eb=Gd{``MCGUJ6%7s!bY8KK7R_gLV`k{OQ=PQJ8Z4cZtN9P-ir`^Ux!8 zUh^MEXP;@Buuk=A=AJ*kP<7amsTTB#CK87LUKwi3u>J8-^EjZiT7xhHBlo4ZC#)nQ zOxE-J7ep?~+NDhjq}k1%YNny(JRa1l#+pyinjuKU{~xaC&-^F1TW)1Kl1 zSE@;l{?^aT7qm0{Ys||$HM%svtWby+U)|%3bVyq)kSeELEJ>?Tab^G(bf9tXHRbNX@ zGya4PQ?a>@2iVs4KK_!&rW3Ncs_d*x#!7m{@D_y$4zM0OKQ-u57oH%le(roYh92vy z#?l*$($sC1*XI4h9X7k53-Rj4Yz>_0%;4D$Mjh0fJ|Vc|={Le4{Xj!W_b+_V`hXV{znyvWz>zPX zCJAXi=CzV~FZpstnO$=*ZwA|a`-SiLErARrAM|*e33S6IUN$05gsn%mluwkts~vyT z7JNT^sJbf7%~D9Pe{qkZ9itsLQ)+fT&x^bj z3d8(~OTym};EQe~fA*N}(`Oc0Ab5&M4i5_FR6|SZ(CYN04~5ajy?Tz&S)s>o-0!$F5vYOBObHLmtn2 zNGG3a&2PL~IZ7cG{eew;^)e$hu$25}fvF9G9ust#r~@m>9v%}4AhixtVuzLc++}u= zIXH5$j$eccLBaHWPh%o`Jl{7Xd8qZi%Eo!kCZ@y^h)kMbp3@+ea%wX4$-hox)+?H| zK7P4&pfAHc%GO2wUIoI@zu`s&5Vr4U48FrEHgp+Uudd z2ztcVHn@Chs#Oi$jo~0G6U&bd*IwD8H-(tpd} zb3q&b1uJ`IwzOp=!b;Ns^vGqrBb7&iW18;>V~_jcDc&*(R9?oPqK?eMD?*)2vLm6P zS&M$neOlmlKSq(2tEnCXyz<@H{p%2?XoK-aPjEc1VxGYgZzO>n-kH)pJ?pdH5So5n zk?bvN=6qOuN9#qF^31t2Uo2i<4jmEYhm|ytjYCcffEchIsK8GVdpskiOATdz!Tj$F zOMZ?M^&9GG_(j@x-K|6CBhwI`kSq-eO6e@+u-T=*31ldwf- zz+Tg&kYP(kwbzqyZQ}LaI&IYQ<>Rp1E1Dqo06&Cb#j7K7!CNNySV1^$Q$7AOKftd4 zguC)ZOOQfP{WKv>%wAYiUwH-dL15O`2GNlE2O#QPXRCzgPVCae9O5mVXgtWnyDtS^}FRu^42AftxRan)hA49$UjjM3YiHfkNRt!dnAWc{WZ!gfiAe}|&6I+k zrDs4zy1w`b#8?Gzh&kMXZEiI9G8i~jTqp0fdvFVzXz*v}mA?}5amuXW?gyXFi#%PG z)ifmC=_`Y0x!Cgup+zhUhDqC5fFho=kfq(^Ooelp_85tZ^+^e)z!=jo^)d^>?E};?k`t8=v6?I03UK=F={K zYdmgjf+pQAqmECB_?Bv27G*+hg>jX^JLBjHtBUZtyD{=LC(9gHGF(d^D=H&xvL8L= zALWbOG~4qAR9Q{Der*$o0_nJudx9%Axs8cm|Aam0gpP7gSyh}}Q?OkW@BxEfmgPYCbliP(XY7prApDvHqjKo&sIWboO)5k@6X-cJ9qI2#uUh4%>{niFJzG_qr zWw{%^wjCQ1#ID4wJh*}!9T>l5OljjQ6=83Ir~R$ap0{%c3Eym!%Kt}cE|I%`d`N88 z`=8>;|6k&p=KMhXp+`pBi|m59h>SlgPi>cZ+NFg%G`(egL0h_^>u{O8mb%6pk-&8_ zD%RMt%u`I=>}|vSQ-V02*CrPhJoVet7G0OlB|UfvBHki+U=Q!fE6VS@i7uKMgs^<- zUdz|D)uIbejVCucmU75$ELXHT$Q`xMUH?2a-vJaO?O6}wkOrguJU$ofJ&fkp%ADTC z4-4?wu5wJ>i~lXbIX!(l5@dzAruO7zj7HYJ*&Si|&K7D1Ab;yo{zU9pMLrPOA(e=!KVf#X&&K2YhGc7d|DbbmUG zrbSI}rK!4KWJa0AaZ1+!xl?*CFEq3irz61L$F&TMz1+{Cy$~TuA?TW!iG5!K<%J9~ zHKa@nWF9{L+Zh9*2hx4&x>w`Nsq%<0KGq!{2W4IhLscYeKT;drG@O(n5uVsZ$SN6| zu`k1Yih1@-os@tzeXQtZUFOdw3?CxxxS)I%*KOqrae$`3<+UsrLT0zy*-oMJ3r-}E zj6P(lt@NfjSbUDC{AMf~2fLX?6*1;p&n{+;>Om5%BaKUn8c9t>{Edb)hjsT@WMiD( zE(f5Sdiv!NA#Z3Y57yH~# z#ADH-J$X3#Yt6IUZ?D9;&FbaQ7h_AJ?=i@&Z%Qyb19SlzPd||gYS!@58p14vsd zOP)CPo$buV$u;HdQBPiFFuiB2Ugzv&mn$J@T!h}`b3>9t%bbJq>2Rm6ESO#OKocFDrfX786G~$3Q#koVPEV@~v zLncw!#*Jp;Xfi`E#bagjg2;&DzLNM%Sj4qZgB^d~vM@9cdbzWJXjd@LLELYbyT2IH z(@W-T^r{<2Qk31VjsZNiIlzaLq=dHkT`hJ>VIGiX058&BjCq=z-I?lknGSz(a`aq@ zK5rOAxBU<(;w>_CM?1u&?MTv>FH{@YCuufskLpMUZdhuEgKOVMaNge`3p@AGTk+B( z>}ob2vB7Ao#_^PYKxSTvlyz@&SF1I6T0reUNyST{q*J+EDzSnV^nP2fw=mOFLPpSd zjnr{?*mmIl(x+3|R}C%lAZeN97KEmH?OK*|1)Y4sEBo4>F!u=)q!jwy%IK1oYF6$P zx9A#=+FFO|66vl-7E2SE@O&$`z2B)Hp=c0Tu^C2NA3M)frBE{%49O@>Jfhj_yU(@j zg^+Z8cLMh`-CwTJ?G0P;#%Q^pfOXh?VvR`!{zcL@?k`szcC+3#d==qTU6!M9p`w>pnk_%=W&pJ3Mtx>7SBy^2h?eFecas@D*^IVWtCT#K3=Dc4T___~ zR77qrt&${^GT2qS^OXXV+t)tu30RwPTEU$m*3!5tC)RTEfq|qZKMyiBOX>))r{TUa z;5hJT>c`CIRl=(%PHH4nEL?N47JKF6w3Rr1i^OTH-KdLeMz(6~O^`|hGC$2|9!hq~ zIb2+eu2>|N?*zmhnsfH0CyE5WyJP(PaVZ6q`LGvH)Wmy}b|N)WHIy7gfcpT!xYb%N@n&F}bcotmG1=sF2?a`d1v`^E*+-eQo`_?Fi zPdZ_H&jCjEaQ4xRhxAlaN+*XV)+w+0sXHGrUTJ)0n(LNuE-Ci-Fv2y>xEW;s zdG%|GR$XRy`V-g#lpPK1I`;O&=J_q#2N&#OH=7%mjuH;#-w)4AujQiPNm2f$FoEq# z=!s*dexMoa*7P9StWbFkWogD?3`UMim*u@T&gwhBH@OIz-^iO2f;G$ezq7Y_^r#R0 zho1E{K@-GH67tTGBmP(4X_TJd)h*p#n-&5@>#gh-x<9C?DiVe@#Jh$Vb!jJr8&)Lk z*CZ;XOGvNO9+u`x28@de4OKL+$sGc#yvCb1O(1P?P=7eX*kdSWM0;OTe*2P=4L>&{ z)C1lHxdyrh0RoZwRRcFwGM|UUFTc(4G3ezyGdD?AeFW{B@D(@6+FlzI0F)u1g6!)M zYoa;S#_IAqMy8{L>~DWx5?iubf1G2TutQuKA|P*IU-vDF6nCLv5TgrGof~@f4Gk4f zgWS7KTGs+pR%YkEkOHYWaFZ#w=HJ*A7Q-!JNY{vgjpOqp*wr&g_esOttV6H60qu{# z^ZYu8GPQHFm|( z=0iEYr_kOz*=$XAj~&Klj?PECE?CKog>^sCPBu8y)NAqq96dUG^7+HJA4S8Lh7P3i zFME%HGeH2=VGBbC(#(QFl``@Ix)RkUCpy&m7e-K`CwxiCIDb5^-~!x!b9 zMnnZ#ag)6CCj8X!R>N4|j|AW5(rWo_V9INDF0gawO`9Ahtko3B1caRO42AeA_;(!L zru?_m1&=bLa#C1d-509jaJhu31w0wIw+?*cc2v^Sz(lg^tPZf_n;jPIt>F4jlAHDm zp?+bi3AJt|z|&>a1Zw(EllWU>a(UsiwPF) zL5emL@iR%&&{8DjVy3kJhJ9NkD(oxr)6L4iAm1Jh=Q&e9NHQ#y) zs?kUE{94}DG^6Ha%SYUu+}xpnUzYFqFguUk-63W|;T{U6Gf13KsoleP9x{Mrqk-EG z-4;3{3b_~}uiKdYm=5J+Tv;ZdG8(Gb3txOB%y6*yh#0(hAumqSH1d=d*9Q$oqj; z%Y@DmdOYBM2-1*BhPZz@&oVLR^LSHnyJtYSzRs)4W`AI#CYY^Y3fH^U1z##FhYnKi zqi2+FH&c;}b8bZ5abDd4VM}a@Q=nR}lG`f-K`wpmg{?S&W?4-pc9Efrjqn-5=bHAC z8!odCI=tpJ#{BE);@;LP93S+3~wrZW7FS%aphxW0a%}Ea?ZM5QuFl z_r{<%4bwTVxQD8n$Is?~ml{wdkWD;3d;M9k(v4dcaq=rxq!2$)P;+F=LgagHHpdo0qwVf+cgIlJzX|fBPE(WLE2+s>wDOQezj%%UU&6! zv&q)Fr@(T>`N*?O!?_WwqZQso$)>SP!Vs~j8s~}iP@z-iS8jBN{loKLxVYmZyp)7B;aqngt6Jj zxmk;r^>L1#WmOlRmTT~MC0VinH(vPs&iJJ_veY3=)pTY}lQiPK#QHR$EZ2_tAk8Nv zJ4h1l5T<4hJ8ALtkJ*o4KF}h=*2-zmY^A2*eSEFusMpdkG$6hbD~OUjzxQ$~dJ?F- zvqMlGjSuQKV;Q;T7Q34HHj z25tguWmt?#s&tu4W)hLA*Jg6D&Y#wHd_H>x%^9xj#8q)j1T`z89*nKMIJ!dvZ{y%O zdec2kqY4jKQYmrJlf5OkasF*{6I1T9+~qBES10^=;fVQDqp3{OQvSoHu%NN`#?j9X zk)sx&ay}EIbHuBbK5>BZC9rX+cw+g-;KBz=!c+n4%jKXd>H?Ab~nz_l?-}v+W5h)Y(u3mKC$K4|}{MCN8lQQ;}6p=viJ# z%;iSMk`yqzQN6csgSpiVAfmb1aAsT7@v#|jYpEHqNSTpvYv)k3nm+b&{`$#>Om-hO z6{&_rx69Z%)YGwVrJDu;Cya-~+&!g-T2aZ1^+#DVgqw6r+sGBB&14GDXN5Ju`iZfJ ztOrUCj0z|l+GPg~1)!%f&yF_(#$P5sSxxYwv#|1)nW4?G4^etodtcNv6=gzu^rB|M zhYSJD`s6X#jeyi4*5d-sgae+9g9_#J51r@S*@o;9WGqLdF|-)C7Ishc;IaX-Z1bR2 z_NCvAlMlN)d6q(Gf_`QHmdQptwVpS)O8ZYe{)5%>?+^apJxR>?m2=apNgb|XN8C91 zt*V>bbN&^+R8H*60~rJJ=|2H=&5hIM4JH)=OOubIh8AVUu?0@z;u9nQ@77u|C82t_ z%7-PxbkWNfOPz(6X>8jpbk8xQteTs;ir#UG%8R{ro*@}3Q_8>|qM*A$uM(c*qapafh0uOg-+4XdEh(LdPXD78dvj!tge2v|7prScZy7|-AHO1Nu zqtB~v8;+h{lAU5tm5m^Oi>bGw zd@DMbQKD*UZp|xMHojI%>10zmZKDO1i|d;+tB}wYoSLkw;Fy4SHoHqY9jFDb*T6X_ zePHkDN4VeNsWSaz9Fu=$Yz26~po=tW2D$^KjmAO+lHm*0c)$K!ppBiD_$t z%XCC(i?a6|bLBttSE5b4#OiR;uB>7p@Tta$CFALf3r39#H?=JShI(`t*Sx2EsdQCg zJzGOEW%EgTn#O1RT%0N{O_C42GCIU4XwYVb0!ujJs5uIkWIaEy92#OKx*_*o8ZQN4gkG0ZmZcUn{FCN9c6|F-jD0{>;^@Y66ujBK_<_NTs&{6+j4 zzbxN>Y-fR8nJmUD|r9(Zy;}4&WxPlNr#f-;d2>Y=krxd+I9IOv;oM&F>=f9iX-! z{e*@?lcnsp62I-4JI~qBMXx}HDCftkx5k!~N7o7eAJ*S>0o^jlRcA@}^_qMraro=G zsx8W5y|OiIr!u3Kx8RB236~Ky5O#R|&^Xp2c1v$KC&TOQrLjp% z#KgulBI5GQwEWzK6v_K(6pBGvGt!VbC)6ZqW(EFrMzzEeXENlbc2S-{tPNP+epetF zWE24y6W6gML|Anz!o?R6uv?(eJkeDt*ROE@Hx*W|b0zR@e84n~uFbouZiJM;25yFK zVqfNjFDdaxhC+TCVrHvmye16bYKYEjk~{e$y&rG9HW%qX%jYMQLG4Q(%Rq{>*nB|P z8=Ziyfu`NYt&zszt#<=8j8>Fnj@nRd<)Cp2ai#H;dd-O#wDDfA zyl;o>W`g24qD#nRT=xFvhRm+dTv9_VDG(3aE>YFxfnVn2#*|=`M;XLt_|DZR>$tAK z?hq~arh{F(jwwdeZtW$W#fpdJrW1U1a5X1{ygv>%-0$7wkl25{7Gz(tcHjy<5pR}b z6j)R5XQkP`9B>zLB*)RDFfVj6>m^?ywlFnyAC`So*q?*E2Snjm}FYSsq>L0RHQz~WJ* zBAn7@Av(oPxsBc0X>ny{=rbOQJI(1j{9g6{K&pt`5S>+W-MGM7-b&d5k-|2CWR%WW z-AD2%Di`FSPg@i_W8)c>uCqYP2-uJZZuVt7ln%TfqUcwIuiNtOHoGIb>gXBw6d3r zf1a%5M|3*aXVqY%lndjZji_4?Dc7x%K; zfJQnQaH9s9cq(t7u}cVHePE)xnlLj{?lKPU4)%1fFvzEoRUJbp0kihgU{rbVgsi(` zRyC;I)Tg1tMXE2zL#zDkRz+n{QT&y->=7VM_ySa3Y`5#%f_?AGKZ%*~0 z@YmI@Au`{{M~iI0mFiNgVw1tCvOe@{9e(Y{jlX0mO!9>Mouwe>vQbzr2S>LAF|*Zt z_FW_tHoYErkb<`2*7O@QGmVoI3h{WPdO!*bYuE~Le<4>~6%-5cCb|d#uI#ZhPJuk0 zT`@6{PQ6~{z6Uij0nnJ0&7E}t!H^^BY6};LPrYwV_9w z-NX%<2Tx0G=(5_ekauIh( z{Ojkn_4Siq#h`zcYlm!WfCJnCYZ`HY`VM2foB;QME!YN@Y$%6N@wesT8hoUt0pZK1DCYIVARIqTUT}CmS)bh9q;=-6#9bqgZjEbsf7SmstOS=oe|?>h zEuZ#IMb*1HLtL|+?O@dA_9}ldm`N9s1exs(@ut z>ZS8rYz*UO^a0!!8@S7$f%~WdNW~a9Eq>K zDD)J1`>vAvR6QtSbsWaom2!i+(2#xm!|JWZrJF;90*-b1ZI{}h>>CG2Wd+%?@39D| ztGv>jmRjM-12auyUpY==GFJ3xLJT)Mv(@iD3{%a|MC+0G60Sf4{ox*Gi9^k za;zQnbvEr7_hk9qSky#LAe-~eoZCWX^*Q4#t56_P1?ZonuHh3>AAXit6|U(=|6sBh zw3W00aSPNqCHjNeAUpq76Or%l1QvoO$AVOT_dRQZ57%gVEXuUm=T9Yvz8I%(pbO(T zw_G<8tNHOW)_^Nv>wcMO%JBvkO8rv{&q}l+_3)n>&E=&{^ouqO>KOsZpe1i|1z(y_ z3bQn|{r??T;uqK1@mCIkh45gfDfKcgK)#fRvK>SULdwPcl@Bm7}70g(rE+FfE8sLxe{xRZ;q2k$TS9tK0sioQme@J1MR zZ%FEY$TSE~9B5u>AgoRk)h8C+Tmx3BZK^}atrNJHF%i!Gs9PL6owvi3=9&En>k<3S z7KP&@n)O2>h0Y;J5e40TzX*N9rHP6AOTMf@9QQME(Z!l2PsQSQ<#MwkgvC9X1GF8)S?oW^bu z00Me)jiiI3oXca3Ec$JM?+iOqL%tSZus0;AV&|Fg#9&I*#b)NB`PMQw^o+6A0`KcL zr}1)v1zlC03RAq(b8A5&k&W||k0!PfJ$so&A7%!?`U2nc8Ydm=I~RsAqPSlZIHCh$ zfkHW3cKAzPqwff9=HyIFh0xQp)sH_20h#3wCNk=8;OCoIPnK0aQ=4{Hd3qdp{0_`i zn?&i~r+f{CwX5iMD&2=?e|?Is)CqzuOV*dV#v~(Mq;Rfr7A?x?VOaJg5Yf0D=bBpW zjxdMfwL^sh7xG5?9pnaEyo_z-%XXH$1gtlpWQ=*kXKh&6l!5Ww`?=A$9p>_4GKag^ zD}K{oggxPJ5rxS4sm(c~YQ(y3S;^ac@2l7I2 z0N16)4a4sFU$RoxCO!YA4PtL>iuxAKUl~i;m;`#PK2|c;n|p6Ox5!$`*Y`Gh#kf21 zPvN_8ILo1ymU{Ay`Sa6qVS!-cglA*vd>>^(whIbA7=2iz?lb(smBhF1ynA7EcEMr1 zs1Q6?o4deu=YP*i$)cJQX$fh!#*Jc-2b-}NGgfF!iN7Cz0J-oTja}=crjC$XInzH< zb1tCbuqWZuVp@{ge{@9WD-+;iJBP*hK9LZy*v4cd2y6dMjZRd zK2mXbjDM0HlDeSvEsmzUd4jsj@w}l7u~*Y&s4#kpM=$q~Wbg>y=GvKTC4|4u@Xh_w zoqI9y^}EZWd)t;m+vr6*tZ6$WzaLURG4ucAMU%PJjdw!xB_&HO36d}EQl(H{v0N$* z*eYf1j(BptS88faId2@LlV1Dd*-c1;Mfv3BD5|8Z&z@fC z&AH23t4((}A`*O>Jw^`6F1Krr@=m7JA!vD~7l$b8J6SW&m?jkGcQSv_1n1}VuQoFV zaS}1C%mJ=FCH=lF0$5-F$hNpWeKZf}o5jdiw?}ymN09d&d*!BX>b^*a?&Olv9=CA4 zQH4Ll?bH==B}Dp$mP@y$ZFN0;*=0FHeh_EKb_i+}moSXq)2y+omizdtY6rQ!%Ol%7~fL;VjV#t=c!!HEy7&#Du z8CzjpGsJs21`YLIwvsgyQ!HDfnY@R(+%}H5UI;4l7|Ybqy|{4hvUJp?*KdoshM`3; zK$E^MvSmHF#hjRA;eIQpP1}#Gmh1AwXYr+|B*89B@@j^JDEvD5`oznIDXtt$&-b)F zIuCn;1Zisex4+)giQP&p zcz)tVxJhrf1vtjN&3O|ci#1a;x-adA*}_9S{Sq)Qd6fnpl05Yn%Kv18nVR&H63{!e zBn`yvUS7;Rx&_lw(VbGQIw9#d;>NZ@ddhS4Y0tBFj^fLkm z@JPOdo$*fcfL|k5hNU&9tPI`^s2wlc0VB#o$YMGXV0+D@Bjq~uXm`E4A*rPrq^cur zW3$Dgoz;UvEJ@I{r8av0s@1VUe}|(054$mks%5Hp;~B zNLO-9xR#&E4#Zv;<{Vqg27u>2>wjIelj{lltveUpECSL`N-P6Yx4LnE*pFV9(M@2lUBac_9 z37s{N!Fx}pB08p%Nwx`qD6BVa6>UWRg4Q*6_$#JoD`Z7Dy6G8% zm0isEF?wMcKiE$3(4Osgzf5Bx(6(SX{57f&Z>0^>g5l-72*NFPz%UC+Pu=^@EJ2bWy2ouJ2RXmQm$j2W5r zz}T`lJm1lkKK-fh?+upO!O7?*2A{1ch9b726p*K}UIEZ(*o*~X3S^FHTZXZ@E^MUf z+##U(dNm-}0(ZPpOESHL3*H>AJ>{@%B>OG(j%wy#j~|}Z^jVTSq$|Ap=ty*J0uZu> zrY3w2eeF;c0$oCFut}J38*`ST9aR#5G+G`Hj@_1bt>KQ3RzJjlWouB* zyGB3iYWU&uNNvsLVleNO={rf;k*&M}kPrrlZ`$GTbHu4GTL-Z2L#*#Igk$CfCJNP1 zH?;jpNCYW=maX{ab42UmPaKh}3rrcZSPro&$zaJW9JGXChcM$-U`C`X%pYsq zT)2@=+Z0DV9*R=?CRpXNM93^T*xOH?`E|AF%w>>Y-RwEE*ts09D{sxR;fGDBmry29 z>h~&it05aN*X2W#U)_cp8@y&H`rT+v!QUiTK5aWdX1>4EEQgsDT;cWCBz%T7jdV++@aIDprv>=~zo{q%lytJ}m1p=Hp3 z)Sq%xcnp^@;h{2uXANLhKcVrOUola252+s5ZdJzK%-Hv83P0G^ zBpcRM3AleMiR08J?dqotX@oV(?WNuS9$`Ezy-XEWczJRE!nn+uY_p7COUu4@i$jz6 zJ$LY$5r5JggaglOOs3KeFq~_~_8zy7fQ9sNIeNSZh0t3Y>-?yK@=0=Bi{U9#aww%Q`a8WTBL%YRgr>%3KcO3v1Kbk zKv@*o2@zxs6#|losXzqT@?3x-6fCO*0a=qkSQJ9o0tg7QYe+&_LMTGmi4p=55_mz> z`eyn%eSdV`ojZ5t{&UZ{XMXpb?|k?Bz6D2F>NFGc&Ijz48r3%CnHxnb!Cdsqw-J|+ zziemg0i{zJN;jpNiIh%GpxNJ=wQ ztH&+J>&V_n&<+U8V7i6=KAK^Moh_j=u6>T)v&J@#^*BZ1! zqZ2YMk6_hV$L!UHrZ00wRiwq3*b+H05L)M`2^F9^@W{NIU9C9Jj%Jl$YuP~DYiKd` z{Qku*L%qJdXpGCtOy_{%KUV2xGl9l&PvCc1h2|snm>-pZlxvS9!v`)r@BVhH@*X7G zp6c!)yiZXB3-~@xTd6rPDvCXz$N5RX z#=8*VUly0jkXE*~W7<%)$R5|S1z)ahMcOXlnn|+)cm?H$$ca6yR(oDMA-B=P$*W+i zS|5b1u69sZ!C}*2Rq|u9AM$H;1AlRX?kFDw3|hC^Z_=uaRomYemw3EXOPllIb1ZtF zEo7}zdWu|+tg0^?=_f0tB%7eA=bp*+_|T#L)cVJ}6pVCA=eh-@uCgQ~o|mL?4(RXZ z=(Nt%tXN{df^Vf$2;oBJ_p8Vhc^Z~%)@eI;u3O*Ju+mN?O1a6_bc5%fy3fMm{v~RT z_JM(lNVAA9RVoZs8H`C))d4vVmadS1k5iC6&2!ZR`ey(tWw70~ESxvjCW1kA?IUHW z-=YXN8h#qG#S)uRP$UqmU}831aPY2%fYe|ai5>fMXJ8Vnz{{i?()RN#q+nIq_rB({ z0Mn5;C_NT}bv9SYGnJuTUrl0N(-ZF8Zjm<5Fx=QTymb>Eja1tJ1Ic#UDQYwkQuX-aIM|D7B zyEEK!H}v_HRu!`OPkx=~K{oz(+(e1@wgl(=m0vEux@(yY@GJGx)rC(42lgF>!93vfci8a#?VAO`8*E_!s-LZ$*pa_k8=X z`l2NNhkgvv{VuA>LN~)z>!q08EyQo2{blt+Hn{Vu?&~}Os1?&^Vqbn^ZLWV8{f>V1 zDIx~0Gxz*fT=5fv_j?-c`!u)|o|g8&yDl1(#->_D{S=^C@2L zM&Qb%u2_{})5mi?t zG$D4_1H_f5sq!^@i^#Pkvr7sPkp2W<@S|WcDP~37H%EF>jW($`h+Cp9x$o^VEYTP_`Um(dNFo_&4JqMMlfwGazTpu|j%cE)4U-14@75M2zehLuZ{4Q~@ z%R1HNwqME@z2aX%)YjttC&Bk)7oH@I^6@>e9gy~Fw|3Qva<8G^A3oe&2V|TKENS8D z15Y2lQA>dIE-zl+SVe{~7;*lSbEvAHHrzV!H{idAX6@_N2zK6~r%p&#lfS)Hq%UUp zE~ij-O-C>q<1pVU&UQv1JSlQF^KnJ*8Bq4X4t9THkvY6E?>SF@6+jc|#ig{Hrux6d zha1pRHtlk!r{QMSKM0L=_VoA0IunG@SZ9(*;kOP6CMV{J`wk%4G2&VI2c%~Yi&ST5 zS~m;kUnHxnJYQP@FY4i*^sG33XFuO$4{tdHoykkvDw2QADT)i-&cv`#sDzWtrP8=n zQx9gHwR2`Xb#@kPKn#rvcMAj4YV>p4oVBQ`EC5ZYMynZ>^y@Vi5SaV20LkB8?*sBK zu0pic9g$gYK_OS5pvo1$I4g%v z#2s3=S7AnWxf6*Max$;ZO!~WHdn$7+20E741s5CSwYFpT`_qV?I8c`<`EdHC2aZkq z+yf`tZLu}lp3>oJDe|9i39`eZ(?dI+Ze&z%+nw4r^9pbdAXGe!)CH!x#qvw(kI;ZH z5r&I_@u4<7tTeW#-vQdw9~-z6KTpjl^!%QZKL*7xkV1mssZCaIkP#zYr*@|55|rTVc#5pRtTd!T35>bNNy~YYrL^cxxAM4*mTa^BiEs=<8j<`Q~y`5^UT6 zUi@ZjbZP6=ha7G5sD^CoT#M7qK@GxHVWd;c7k_L=$86vF2Bn$ZMQMu2ni5P7;%DCo z;5=p{P~4B`22>d=M9i!Naey5hVs8n%hzgZ?pbC%WSXaHL?pTsDH7_e6lSxnkL6Yo>RB zoFB5x&r-b5V zL4{f5+K<~twHGbjXz0L)$J6f4D~HCP4;7^GQb+PucB1V1Z+leW=gz9~gYRK78o;#V zJ2kKKPs%zit8n8F7Z>}W_k09n51Us_Lpic|!l8rNpmNaEq-ryyuVrhM Date: Tue, 27 Oct 2020 20:48:42 +0800 Subject: [PATCH 189/271] added the methods to calculate food nutrients from food added within a certain time period (2 methods). --- .../seedu/dietbook/calculator/Calculator.java | 146 +++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index b01eddcc6d..9164ae7fce 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -1,10 +1,12 @@ package seedu.dietbook.calculator; import seedu.dietbook.food.Food; +import seedu.dietbook.list.FoodList; import seedu.dietbook.person.Gender; import seedu.dietbook.person.Person; -import java.util.ArrayList; +import java.time.LocalDateTime; +import java.util.List; /** * Represents a calculator of food items in foodList. @@ -21,7 +23,7 @@ public class Calculator { * * @param foodList foodList containing food items to calculate. */ - public Calculator(ArrayList foodList) { + public Calculator(List foodList) { assert foodList != null : "The foodList should not be null."; for (int i = 0; i < foodList.size(); i++) { @@ -43,6 +45,41 @@ public int calculateCalorie() { return totalCalorie; } + /** + * Returns an int type variable containing the value of total calorie + * of the foods with time after a specific time. + * + * @param startTime the start time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateCalorie(LocalDateTime startTime) { + int calorie = 0; + for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { + calorie += FoodList.getFoodsAfterDateTime(startTime).get(i).getCalorie(); + } + return calorie; + } + + /** + * Returns an int type variable containing the value of total calories + * of the foods with time after a specific time and before a specific time. + * + * @param startTime the start time for food items to be included. + * @param endTime the end time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateCalorie(LocalDateTime startTime, LocalDateTime endTime) { + int calorie = 0; + for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + calorie += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getCalorie(); + } + return calorie; + } + /** * Returns an int type variable containing the value of total carbs. * @@ -52,6 +89,41 @@ public int calculateCarb() { return totalCarbohydrate; } + /** + * Returns an int type variable containing the value of total carbs + * of the foods with time after a specific time. + * + * @param startTime the start time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateCarb(LocalDateTime startTime) { + int carb = 0; + for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { + carb += FoodList.getFoodsAfterDateTime(startTime).get(i).getCarbohydrate(); + } + return carb; + } + + /** + * Returns an int type variable containing the value of total carbs + * of the foods with time after a specific time and before a specific time. + * + * @param startTime the start time for food items to be included. + * @param endTime the end time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateCarb(LocalDateTime startTime, LocalDateTime endTime) { + int carb = 0; + for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + carb += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getCarbohydrate(); + } + return carb; + } + /** * Returns an int type variable containing the value of total protein. * @@ -61,6 +133,41 @@ public int calculateProtein() { return totalProtein; } + /** + * Returns an int type variable containing the value of total protein + * of the foods with time after a specific time. + * + * @param startTime the start time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateProtein(LocalDateTime startTime) { + int protein = 0; + for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { + protein += FoodList.getFoodsAfterDateTime(startTime).get(i).getProtein(); + } + return protein; + } + + /** + * Returns an int type variable containing the value of total protein + * of the foods with time after a specific time and before a specific time. + * + * @param startTime the start time for food items to be included. + * @param endTime the end time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateProtein(LocalDateTime startTime, LocalDateTime endTime) { + int protein = 0; + for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + protein += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getProtein(); + } + return protein; + } + /** * Returns an int type variable containing the value of total fats. * @@ -70,6 +177,41 @@ public int calculateFat() { return totalFat; } + /** + * Returns an int type variable containing the value of total fats + * of the foods with time after a specific time. + * + * @param startTime the start time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateFat(LocalDateTime startTime) { + int fat = 0; + for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { + fat += FoodList.getFoodsAfterDateTime(startTime).get(i).getFats(); + } + return fat; + } + + /** + * Returns an int type variable containing the value of total fats + * of the foods with time after a specific time and before a specific time. + * + * @param startTime the start time for food items to be included. + * @param endTime the end time for food items to be included. + * + * @return the value of total calorie of food items with time after + * startTime in foodList. + */ + public int calculateFat(LocalDateTime startTime, LocalDateTime endTime) { + int fat = 0; + for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + fat += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getFats(); + } + return fat; + } + /** * Returns an int type variable containing the value of recommended daily calorie intake. * It is calculated based on the gender, activity level, age, height, original weight, From ab18fd742de4ee0f8978cf0627549a24691e3980 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 20:49:04 +0800 Subject: [PATCH 190/271] Update features section of the user guide --- docs/UserGuide.md | 73 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index c53bb4592d..545bd8d34e 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -35,13 +35,78 @@ e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` and `add x/1 n/mee` a e.g. `help` is a valid command but `Help` is not.
e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` is valid but `add N/mee x/1` is not. -* Spaces to separate command words, parameters, command word and parameters are important.
-e.g. For `calculate all`, `calculate all` is valid but `calculateall` is not.
+* A single spacing to separate command words, parameters, command word and parameters is required.
+e.g. For `calculate all`, `calculate all` is valid but `calculateall` and `calculate`         `all`is not.
e.g. For `delete INDEX`, `delete 1` is valid if there is a food item with index 1 but`delete1` is not.
e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` is valid but `add n/meex/1` is not.
### Features related to user information +#### Entering username: `name` + +Stores the user's name into DietBook during the initial setup. + +Format: `name YOUR_NAME` + +* The name given must not be empty. +* This command is **only used when setting up DietBook for the first time**. Any subsequent editing of the name can be done using the [editinfo](#Editing user information: `editinfo`) command. + +Example of usage: + +* `name Tom and Jerry`
+* `name Jack` + +Output example for usage example 2: +``` +Hi Jack! +Before we get started, I would like to know about about you so that I can make more +accurate calculations for you :). Therefore, could you please share with me the following: +- Your gender either F for female or M for male or O for others. +- Your age which is a positive integer. +- Your height in cm. +- Your original weight in kg, the weight when you first started using DietBook or you current weight. +- Your current weight in kg. +- Your target weight in kg, or your current weight if that is also your target weight. +- Your activity level, represented by a number from 1 to 5. + 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. + 2 = You engage in some form of light exercise or have a job that requires some physical activity. + 3 = You engage in moderate amount of exercise or have a job that requires moderate physical activity. + 4 = You engage in vigorous exercise or have a physically demanding job. + 5 = You engage in extremely vigorous exercise or have an extremely physically demanding job. + +Please input your details in the following format: + info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT c/CURRENT_WEIGHT t/TARGET_WEIGHT l/ACTIVITY_LEVEL + Example: info g/F a/21 h/165 o/65 c/65 t/55 l/2 +``` + +#### Entering user information : `info` + +Stores the user's personal information into DietBook during the initial setup. + +Format: `info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT c/CURRENT_WEIGHT t/TARGET_WEIGHT l/ACTIVITY_LEVEL` + +* This command is **only used when setting up DietBook for the first time**. Any subsequent editing of user information can be done using the [editinfo](#Editing user information: `editinfo`) command. +* The gender must be either **`M` for male, `F` for female or `O` for others**. +* The age must be a positive integer **between 0 and 150**. +* The height in cm must be a positive integer **between 0 and 300**. +* The original, current and target weight in kg must be a positive integer **between 0 and 500**. +* The activity level must be a positive integer **from 1 to 5, inclusive**. + * 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. + * 2 = You engage in some form of light exercise or have a job that requires some physical activity. + * 3 = You engage in moderate amount of exercise or have a job that requires moderate physical activity. + * 4 = You engage in vigorous exercise or have a physically demanding job. + * 5 = You engage in extremely vigorous exercise or have an extremely physically demanding job. + +Example of usage: + +* `info g/M a/21 h/175 o/85 c/85 t/75 l/2` stores the user's gender, age, height, original, current and target weight as well as the activity level to `male`, `21`, `175`, `85`, `85`, `75` and `You engage in some form of light exercise or have a job that requires some physical activity.` respectively. + +Output example: +``` +Thank you! DietBook has been initialised and you may start by entering any valid commands. +If you require a list of valid commands, you can enter: help +``` + #### Viewing user information: `userinfo` Shows the user information stored in DietBook. @@ -73,8 +138,8 @@ Format: `editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/ * The name must not be empty. * The gender must be either **`M` for male, `F` for female or `O` for others**. * The age must be a positive integer **between 0 and 150**. -* The height must be a positive integer **between 0 and 300**. -* The original, current and target weight must be a positive integer **between 0 and 500**. +* The height in cm must be a positive integer **between 0 and 300**. +* The original, current and target weight in kg must be a positive integer **between 0 and 500**. * The activity level must be a positive integer **from 1 to 5, inclusive**. * 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. * 2 = You engage in some form of light exercise or have a job that requires some physical activity. From 097b0b88bca0b9861692b53874315a840defa6ac Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 20:49:33 +0800 Subject: [PATCH 191/271] Update command summary of the user guide --- docs/UserGuide.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 545bd8d34e..e12bef5916 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -233,5 +233,7 @@ Example of usage: Action | Format, Examples ---- | ---- -userinfo | `userinfo` -editinfo | `[n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/CURRENT_WEIGHT] [t/TARGET_WEIGHT] [l/ACTIVITY_LEVEL]`
e.g.,`editinfo c/75 l/4` +Enter name | **Note**: Used only when setting up DietBook for the first time.
`name YOUR_NAME`
e.g.,`name Jack` +Enter info | **Note**: Used only when setting up DietBook for the first time.
`info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT c/CURRENT_WEIGHT t/TARGET_WEIGHT l/ACTIVITY_LEVEL`
e.g.,`info g/M a/21 h/175 o/85 c/85 t/75 l/2` +View user info | `userinfo` +Edit user info | `editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/CURRENT_WEIGHT] [t/TARGET_WEIGHT] [l/ACTIVITY_LEVEL]`
e.g.,`editinfo c/75 l/4` From 766b291e048dc8eab4b89d570bf543254a4c5936 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 21:05:06 +0800 Subject: [PATCH 192/271] increased accuracy of the calculation by editing the case handling of activityScore. added 2 assertion statements for the initialization of activityScore and requirement. --- .../seedu/dietbook/calculator/Calculator.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index 9164ae7fce..5a45177e08 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -223,7 +223,7 @@ public int calculateFat(LocalDateTime startTime, LocalDateTime endTime) { public int calculateRecomendation(Person person) { double requirement = 0; int recomendation; - double activityScore; + double activityScore = 0; switch (person.getActivityLevel()) { case NONE: activityScore = 1; @@ -247,7 +247,15 @@ public int calculateRecomendation(Person person) { } break; case HIGH: - default: + if (person.getGender() == Gender.MALE) { + activityScore = 1.37; + } else if (person.getGender() == Gender.FEMALE) { + activityScore = 1.36; + } else { + activityScore = 1.365; + } + break; + case EXTREME: if (person.getGender() == Gender.MALE) { activityScore = 1.48; } else if (person.getGender() == Gender.FEMALE) { @@ -256,6 +264,9 @@ public int calculateRecomendation(Person person) { activityScore = 1.465; } break; + default: + assert activityScore != 0 : "The activityScore should not be 0 if" + + "the activityLevel are one of five given cases."; } switch (person.getGender()) { @@ -267,9 +278,13 @@ public int calculateRecomendation(Person person) { requirement = 354 - 6.91 * person.getAge() + 9.36 * activityScore * person.getOriginalWeight() + 726 * person.getHeight() / 100; break; - default: + case OTHERS: requirement = 508 - 8.22 * person.getAge() + 12.635 * activityScore * person.getOriginalWeight() + 632.8 * person.getHeight() / 100; + break; + default: + assert requirement != 0 : "The requirement should not be 0 if the gender is " + + "ont of the three given cases."; } if (person.getOriginalWeight() > person.getTargetWeight()) { From a82772f7ddcc05b5f02a3b6532a0a8efd187b28f Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 21:43:45 +0800 Subject: [PATCH 193/271] changed from using original weight to calculate recommended daily calorie intake. --- src/main/java/seedu/dietbook/calculator/Calculator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index 5a45177e08..79ad349f60 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -287,7 +287,7 @@ public int calculateRecomendation(Person person) { + "ont of the three given cases."; } - if (person.getOriginalWeight() > person.getTargetWeight()) { + if (person.getCurrentWeight() > person.getTargetWeight()) { recomendation = (int) requirement - 300; } else { recomendation = (int) requirement + 100; From e6a6a998ab1ea025de976619d65a8cb19fb263dc Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 21:47:38 +0800 Subject: [PATCH 194/271] implement PersonSaveLoadManager allows saving and loading --- .../java/seedu/{duke => dietbook}/Duke.java | 2 +- .../{duke => dietbook}/database/Canteen.java | 2 +- .../{duke => dietbook}/database/DataBase.java | 4 +- .../{duke => dietbook}/database/Store.java | 5 +- .../{duke => dietbook}/database/data.txt | 0 .../seedu/{duke => dietbook}/food/Food.java | 2 +- .../saveload/EmptyLoader.java | 2 +- .../saveload/FileLoader.java | 2 +- .../saveload/FoodSaveLoadManager.java | 4 +- .../{duke => dietbook}/saveload/Loader.java | 2 +- .../saveload/PersonSaveLoadManager.java | 184 ++++++++++++++++++ .../{duke => dietbook}/saveload/Saver.java | 9 +- .../seedu/{duke => dietbook}/DukeTest.java | 2 +- .../database/DataBaseTest.java | 2 +- .../seedu/{duke => dietbook}/food/Food.java | 2 +- .../{duke => dietbook}/food/FoodTest.java | 4 +- .../FoodSaveLoadManagerManualTest.java | 4 +- .../saveload/FoodSaveLoadManagerTest.java | 4 +- .../saveload/SaveLoadFileTest.java | 2 +- .../saveload/SaverTest.java | 2 +- 20 files changed, 214 insertions(+), 26 deletions(-) rename src/main/java/seedu/{duke => dietbook}/Duke.java (96%) rename src/main/java/seedu/{duke => dietbook}/database/Canteen.java (94%) rename src/main/java/seedu/{duke => dietbook}/database/DataBase.java (99%) rename src/main/java/seedu/{duke => dietbook}/database/Store.java (89%) rename src/main/java/seedu/{duke => dietbook}/database/data.txt (100%) rename src/main/java/seedu/{duke => dietbook}/food/Food.java (97%) rename src/main/java/seedu/{duke => dietbook}/saveload/EmptyLoader.java (95%) rename src/main/java/seedu/{duke => dietbook}/saveload/FileLoader.java (98%) rename src/main/java/seedu/{duke => dietbook}/saveload/FoodSaveLoadManager.java (97%) rename src/main/java/seedu/{duke => dietbook}/saveload/Loader.java (94%) create mode 100644 src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java rename src/main/java/seedu/{duke => dietbook}/saveload/Saver.java (97%) rename src/test/java/seedu/{duke => dietbook}/DukeTest.java (88%) rename src/test/java/seedu/{duke => dietbook}/database/DataBaseTest.java (99%) rename src/test/java/seedu/{duke => dietbook}/food/Food.java (97%) rename src/test/java/seedu/{duke => dietbook}/food/FoodTest.java (75%) rename src/test/java/seedu/{duke => dietbook}/saveload/FoodSaveLoadManagerManualTest.java (94%) rename src/test/java/seedu/{duke => dietbook}/saveload/FoodSaveLoadManagerTest.java (96%) rename src/test/java/seedu/{duke => dietbook}/saveload/SaveLoadFileTest.java (96%) rename src/test/java/seedu/{duke => dietbook}/saveload/SaverTest.java (97%) diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/dietbook/Duke.java similarity index 96% rename from src/main/java/seedu/duke/Duke.java rename to src/main/java/seedu/dietbook/Duke.java index 5c74e68d59..e2af504b4b 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/dietbook/Duke.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.dietbook; import java.util.Scanner; diff --git a/src/main/java/seedu/duke/database/Canteen.java b/src/main/java/seedu/dietbook/database/Canteen.java similarity index 94% rename from src/main/java/seedu/duke/database/Canteen.java rename to src/main/java/seedu/dietbook/database/Canteen.java index 1243b0d9be..51946e60a8 100644 --- a/src/main/java/seedu/duke/database/Canteen.java +++ b/src/main/java/seedu/dietbook/database/Canteen.java @@ -1,4 +1,4 @@ -package seedu.duke.database; +package seedu.dietbook.database; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java similarity index 99% rename from src/main/java/seedu/duke/database/DataBase.java rename to src/main/java/seedu/dietbook/database/DataBase.java index 74672a54ef..e9956f563e 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -1,7 +1,7 @@ -package seedu.duke.database; +package seedu.dietbook.database; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.io.File; import java.io.FileNotFoundException; diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/dietbook/database/Store.java similarity index 89% rename from src/main/java/seedu/duke/database/Store.java rename to src/main/java/seedu/dietbook/database/Store.java index af311ae856..63ff2fa3fa 100644 --- a/src/main/java/seedu/duke/database/Store.java +++ b/src/main/java/seedu/dietbook/database/Store.java @@ -1,9 +1,8 @@ -package seedu.duke.database; +package seedu.dietbook.database; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; public class Store { diff --git a/src/main/java/seedu/duke/database/data.txt b/src/main/java/seedu/dietbook/database/data.txt similarity index 100% rename from src/main/java/seedu/duke/database/data.txt rename to src/main/java/seedu/dietbook/database/data.txt diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/dietbook/food/Food.java similarity index 97% rename from src/main/java/seedu/duke/food/Food.java rename to src/main/java/seedu/dietbook/food/Food.java index c43d8f0384..a2d7027f61 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/dietbook/food/Food.java @@ -1,4 +1,4 @@ -package seedu.duke.food; +package seedu.dietbook.food; public class Food { diff --git a/src/main/java/seedu/duke/saveload/EmptyLoader.java b/src/main/java/seedu/dietbook/saveload/EmptyLoader.java similarity index 95% rename from src/main/java/seedu/duke/saveload/EmptyLoader.java rename to src/main/java/seedu/dietbook/saveload/EmptyLoader.java index 96e1f82240..d5c701bcb3 100644 --- a/src/main/java/seedu/duke/saveload/EmptyLoader.java +++ b/src/main/java/seedu/dietbook/saveload/EmptyLoader.java @@ -1,4 +1,4 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; import java.util.Optional; diff --git a/src/main/java/seedu/duke/saveload/FileLoader.java b/src/main/java/seedu/dietbook/saveload/FileLoader.java similarity index 98% rename from src/main/java/seedu/duke/saveload/FileLoader.java rename to src/main/java/seedu/dietbook/saveload/FileLoader.java index 70e20b7c72..9169e4df53 100644 --- a/src/main/java/seedu/duke/saveload/FileLoader.java +++ b/src/main/java/seedu/dietbook/saveload/FileLoader.java @@ -1,4 +1,4 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; import java.io.File; import java.io.FileNotFoundException; diff --git a/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java b/src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java similarity index 97% rename from src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java rename to src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java index 6e070a7893..0d56dc1df0 100644 --- a/src/main/java/seedu/duke/saveload/FoodSaveLoadManager.java +++ b/src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java @@ -1,6 +1,6 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.io.FileNotFoundException; import java.util.ArrayList; diff --git a/src/main/java/seedu/duke/saveload/Loader.java b/src/main/java/seedu/dietbook/saveload/Loader.java similarity index 94% rename from src/main/java/seedu/duke/saveload/Loader.java rename to src/main/java/seedu/dietbook/saveload/Loader.java index 076a5e7112..912431166e 100644 --- a/src/main/java/seedu/duke/saveload/Loader.java +++ b/src/main/java/seedu/dietbook/saveload/Loader.java @@ -1,4 +1,4 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; import java.io.FileNotFoundException; import java.util.Optional; diff --git a/src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java b/src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java new file mode 100644 index 0000000000..d0650997f8 --- /dev/null +++ b/src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java @@ -0,0 +1,184 @@ +package seedu.dietbook.saveload; + +import java.io.FileNotFoundException; + +/** + * This class is responsible for saving and loading personal information. + * It has setters and getters for the following fields : + * name, gender, age, height, original weight, current weight, target weight, activity level + * it has a method load which loads from a specified saved file + * it has a method save which saves the current information to a specified file name + */ +public class PersonSaveLoadManager { + private static final int NUM_OF_ENTRIES = 8; + private static final int TABLE_HEIGHT = 1; + private static final int PERSON_DATA_ROW = 1; + private static final String PERSON_FOLDER_NAME = "PERSONA_IS_NO_SUCH_PERSOOSOOSNSNSNS"; + + private static final int NAME_ENTRY_INDEX = 1; + private static final int GENDER_ENTRY_INDEX = 2; + private static final int AGE_ENTRY_INDEX = 3; + private static final int HEIGHT_ENTRY_INDEX = 4; + private static final int ORIGINAL_WEIGHT_ENTRY_INDEX = 5; + private static final int CURRENT_WEIGHT_ENTRY_INDEX = 6; + private static final int TARGET_WEIGHT_ENTRY_INDEX = 7; + private static final int ACTIVITY_LEVEL_ENTRY_INDEX = 8; + + private static final String DEFAULT_NAME = "Missing Name"; + private static final String DEFAULT_GENDER = "Others"; + private static final int DEFAULT_AGE = 0; + private static final int DEFAULT_HEIGHT = 0; + private static final int DEFAULT_ORIGINAL_WEIGHT = 0; + private static final int DEFAULT_CURRENT_WEIGHT = 0; + private static final int DEFAULT_TARGET_WEIGHT = 0; + private static final int DEFAULT_ACTIVITY_LEVEL = 0; + + private String name; + private String gender; + private int age; + private int height; + private int originalWeight; + private int currentWeight; + private int targetWeight; + private int activityLevel; + + private Saver saver; + private Loader fileLoader; + + public PersonSaveLoadManager() { + this.saver = new Saver(NUM_OF_ENTRIES, TABLE_HEIGHT); + this.fileLoader = Loader.loadEmpty(); + + this.name = DEFAULT_NAME; + this.gender = DEFAULT_GENDER; + this.age = DEFAULT_AGE; + this.height = DEFAULT_HEIGHT; + this.originalWeight = DEFAULT_ORIGINAL_WEIGHT; + this.currentWeight = DEFAULT_CURRENT_WEIGHT; + this.targetWeight = DEFAULT_TARGET_WEIGHT; + this.activityLevel = DEFAULT_ACTIVITY_LEVEL; + } + + /** + * loads a saved file and fill up all the fields with the data from the loaded file. + * set the field to default is the loaded file does not contain the field + * @param fileName name of the saved file to be loaded to + * @throws FileNotFoundException there is no save file with the name + * @throws IllegalAccessException the get method is called when the loader is empty, will never happen with the + * current implementation. + */ + public void load(String fileName) throws FileNotFoundException, IllegalAccessException { + this.reset(); + this.fileLoader = Loader.load(PERSON_FOLDER_NAME, fileName); + this.name = this.fileLoader.get(NAME_ENTRY_INDEX, PERSON_DATA_ROW).orElse(DEFAULT_NAME); + this.gender = this.fileLoader.get(GENDER_ENTRY_INDEX, PERSON_DATA_ROW).orElse(DEFAULT_GENDER); + this.age = Integer.parseInt(this.fileLoader.get(AGE_ENTRY_INDEX, PERSON_DATA_ROW).orElse( + Integer.toString(DEFAULT_AGE))); + this.height = Integer.parseInt(this.fileLoader.get(HEIGHT_ENTRY_INDEX, PERSON_DATA_ROW).orElse( + Integer.toString(DEFAULT_HEIGHT))); + this.originalWeight = Integer.parseInt(this.fileLoader.get(ORIGINAL_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW).orElse( + Integer.toString(DEFAULT_ORIGINAL_WEIGHT))); + this.currentWeight = Integer.parseInt(this.fileLoader.get(CURRENT_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW).orElse( + Integer.toString(DEFAULT_CURRENT_WEIGHT))); + this.targetWeight = Integer.parseInt(this.fileLoader.get(TARGET_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW).orElse( + Integer.toString(DEFAULT_TARGET_WEIGHT))); + this.activityLevel = Integer.parseInt(this.fileLoader.get(ACTIVITY_LEVEL_ENTRY_INDEX, PERSON_DATA_ROW).orElse( + Integer.toString(DEFAULT_ACTIVITY_LEVEL))); + + } + + /** + * Method saves the current data stored in the fields to the specified file name. + * Will over-write files with the same name. + * @param fileName name of the file to save to + */ + public void save(String fileName) { + this.saver.reset(); + this.saver.add(this.name, NAME_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(this.gender, GENDER_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(Integer.toString(this.age), AGE_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(Integer.toString(this.height), HEIGHT_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(Integer.toString(this.originalWeight), ORIGINAL_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(Integer.toString(this.currentWeight), CURRENT_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(Integer.toString(this.targetWeight), TARGET_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(Integer.toString(this.currentWeight), ACTIVITY_LEVEL_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.save(PERSON_FOLDER_NAME, fileName); + } + + public void reset() { + this.fileLoader = Loader.loadEmpty(); + this.name = DEFAULT_NAME; + this.gender = DEFAULT_GENDER; + this.age = DEFAULT_AGE; + this.height = DEFAULT_HEIGHT; + this.originalWeight = DEFAULT_ORIGINAL_WEIGHT; + this.currentWeight = DEFAULT_CURRENT_WEIGHT; + this.targetWeight = DEFAULT_TARGET_WEIGHT; + this.activityLevel = DEFAULT_ACTIVITY_LEVEL; + } + + // ----- Setters and Getters ------ + public String getName() { + return name; + } + + public String getGender() { + return gender; + } + + public int getAge() { + return age; + } + + public int getHeight() { + return height; + } + + public int getOriginalWeight() { + return originalWeight; + } + + public int getCurrentWeight() { + return currentWeight; + } + + public int getTargetWeight() { + return targetWeight; + } + + public int getActivityLevel() { + return activityLevel; + } + + public void setName(String name) { + this.name = name; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public void setAge(int age) { + this.age = age; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setOriginalWeight(int originalWeight) { + this.originalWeight = originalWeight; + } + + public void setCurrentWeight(int currentWeight) { + this.currentWeight = currentWeight; + } + + public void setTargetWeight(int targetWeight) { + this.targetWeight = targetWeight; + } + + public void setActivityLevel(int activityLevel) { + this.activityLevel = activityLevel; + } +} diff --git a/src/main/java/seedu/duke/saveload/Saver.java b/src/main/java/seedu/dietbook/saveload/Saver.java similarity index 97% rename from src/main/java/seedu/duke/saveload/Saver.java rename to src/main/java/seedu/dietbook/saveload/Saver.java index 8c2f5075ef..b8c08f3c65 100644 --- a/src/main/java/seedu/duke/saveload/Saver.java +++ b/src/main/java/seedu/dietbook/saveload/Saver.java @@ -1,4 +1,4 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; import java.io.File; import java.io.FileWriter; @@ -63,6 +63,13 @@ public void resetSize(int newWidth, int newHeight) { initEntries(); } + /** + * Clears the entire table. + */ + public void reset() { + initEntries(); + } + /** * Adds the string provided to the position x,y on the table. * @param entry the entry to be provided into this position diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/dietbook/DukeTest.java similarity index 88% rename from src/test/java/seedu/duke/DukeTest.java rename to src/test/java/seedu/dietbook/DukeTest.java index 2dda5fd651..eef4b4c86a 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/dietbook/DukeTest.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.dietbook; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/seedu/duke/database/DataBaseTest.java b/src/test/java/seedu/dietbook/database/DataBaseTest.java similarity index 99% rename from src/test/java/seedu/duke/database/DataBaseTest.java rename to src/test/java/seedu/dietbook/database/DataBaseTest.java index 116b4192bc..34a097a274 100644 --- a/src/test/java/seedu/duke/database/DataBaseTest.java +++ b/src/test/java/seedu/dietbook/database/DataBaseTest.java @@ -1,4 +1,4 @@ -package seedu.duke.database; +package seedu.dietbook.database; import java.io.FileNotFoundException; import java.util.NoSuchElementException; diff --git a/src/test/java/seedu/duke/food/Food.java b/src/test/java/seedu/dietbook/food/Food.java similarity index 97% rename from src/test/java/seedu/duke/food/Food.java rename to src/test/java/seedu/dietbook/food/Food.java index c43d8f0384..a2d7027f61 100644 --- a/src/test/java/seedu/duke/food/Food.java +++ b/src/test/java/seedu/dietbook/food/Food.java @@ -1,4 +1,4 @@ -package seedu.duke.food; +package seedu.dietbook.food; public class Food { diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/dietbook/food/FoodTest.java similarity index 75% rename from src/test/java/seedu/duke/food/FoodTest.java rename to src/test/java/seedu/dietbook/food/FoodTest.java index 97b646a032..d423c7f1d0 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/dietbook/food/FoodTest.java @@ -1,6 +1,4 @@ -package seedu.duke.food; - -import org.junit.jupiter.api.Test; +package seedu.dietbook.food; class FoodTest { diff --git a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java b/src/test/java/seedu/dietbook/saveload/FoodSaveLoadManagerManualTest.java similarity index 94% rename from src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java rename to src/test/java/seedu/dietbook/saveload/FoodSaveLoadManagerManualTest.java index 4f07f241f0..e9f70ce87e 100644 --- a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerManualTest.java +++ b/src/test/java/seedu/dietbook/saveload/FoodSaveLoadManagerManualTest.java @@ -1,6 +1,6 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.io.FileNotFoundException; import java.util.ArrayList; diff --git a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java b/src/test/java/seedu/dietbook/saveload/FoodSaveLoadManagerTest.java similarity index 96% rename from src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java rename to src/test/java/seedu/dietbook/saveload/FoodSaveLoadManagerTest.java index e286b9bb45..5e885fe969 100644 --- a/src/test/java/seedu/duke/saveload/FoodSaveLoadManagerTest.java +++ b/src/test/java/seedu/dietbook/saveload/FoodSaveLoadManagerTest.java @@ -1,8 +1,8 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java b/src/test/java/seedu/dietbook/saveload/SaveLoadFileTest.java similarity index 96% rename from src/test/java/seedu/duke/saveload/SaveLoadFileTest.java rename to src/test/java/seedu/dietbook/saveload/SaveLoadFileTest.java index 1b09acfb81..26f2d7d5de 100644 --- a/src/test/java/seedu/duke/saveload/SaveLoadFileTest.java +++ b/src/test/java/seedu/dietbook/saveload/SaveLoadFileTest.java @@ -1,4 +1,4 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; import java.io.FileNotFoundException; diff --git a/src/test/java/seedu/duke/saveload/SaverTest.java b/src/test/java/seedu/dietbook/saveload/SaverTest.java similarity index 97% rename from src/test/java/seedu/duke/saveload/SaverTest.java rename to src/test/java/seedu/dietbook/saveload/SaverTest.java index 9fbe56e768..ac6d960142 100644 --- a/src/test/java/seedu/duke/saveload/SaverTest.java +++ b/src/test/java/seedu/dietbook/saveload/SaverTest.java @@ -1,4 +1,4 @@ -package seedu.duke.saveload; +package seedu.dietbook.saveload; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 2bb79bede802e9ac56ca2b58a9cbb76255190000 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 21:50:29 +0800 Subject: [PATCH 195/271] automatically changes. --- src/main/java/seedu/dietbook/DietBook.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/DietBook.java b/src/main/java/seedu/dietbook/DietBook.java index 24128b4a51..f1ed8f95cb 100644 --- a/src/main/java/seedu/dietbook/DietBook.java +++ b/src/main/java/seedu/dietbook/DietBook.java @@ -1,10 +1,10 @@ package seedu.dietbook; -import java.io.FileNotFoundException; -import java.io.IOException; import seedu.dietbook.database.DataBase; import seedu.dietbook.list.FoodList; +import java.io.FileNotFoundException; + public class DietBook { private FoodList foodList; private Ui ui; From f5695d95e30fd1c4534da760c90721c705dd3da9 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 21:57:11 +0800 Subject: [PATCH 196/271] Remove magic numbers --- .../java/seedu/dietbook/person/Person.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/dietbook/person/Person.java b/src/main/java/seedu/dietbook/person/Person.java index 6fd3f52ebb..da30de95a0 100644 --- a/src/main/java/seedu/dietbook/person/Person.java +++ b/src/main/java/seedu/dietbook/person/Person.java @@ -288,8 +288,10 @@ private void performAssertionsForActivityLevel(ActivityLevel activityLevel) { * @param weightType A string describing whether the weight given the original, current or target weight. */ private void performAssertionsForWeight(int weight, String weightType) { - assert weight > 0 : weightType + " of person should be greater than 0"; - assert weight < 500 : weightType + " of person should less than 500"; + int minWeight = 1; + assert weight >= minWeight : weightType + " of person should be greater than 0"; + int maxWeight = 500; + assert weight < maxWeight : weightType + " of person should less than 500"; } /** @@ -298,8 +300,10 @@ private void performAssertionsForWeight(int weight, String weightType) { * @param height The height of the person. */ private void performAssertionsForHeight(int height) { - assert height > 0 : "Height of person should be greater than 0"; - assert height < 300 : "Height of person should be less than 300"; + int minHeight = 1; + assert height >= minHeight : "Height of person should be greater than 0"; + int maxHeight = 300; + assert height < maxHeight : "Height of person should be less than 300"; } /** @@ -327,7 +331,9 @@ private void performAssertionsForNameInput(String name) { * @param age The age of the person. */ private void performAssertionsForAgeInput(int age) { - assert age > 0 : "The age of person should be greater than 0"; - assert age < 150 : "The age of person should be lesser than 150"; + int minAge = 1; + assert age >= minAge : "The age of person should be greater than 0"; + int maxAge = 150; + assert age < maxAge : "The age of person should be lesser than 150"; } } From bffeea849f6ef7fc1678d4f669fb73f4203e8650 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 22:00:04 +0800 Subject: [PATCH 197/271] Update minimum acceptable height and weight --- src/main/java/seedu/dietbook/checker/InputChecker.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index c5ad3a2ab8..b521fcaf0f 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -172,8 +172,8 @@ public static void checkAgeLimit(int age) throws DietException { * @throws DietException when value is not within the limit. */ public static void checkHeightLimit(int height) throws DietException { - if (height < 0) { - throw new DietException("Input value cannot be less than 0!"); + if (height < 1) { + throw new DietException("Input value cannot be less than 1"); } else if (height > HEIGHT_CAP) { throw new DietException("Input value cannot be more than 273!"); } @@ -186,8 +186,8 @@ public static void checkHeightLimit(int height) throws DietException { * @throws DietException when value is not within the limit. */ public static void checkWeightLimit(int weight) throws DietException { - if (weight < 0) { - throw new DietException("Input value cannot be less than 0!"); + if (weight < 1) { + throw new DietException("Input value cannot be less than 1!"); } else if (weight > WEIGHT_CAP) { throw new DietException("Input value cannot be more than 443!"); } From b1c23eca395e0ea1201593ab91bf1144a2e320c6 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 22:00:35 +0800 Subject: [PATCH 198/271] Change minimum age to zero --- src/main/java/seedu/dietbook/person/Person.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/person/Person.java b/src/main/java/seedu/dietbook/person/Person.java index da30de95a0..a257ff8ba3 100644 --- a/src/main/java/seedu/dietbook/person/Person.java +++ b/src/main/java/seedu/dietbook/person/Person.java @@ -331,8 +331,8 @@ private void performAssertionsForNameInput(String name) { * @param age The age of the person. */ private void performAssertionsForAgeInput(int age) { - int minAge = 1; - assert age >= minAge : "The age of person should be greater than 0"; + int minAge = 0; + assert age >= minAge : "The age of person should be equals to or greater than 0"; int maxAge = 150; assert age < maxAge : "The age of person should be lesser than 150"; } From 665480bcf2f4d3ac283f8c734c8155d9ed6585e9 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 22:06:23 +0800 Subject: [PATCH 199/271] Update assertions --- src/main/java/seedu/dietbook/person/Person.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/person/Person.java b/src/main/java/seedu/dietbook/person/Person.java index a257ff8ba3..a0e02c7e6b 100644 --- a/src/main/java/seedu/dietbook/person/Person.java +++ b/src/main/java/seedu/dietbook/person/Person.java @@ -291,7 +291,7 @@ private void performAssertionsForWeight(int weight, String weightType) { int minWeight = 1; assert weight >= minWeight : weightType + " of person should be greater than 0"; int maxWeight = 500; - assert weight < maxWeight : weightType + " of person should less than 500"; + assert weight <= maxWeight : weightType + " of person should less than 500"; } /** @@ -303,7 +303,7 @@ private void performAssertionsForHeight(int height) { int minHeight = 1; assert height >= minHeight : "Height of person should be greater than 0"; int maxHeight = 300; - assert height < maxHeight : "Height of person should be less than 300"; + assert height <= maxHeight : "Height of person should be less than 300"; } /** @@ -334,6 +334,6 @@ private void performAssertionsForAgeInput(int age) { int minAge = 0; assert age >= minAge : "The age of person should be equals to or greater than 0"; int maxAge = 150; - assert age < maxAge : "The age of person should be lesser than 150"; + assert age <= maxAge : "The age of person should be lesser than 150"; } } From 9979d41bcaf99e38fce58cd8fa962980538d9eda Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:12:59 +0800 Subject: [PATCH 200/271] add Junit test --- .../saveload/PersonSaveLoadManagerTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java diff --git a/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java b/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java new file mode 100644 index 0000000000..bad761d44e --- /dev/null +++ b/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java @@ -0,0 +1,21 @@ +package seedu.dietbook.saveload; + +import org.junit.jupiter.api.BeforeEach; + +import static org.junit.jupiter.api.Assertions.*; + +class PersonSaveLoadManagerTest { + private static PersonSaveLoadManager pslTest; + + @BeforeEach + private void setUp(){ + pslTest = new PersonSaveLoadManager(); + pslTest.setName("Victor Chng"); + pslTest.setActivityLevel(0); + pslTest.setGender("UnKnown"); + pslTest.setAge(100); + pslTest.setOriginalWeight(200); + pslTest.setCurrentWeight(300); + pslTest.setTargetWeight(100); + } +} \ No newline at end of file From 12ce0a3de87eb65abd2503167903a6a0fa3aa213 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 22:14:25 +0800 Subject: [PATCH 201/271] Update acceptable values for some parameters --- docs/UserGuide.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index e12bef5916..f5988acfa2 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -87,9 +87,9 @@ Format: `info g/GENDER a/AGE h/HEIGHT o/ORIGINAL_WEIGHT c/CURRENT_WEIGHT t/TARGE * This command is **only used when setting up DietBook for the first time**. Any subsequent editing of user information can be done using the [editinfo](#Editing user information: `editinfo`) command. * The gender must be either **`M` for male, `F` for female or `O` for others**. -* The age must be a positive integer **between 0 and 150**. -* The height in cm must be a positive integer **between 0 and 300**. -* The original, current and target weight in kg must be a positive integer **between 0 and 500**. +* The age must be a positive integer **from 0 to 150, inclusive**. +* The height in cm must be a positive integer **from 1 to 300, inclusive**. +* The original, current and target weight in kg must be a positive integer ***from 1 to 500, inclusive**. * The activity level must be a positive integer **from 1 to 5, inclusive**. * 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. * 2 = You engage in some form of light exercise or have a job that requires some physical activity. @@ -137,9 +137,9 @@ Format: `editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/ * Existing values will be updated to the input values. * The name must not be empty. * The gender must be either **`M` for male, `F` for female or `O` for others**. -* The age must be a positive integer **between 0 and 150**. -* The height in cm must be a positive integer **between 0 and 300**. -* The original, current and target weight in kg must be a positive integer **between 0 and 500**. +* The age must be a positive integer **from 0 to 150, inclusive**. +* The height must be a positive integer **from 1 to 300, inclusive**. +* The original, current and target weight must be a positive integer **from 1 to 500, inclusive**. * The activity level must be a positive integer **from 1 to 5, inclusive**. * 1 = You hardly engage in any exercise or have a job that requires little to no physical activity. * 2 = You engage in some form of light exercise or have a job that requires some physical activity. From 82d1edf9e736284fe7b04cf4ccc5a3c252342628 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 22:15:09 +0800 Subject: [PATCH 202/271] deleted classes not included in the current main from tp_repo --- .../java/seedu/calculator/Calculator.java | 67 ------ src/main/java/seedu/dietbook/Parser.java | 212 ------------------ .../seedu/dietbook/calculator/Calculator.java | 6 +- 3 files changed, 3 insertions(+), 282 deletions(-) delete mode 100644 src/main/java/seedu/calculator/Calculator.java delete mode 100644 src/main/java/seedu/dietbook/Parser.java diff --git a/src/main/java/seedu/calculator/Calculator.java b/src/main/java/seedu/calculator/Calculator.java deleted file mode 100644 index 44a3b54dc6..0000000000 --- a/src/main/java/seedu/calculator/Calculator.java +++ /dev/null @@ -1,67 +0,0 @@ -package seedu.calculator; - -import seedu.dietbook.food.Food; - -import java.util.ArrayList; - -/** - * Represents a calculator of food items in foodList. - */ -public class Calculator { - private int totalCalorie = 0; - private int totalCarbohydrate = 0; - private int totalProtein = 0; - private int totalFat = 0; - - /** - * Construct a calculator taking in a foodList. Add up calories, - * carbs, protein, and fats in each food item. - * - * @param foodList foodList containing food items to calculate. - */ - public Calculator(ArrayList foodList) { - assert foodList != null : "the foodList should not be null."; - for (int i = 0; i < foodList.size(); i++) { - totalCalorie += foodList.get(i).getCalorie(); - totalCarbohydrate += foodList.get(i).getCarbohydrate(); - totalProtein += foodList.get(i).getProtein(); - totalFat += foodList.get(i).getFat(); - } - } - - /** - * Returns an int type variable containing the value of total calorie. - * - * @return the value of total calorie of food items in foodList. - */ - public int calculateCalorie() { - return totalCalorie; - } - - /** - * Returns an int type variable containing the value of total carbs. - * - * @return the value of total carbs of food items in foodList. - */ - public int calculateCarb() { - return totalCarbohydrate; - } - - /** - * Returns an int type variable containing the value of total protein. - * - * @return the value of total protein of food items in foodList. - */ - public int calculateProtein() { - return totalProtein; - } - - /** - * Returns an int type variable containing the value of total fats. - * - * @return the value of total fats of food items in foodList. - */ - public int calculateFat() { - return totalFat; - } -} diff --git a/src/main/java/seedu/dietbook/Parser.java b/src/main/java/seedu/dietbook/Parser.java deleted file mode 100644 index 2486e212be..0000000000 --- a/src/main/java/seedu/dietbook/Parser.java +++ /dev/null @@ -1,212 +0,0 @@ -package seedu.dietbook; - -import seedu.dietbook.calculator.Calculator; -import seedu.dietbook.list.FoodList; -import seedu.dietbook.person.Gender; -import seedu.dietbook.person.ActivityLevel; - -import java.io.FileNotFoundException; - -public class Parser { - public static final String COMMAND_NAME = "name"; - public static final String COMMAND_LIST = "list"; - public static final String COMMAND_INFO = "info"; - public static final String COMMAND_EXIT = "exit"; - public static final String COMMAND_ADD = "add"; - public static final String COMMAND_CLEAR = "clear"; - public static final String COMMAND_DELETE = "delete"; - public static final String COMMAND_CALCULATE = "calculate"; - public static final String COMMAND_DATA = "data"; - public static final String COMMAND_USERINFO = "userinfo"; - public static final String[] PARAM_CALCULATE = {"fat", "carbohydrate","protein", "calorie", "all"}; - public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/"}; - public static final String[] PARAM_ADD = {"n/","x/","k/","f/","p/","c/"}; - - - /** - * Returns the command of a user input. - * @param userInput which is user input. - * @return First word which is the command of the user input. - */ - private static String getCommand(String userInput) { - return userInput.split(" ")[0]; - } - - /** - * Returns the subsequent parameter after the command from the user input. - * @param userInput user input. - * @return parameter part of the user input. - * @throws DietException when the user input is of a wrong format. - */ - private static String getCommandParam(String userInput) throws DietException { - String command = getCommand(userInput); - String[] input = {userInput}; - - if (userInput.split(command).length < 2 - || userInput.split(command)[1].equals(" ")) { - throw new DietException("☹ Error! Missing command parameters!"); - } else { - switch (command) { - case COMMAND_NAME: - return userInput.split(" ")[1]; - case COMMAND_CALCULATE: - for (String param: PARAM_CALCULATE) { - if (userInput.contains(param)) { - return userInput.split(" ")[1]; - } - } - throw new DietException("☹ Incorrect nutrient type"); - case COMMAND_ADD: - for (String param: PARAM_ADD) { - if (!userInput.contains(param)) { - throw new DietException("☹ Missing or incorrect add statement"); - } - } - return userInput.substring(userInput.indexOf(' ') + 1); - case COMMAND_INFO: - for (String param: PARAM_INFO) { - if (!userInput.contains(param)) { - throw new DietException("☹ Missing or incorrect info statement"); - } - } - return userInput.substring(userInput.indexOf(' ') + 1); - default: - return null; - } - } - } - - /** - * Processes the parameters for add command of user input and adds a Food object. - * @param userInput user input. - * @param foodList the FoodList object. - * @return name of the food that was added. - * @throws DietException when the user input is of a wrong format. - */ - private static String getProcessedAdd(String userInput, FoodList foodList) throws DietException { - String[] processedParam = getCommandParam(userInput).split(" "); - int portionSize = Integer.parseInt(processedParam[0].substring(processedParam[0].indexOf("/") + 1)); - String foodName = processedParam[1].substring(processedParam[1].indexOf("/") + 1); - int calorie = Integer.parseInt(processedParam[2].substring(processedParam[2].indexOf("/") + 1)); - int carb = Integer.parseInt(processedParam[3].substring(processedParam[3].indexOf("/") + 1)); - int protein = Integer.parseInt(processedParam[4].substring(processedParam[4].indexOf("/") + 1)); - int fat = Integer.parseInt(processedParam[5].substring(processedParam[5].indexOf("/") + 1)); - foodList.addFood(portionSize, foodName, calorie, carb, protein, fat); - return foodName; - } - - /** - * Processes the parameters for info command of user input and updates the Person object. - * @param userInput user input. - * @param manager the manager object. - * @throws DietException when the user input is of a wrong format. - */ - private static void executeProcessedInfo(String userInput, Manager manager) throws DietException { - Gender gender; - ActivityLevel actLvl; - String[] processedParam = getCommandParam(userInput).split(" "); - String processGender = processedParam[0].substring(processedParam[0].indexOf("/") + 1); - if (processGender.equals("M")) { - gender = Gender.MALE; - } else { - gender = Gender.FEMALE; - } - int age = Integer.parseInt(processedParam[1].substring(processedParam[1].indexOf("/") + 1)); - int height = Integer.parseInt(processedParam[2].substring(processedParam[2].indexOf("/") + 1)); - int orgWeight = Integer.parseInt(processedParam[3].substring(processedParam[3].indexOf("/") + 1)); - int tarWeight = Integer.parseInt(processedParam[4].substring(processedParam[4].indexOf("/") + 1)); - String processActLvl = processedParam[5].substring(processedParam[5].indexOf("/") + 1); - if (processActLvl.equals("1")) { - actLvl = ActivityLevel.NONE; - } else if (processActLvl.equals("2")) { - actLvl = ActivityLevel.LOW; - } else if (processActLvl.equals("3")) { - actLvl = ActivityLevel.MEDIUM; - } else if (processActLvl.equals("4")) { - actLvl = ActivityLevel.HIGH; - } else { - actLvl = ActivityLevel.EXTREME; - } - manager.setPerson(manager.getName(), gender, age, height, orgWeight, tarWeight, actLvl); - } - - /** - * Returns the index after the command of a user input, e.g. delete 3. - * @param userInput user input. - * @return index part of the user input. - * @throws DietException when the user input is of a wrong format. - */ - private static int getCommandIndex(String userInput) throws DietException { - String command = getCommand(userInput); - - if (userInput.split(command).length < 2 || userInput.split(command)[1].equals(" ")) { - throw new DietException("☹ OOPS!!! Missing index of duke.task!"); - } - try { - return Integer.parseInt(userInput.split(" ")[1]); - } catch (NumberFormatException e) { - throw new DietException("☹ OOPS!!! No integer index detected!"); - } - } - - /** - * Makes sense of the user input and carries out the functions according to the command given. - * @param userInput user input. - * @throws DietException when the program does not recognize the command given. - */ - public static void parse(String userInput, Manager manager, Ui ui) throws DietException, FileNotFoundException { - Calculator calculator = manager.getCalculator(); - switch (getCommand(userInput)) { - case COMMAND_NAME: - manager.setName(getCommandParam(userInput)); - ui.printAskForUserInfoMessage(manager.getName()); - return; - case COMMAND_EXIT: - ui.printExitMessage(manager.getName()); - DietBook.isExit = true; - return; - case COMMAND_LIST: - ui.printFoodList(manager.getFoodList().toString()); - return; - case COMMAND_USERINFO: - ui.printPersonInfo(manager.getPerson().toString()); - return; - case COMMAND_DATA: - manager.getDataBase().init(); - ui.printDatabase(manager.getDataBase().getFoodList()); - return; - case COMMAND_DELETE: - ui.printDeletedFood(manager.getFoodList().delete(getCommandIndex(userInput))); - manager.setCalculator(); - return; - case COMMAND_CLEAR: - ui.printClearFoodListMessage(); - manager.getFoodList().clear(); - return; - case COMMAND_CALCULATE: - if (getCommandParam(userInput).equals("all")) { - ui.printAllNutrientIntake(calculator.calculateCalorie(), calculator.calculateCarb(), - calculator.calculateProtein(), calculator.calculateFat()); - } else if (getCommandParam(userInput).equals("calorie")) { - ui.printCalorieIntake(calculator.calculateCalorie()); - } else if (getCommandParam(userInput).equals("carbohydrate")) { - ui.printCarbohydrateIntake(calculator.calculateCarb()); - } else if (getCommandParam(userInput).equals("protein")) { - ui.printProteinIntake(calculator.calculateProtein()); - } else { - ui.printFatIntake(calculator.calculateFat()); - } - return; - case COMMAND_INFO: - executeProcessedInfo(userInput, manager); - ui.printTutorialMessage(); - return; - case COMMAND_ADD: - ui.printNewFood(getProcessedAdd(userInput, manager.getFoodList())); - manager.setCalculator(); - return; - default: - throw new DietException("☹ There's no such command!"); - } - } -} diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index 79ad349f60..e8304fe278 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -32,7 +32,7 @@ public Calculator(List foodList) { totalCalorie += foodList.get(i).getCalorie(); totalCarbohydrate += foodList.get(i).getCarbohydrate(); totalProtein += foodList.get(i).getProtein(); - totalFat += foodList.get(i).getFats(); + totalFat += foodList.get(i).getFat(); } } @@ -189,7 +189,7 @@ public int calculateFat() { public int calculateFat(LocalDateTime startTime) { int fat = 0; for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { - fat += FoodList.getFoodsAfterDateTime(startTime).get(i).getFats(); + fat += FoodList.getFoodsAfterDateTime(startTime).get(i).getFat(); } return fat; } @@ -207,7 +207,7 @@ public int calculateFat(LocalDateTime startTime) { public int calculateFat(LocalDateTime startTime, LocalDateTime endTime) { int fat = 0; for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { - fat += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getFats(); + fat += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getFat(); } return fat; } From b43b1acac52a7bce2d789ea8d31d221a57746b55 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:17:01 +0800 Subject: [PATCH 203/271] no message --- src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java | 2 +- src/test/java/seedu/dietbook/food/Food.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java b/src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java index 0d56dc1df0..c866437c4a 100644 --- a/src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java +++ b/src/main/java/seedu/dietbook/saveload/FoodSaveLoadManager.java @@ -71,7 +71,7 @@ public void save(String fileName, List foodlist) { saver.add(Integer.toString(foodlist.get(j - 1).getCalorie()), 2, j); saver.add(Integer.toString(foodlist.get(j - 1).getCarbohydrate()), 3, j); saver.add(Integer.toString(foodlist.get(j - 1).getProtein()), 4, j); - saver.add(Integer.toString(foodlist.get(j - 1).getFats()), 5, j); + saver.add(Integer.toString(foodlist.get(j - 1).getFat()), 5, j); } saver.save(FOOD_FOLDER_NAME, fileName); } diff --git a/src/test/java/seedu/dietbook/food/Food.java b/src/test/java/seedu/dietbook/food/Food.java index a2d7027f61..505588e82b 100644 --- a/src/test/java/seedu/dietbook/food/Food.java +++ b/src/test/java/seedu/dietbook/food/Food.java @@ -16,7 +16,7 @@ public Food(String name, int calorie, int carbohydrate, int protein, int fats) { this.fats = fats; } - public int getFats() { + public int getFat() { return fats; } From 4efc2637e2e82c296445967a74c9b0eb1cfe0023 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:19:18 +0800 Subject: [PATCH 204/271] change directory --- src/main/java/seedu/{duke => dietbook}/Duke.java | 2 +- src/main/java/seedu/{duke => dietbook}/database/Canteen.java | 2 +- .../java/seedu/{duke => dietbook}/database/DataBase.java | 4 ++-- src/main/java/seedu/{duke => dietbook}/database/Store.java | 5 ++--- src/main/java/seedu/{duke => dietbook}/database/data.txt | 0 src/main/java/seedu/{duke => dietbook}/food/Food.java | 2 +- src/test/java/seedu/{duke => dietbook}/DukeTest.java | 2 +- .../java/seedu/{duke => dietbook}/database/DataBaseTest.java | 2 +- src/test/java/seedu/{duke => dietbook}/food/FoodTest.java | 4 +--- 9 files changed, 10 insertions(+), 13 deletions(-) rename src/main/java/seedu/{duke => dietbook}/Duke.java (96%) rename src/main/java/seedu/{duke => dietbook}/database/Canteen.java (94%) rename src/main/java/seedu/{duke => dietbook}/database/DataBase.java (99%) rename src/main/java/seedu/{duke => dietbook}/database/Store.java (89%) rename src/main/java/seedu/{duke => dietbook}/database/data.txt (100%) rename src/main/java/seedu/{duke => dietbook}/food/Food.java (97%) rename src/test/java/seedu/{duke => dietbook}/DukeTest.java (88%) rename src/test/java/seedu/{duke => dietbook}/database/DataBaseTest.java (99%) rename src/test/java/seedu/{duke => dietbook}/food/FoodTest.java (75%) diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/dietbook/Duke.java similarity index 96% rename from src/main/java/seedu/duke/Duke.java rename to src/main/java/seedu/dietbook/Duke.java index 5c74e68d59..e2af504b4b 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/dietbook/Duke.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.dietbook; import java.util.Scanner; diff --git a/src/main/java/seedu/duke/database/Canteen.java b/src/main/java/seedu/dietbook/database/Canteen.java similarity index 94% rename from src/main/java/seedu/duke/database/Canteen.java rename to src/main/java/seedu/dietbook/database/Canteen.java index 1243b0d9be..51946e60a8 100644 --- a/src/main/java/seedu/duke/database/Canteen.java +++ b/src/main/java/seedu/dietbook/database/Canteen.java @@ -1,4 +1,4 @@ -package seedu.duke.database; +package seedu.dietbook.database; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/seedu/duke/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java similarity index 99% rename from src/main/java/seedu/duke/database/DataBase.java rename to src/main/java/seedu/dietbook/database/DataBase.java index 74672a54ef..e9956f563e 100644 --- a/src/main/java/seedu/duke/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -1,7 +1,7 @@ -package seedu.duke.database; +package seedu.dietbook.database; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.io.File; import java.io.FileNotFoundException; diff --git a/src/main/java/seedu/duke/database/Store.java b/src/main/java/seedu/dietbook/database/Store.java similarity index 89% rename from src/main/java/seedu/duke/database/Store.java rename to src/main/java/seedu/dietbook/database/Store.java index af311ae856..63ff2fa3fa 100644 --- a/src/main/java/seedu/duke/database/Store.java +++ b/src/main/java/seedu/dietbook/database/Store.java @@ -1,9 +1,8 @@ -package seedu.duke.database; +package seedu.dietbook.database; -import seedu.duke.food.Food; +import seedu.dietbook.food.Food; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; public class Store { diff --git a/src/main/java/seedu/duke/database/data.txt b/src/main/java/seedu/dietbook/database/data.txt similarity index 100% rename from src/main/java/seedu/duke/database/data.txt rename to src/main/java/seedu/dietbook/database/data.txt diff --git a/src/main/java/seedu/duke/food/Food.java b/src/main/java/seedu/dietbook/food/Food.java similarity index 97% rename from src/main/java/seedu/duke/food/Food.java rename to src/main/java/seedu/dietbook/food/Food.java index c43d8f0384..a2d7027f61 100644 --- a/src/main/java/seedu/duke/food/Food.java +++ b/src/main/java/seedu/dietbook/food/Food.java @@ -1,4 +1,4 @@ -package seedu.duke.food; +package seedu.dietbook.food; public class Food { diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/dietbook/DukeTest.java similarity index 88% rename from src/test/java/seedu/duke/DukeTest.java rename to src/test/java/seedu/dietbook/DukeTest.java index 2dda5fd651..eef4b4c86a 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/dietbook/DukeTest.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.dietbook; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/seedu/duke/database/DataBaseTest.java b/src/test/java/seedu/dietbook/database/DataBaseTest.java similarity index 99% rename from src/test/java/seedu/duke/database/DataBaseTest.java rename to src/test/java/seedu/dietbook/database/DataBaseTest.java index 116b4192bc..34a097a274 100644 --- a/src/test/java/seedu/duke/database/DataBaseTest.java +++ b/src/test/java/seedu/dietbook/database/DataBaseTest.java @@ -1,4 +1,4 @@ -package seedu.duke.database; +package seedu.dietbook.database; import java.io.FileNotFoundException; import java.util.NoSuchElementException; diff --git a/src/test/java/seedu/duke/food/FoodTest.java b/src/test/java/seedu/dietbook/food/FoodTest.java similarity index 75% rename from src/test/java/seedu/duke/food/FoodTest.java rename to src/test/java/seedu/dietbook/food/FoodTest.java index 97b646a032..d423c7f1d0 100644 --- a/src/test/java/seedu/duke/food/FoodTest.java +++ b/src/test/java/seedu/dietbook/food/FoodTest.java @@ -1,6 +1,4 @@ -package seedu.duke.food; - -import org.junit.jupiter.api.Test; +package seedu.dietbook.food; class FoodTest { From 34b46b4c0e0aa556c22cf9b0ce9a50b2a3315cd1 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 22:31:35 +0800 Subject: [PATCH 205/271] resolve static problems --- src/main/java/seedu/dietbook/calculator/Calculator.java | 2 +- src/main/java/seedu/dietbook/list/FoodList.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index 7df6b6b048..e8304fe278 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -207,7 +207,7 @@ public int calculateFat(LocalDateTime startTime) { public int calculateFat(LocalDateTime startTime, LocalDateTime endTime) { int fat = 0; for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { - fat += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getFats(); + fat += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getFat(); } return fat; } diff --git a/src/main/java/seedu/dietbook/list/FoodList.java b/src/main/java/seedu/dietbook/list/FoodList.java index 67ab59ec5e..6ff392d0de 100644 --- a/src/main/java/seedu/dietbook/list/FoodList.java +++ b/src/main/java/seedu/dietbook/list/FoodList.java @@ -1,9 +1,10 @@ package seedu.dietbook.list; +import seedu.dietbook.food.Food; + +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import java.time.LocalDateTime; -import seedu.dietbook.food.Food; /** @@ -12,7 +13,7 @@ * This is a stateful object. */ public class FoodList { - private ArrayList foodEntries; + private static ArrayList foodEntries; /** * Default constructor that instantiates FoodList with an empty foodentry arraylist. @@ -136,7 +137,7 @@ public List getPortionedFoodsAfterDateTime(LocalDateTime dateTime) { /** * Obtain list of foods consumed within the range of a specified timing. */ - public List getFoodsInDateTimeRange(LocalDateTime start, LocalDateTime end) { + public static List getFoodsInDateTimeRange(LocalDateTime start, LocalDateTime end) { List entriesInRange = FoodListManager.filterListByDate(foodEntries, start, end); return FoodListManager.listToFoods(entriesInRange); } From 84c6fe540388de60ae9d5cca8ffa4ddcaacbed43 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:34:24 +0800 Subject: [PATCH 206/271] add retrieval methods for portion and date --- .../java/seedu/dietbook/list/FoodList.java | 16 ++++++++++++ .../seedu/dietbook/list/FoodListManager.java | 25 +++++++++++++++++-- .../seedu/dietbook/list/FoodListTest.java | 7 ++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/list/FoodList.java b/src/main/java/seedu/dietbook/list/FoodList.java index bb646606b3..1b42b9c0a3 100644 --- a/src/main/java/seedu/dietbook/list/FoodList.java +++ b/src/main/java/seedu/dietbook/list/FoodList.java @@ -149,6 +149,22 @@ public List getPortionedFoodsInDateTimeRange(LocalDateTime start, LocalDat return FoodListManager.listToPortionedFoods(entriesInRange); } + /** + * Obtain list of portion sizes. + * (For storage purposes) + */ + public List getPortionSizes() { + return FoodListManager.listToPortionSizes(foodEntries); + } + + /** + * Obtain list of LocalDateTimes for when the entries were made. + * (For storage purposes) + */ + public List getDateTimes() { + return FoodListManager.listToLocalDateTimes(foodEntries); + } + @Override public String toString() { return FoodListManager.listToString(foodEntries); diff --git a/src/main/java/seedu/dietbook/list/FoodListManager.java b/src/main/java/seedu/dietbook/list/FoodListManager.java index 2c35f45dc2..8ef1efb5c0 100644 --- a/src/main/java/seedu/dietbook/list/FoodListManager.java +++ b/src/main/java/seedu/dietbook/list/FoodListManager.java @@ -52,7 +52,7 @@ protected static List listToStrings(List list) { /** * Extracts the list of foods from the foodentries list. * @param list list of foodEntries - * @return arraylist of Food objects. + * @return list of Food objects. */ protected static List listToFoods(List list) { Function function = x -> x.getFood(); @@ -63,7 +63,7 @@ protected static List listToFoods(List list) { * Creates a list of foods that have their nutritional values scaled by portion size. * This is based on the FoodEntries in the list provided. * @param list list of FoodEntries - * @return arraylist of Food objects + * @return list of Food objects */ protected static List listToPortionedFoods(List list) { Function function = x -> { @@ -81,8 +81,29 @@ protected static List listToPortionedFoods(List list) { return ListFunction.applyFunctionToList(list, function); } + /** + * Obtain the LocalDateTime objects associated with each entry. + */ + protected static List listToLocalDateTimes(List list) { + Function function = x -> { + assert (x instanceof DatedFoodEntry) : "A FoodEntry without a date was unexpectedly added and found"; + DatedFoodEntry datedEntry = (DatedFoodEntry) x; + return datedEntry.getDateTime(); + }; + return ListFunction.applyFunctionToList(list, function); + } + + /** + * Obtain the portion sizes associated with each food entry. + */ + protected static List listToPortionSizes(List list) { + Function function = x -> x.getPortionSize(); + return ListFunction.applyFunctionToList(list, function); + } + /** * Obtain only food entries after a specified dateTime. + * @param dateTime the start/"before" datetime for filtering. */ protected static List filterListByDate(List list, LocalDateTime dateTime) { Predicate predicate = x -> { diff --git a/src/test/java/seedu/dietbook/list/FoodListTest.java b/src/test/java/seedu/dietbook/list/FoodListTest.java index 586eb5e811..6ec36eb032 100644 --- a/src/test/java/seedu/dietbook/list/FoodListTest.java +++ b/src/test/java/seedu/dietbook/list/FoodListTest.java @@ -99,4 +99,11 @@ void dateFilterRangeTest() { list.getPortionedFoods().toString()); } + @Test + void getFoodEntryProperties_standardList_FoodEntryProperties() { + assertTrue(list.getDateTimes().get(0) instanceof LocalDateTime); + assertEquals(list.getPortionSizes().get(0), 3); + assertEquals(list.getFoods().get(0), food); + } + } From 0f77f9f06a21b227811976c32cc52ebf0f60a9fe Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 22:39:43 +0800 Subject: [PATCH 207/271] updated with new person format --- src/test/java/seedu/dietbook/calculator/CalculatorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/dietbook/calculator/CalculatorTest.java b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java index ea25a7aa09..bd0d3a5d47 100644 --- a/src/test/java/seedu/dietbook/calculator/CalculatorTest.java +++ b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java @@ -56,8 +56,8 @@ void calculateFat_foodListOfThreeItems_sumOfFat() { @Test void calculateRecomendedCalorieIntake_aPerson_recomendationOfCalorieIntake() { - Person Harry = new Person("Harry", Gender.MALE, 19, 182, 66, 75, ActivityLevel.LOW); - Person Erica = new Person("Erica", Gender.FEMALE, 20, 168, 52, 45, ActivityLevel.MEDIUM); + Person Harry = new Person("Harry", Gender.MALE, 19, 182, 66, 69, 75, ActivityLevel.LOW); + Person Erica = new Person("Erica", Gender.FEMALE, 20, 168, 52, 50, 45, ActivityLevel.MEDIUM); Calculator calculator = new Calculator(new ArrayList()); assertEquals(2728, calculator.calculateRecomendation(Harry)); assertEquals(1752, calculator.calculateRecomendation(Erica)); From 726d0940451811eface846f533618ee2dbb99580 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:43:47 +0800 Subject: [PATCH 208/271] add Junit test for PersonSaveLoadManager --- .../saveload/PersonSaveLoadManagerTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java b/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java index bad761d44e..419cdec53e 100644 --- a/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java +++ b/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java @@ -1,6 +1,9 @@ package seedu.dietbook.saveload; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.FileNotFoundException; import static org.junit.jupiter.api.Assertions.*; @@ -17,5 +20,25 @@ private void setUp(){ pslTest.setOriginalWeight(200); pslTest.setCurrentWeight(300); pslTest.setTargetWeight(100); + pslTest.save("pslTest"); + } + + @Test + private void Load_NoSuchFile_ExpectFileNotFoundException() { + PersonSaveLoadManager localpslTest = new PersonSaveLoadManager(); + assertThrows(FileNotFoundException.class, () -> localpslTest.load("pie die pie")); + } + + @Test + private void Load_CorrectFile_AllContentsCorrect() throws Exception { + PersonSaveLoadManager localpslTest = new PersonSaveLoadManager(); + localpslTest.load("pslTest"); + assertEquals("Victor Chng", localpslTest.getName()); + assertEquals("Unknown", localpslTest.getGender()); + assertEquals(200, localpslTest.getOriginalWeight()); + assertEquals(100, localpslTest.getAge()); + assertEquals(300, localpslTest.getCurrentWeight()); + assertEquals(100, localpslTest.getTargetWeight()); + assertEquals(0, localpslTest.getActivityLevel()); } } \ No newline at end of file From d080a33bc7d8e9f59180de0c9d1afd57df1dd462 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:45:16 +0800 Subject: [PATCH 209/271] fix check style --- src/main/java/seedu/dietbook/database/DataBase.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java index 89b6199de2..9d23267ae1 100644 --- a/src/main/java/seedu/dietbook/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -259,14 +259,14 @@ public List getFoodList() { } /** - * Provide a list o all food in the data base in numbered String form + * Provide a list o all food in the data base in numbered String form. * @return String */ - public String getFoodListString(){ + public String getFoodListString() { List foodlist = foodStream().collect(Collectors.toList()); StringBuilder foodListString = new StringBuilder(); int foodnum = 0; - for (Food food : foodlist){ + for (Food food : foodlist) { foodnum++; foodListString.append(" ").append(foodnum).append(". ").append(food.toString()); } From 03fcd8a44a38b8af5c03174b30aa80bb31e36014 Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:49:09 +0800 Subject: [PATCH 210/271] Relaxed date filter test for robustness Some computers run the tests so quickly that LocalDateTime.now() has negligible difference in time elapsed. Relaxed upper boundary of test to LocalDateTime.MAX for robustness. --- src/test/java/seedu/dietbook/list/FoodListTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/dietbook/list/FoodListTest.java b/src/test/java/seedu/dietbook/list/FoodListTest.java index 6ec36eb032..3b7325f856 100644 --- a/src/test/java/seedu/dietbook/list/FoodListTest.java +++ b/src/test/java/seedu/dietbook/list/FoodListTest.java @@ -95,8 +95,8 @@ void dateFilterRangeTest() { assertTrue(list.getFoodsInDateTimeRange(timeNow, LocalDateTime.MAX).size() == 0); - assertEquals(list.getPortionedFoodsInDateTimeRange(LocalDateTime.MIN, timeNow).toString(), - list.getPortionedFoods().toString()); + assertEquals(list.getPortionedFoods().toString(), + list.getPortionedFoodsInDateTimeRange(LocalDateTime.MIN, LocalDateTime.MAX).toString()); } @Test From a64c0f7c3fa47d12b616bccd20c0aed336c5ffea Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 22:49:56 +0800 Subject: [PATCH 211/271] fix check style --- .../dietbook/saveload/PersonSaveLoadManagerTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java b/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java index 419cdec53e..e7c09650d1 100644 --- a/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java +++ b/src/test/java/seedu/dietbook/saveload/PersonSaveLoadManagerTest.java @@ -5,14 +5,14 @@ import java.io.FileNotFoundException; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class PersonSaveLoadManagerTest { - private static PersonSaveLoadManager pslTest; @BeforeEach - private void setUp(){ - pslTest = new PersonSaveLoadManager(); + private void setUp() { + PersonSaveLoadManager pslTest = new PersonSaveLoadManager(); pslTest.setName("Victor Chng"); pslTest.setActivityLevel(0); pslTest.setGender("UnKnown"); @@ -24,13 +24,13 @@ private void setUp(){ } @Test - private void Load_NoSuchFile_ExpectFileNotFoundException() { + private void load_noSuchFile_expectFileNotFoundException() { PersonSaveLoadManager localpslTest = new PersonSaveLoadManager(); assertThrows(FileNotFoundException.class, () -> localpslTest.load("pie die pie")); } @Test - private void Load_CorrectFile_AllContentsCorrect() throws Exception { + private void load_correctFile_allContentsCorrect() throws Exception { PersonSaveLoadManager localpslTest = new PersonSaveLoadManager(); localpslTest.load("pslTest"); assertEquals("Victor Chng", localpslTest.getName()); From 23977b84dbcc8f324cba3f40faef794ecbaa483b Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 22:55:25 +0800 Subject: [PATCH 212/271] Add methods without recalculated food --- src/main/java/seedu/dietbook/Ui.java | 126 ++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index c5ff4030ec..bfc4f3cded 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -38,7 +38,7 @@ public String readCommand() { } /** - * Prints the welcome message from DietBook when it is fist booted up. + * Prints the welcome message from DietBook when it is first booted up. */ public void printWelcomeMessage() { String logo = getLogo(); @@ -244,6 +244,19 @@ public void printFoodList(String foods, LocalDateTime start, LocalDateTime end) } } + /** + * Prints food items recorded into the food list after a given timing in the order that they were + * added or a message stating no food items were recorded after the given timing till now. + * + * @param foods The string representation of food items in the food list recorded from the given time + * till now. + * @param start Starting date time of the time period till now. + */ + public void printFoodList(String foods, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printFoodList(foods, start, end); + } + /** * Prints a message to show that the food specified has been added to the food list. * @@ -309,6 +322,11 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods) { "g", recalculatedFoods)); } + public void printCarbIntake(int carbIntake) { + print(stringOneIntakeAndFoodsWithoutTime(carbIntake,"carbohydrate", + "g")); + } + /** * Prints the total amount of carbohydrates consumed by the user and a list of the foods which had * their nutritional information recalculated by DietBook if any, given a certain time period. @@ -331,6 +349,12 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods, print(stringIntakeAndFoodsWithTime(carbIntakeAndFoodsWithoutTime, start, end)); } + public void printCarbIntake(int carbIntake, LocalDateTime start, LocalDateTime end) { + String carbIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(carbIntake, + "carbohydrate", "g"); + print(stringIntakeAndFoodsWithTime(carbIntakeAndFoodsWithoutTime, start, end)); + } + /** * Prints the total amount of carbohydrates consumed by the user and a list of the foods which had * their nutritional information recalculated by DietBook if any, given a start date. @@ -351,6 +375,11 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods, printCarbIntakeAndFoods(carbIntake, recalculatedFoods, start, end); } + public void printCarbIntake(int carbIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printCarbIntake(carbIntake, start, end); + } + /** * Prints the total amount of calories consumed by the user and the list of food items which had * their nutritional information recalculated by DietBook if any. @@ -367,6 +396,10 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo recalculatedFoods)); } + public void printCalorieIntake(int calorieIntake) { + print(stringOneIntakeAndFoodsWithoutTime(calorieIntake,"calorie","kcal")); + } + /** * Prints the total amount of calories consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a certain time period. @@ -389,6 +422,12 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo print(stringIntakeAndFoodsWithTime(calorieIntakeAndFoodsWithoutTime, start, end)); } + public void printCalorieIntake(int calorieIntake, LocalDateTime start, LocalDateTime end) { + String calorieIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(calorieIntake, + "calorie", "kcal"); + print(stringIntakeAndFoodsWithTime(calorieIntakeAndFoodsWithoutTime, start, end)); + } + /** * Prints the total amount of calories consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a start date. @@ -409,6 +448,11 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo printCalorieIntakeAndFoods(calorieIntake, recalculatedFoods, start, end); } + public void printCalorieIntake(int calorieIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printCalorieIntake(calorieIntake, start, end); + } + /** * Prints the total amount of proteins consumed by the user and the list of food items which had * their nutritional information recalculated by DietBook if any. @@ -425,6 +469,10 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo recalculatedFoods)); } + public void printProteinIntake(int proteinIntake) { + print(stringOneIntakeAndFoodsWithoutTime(proteinIntake,"protein","g")); + } + /** * Prints the total amount of proteins consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a certain time period. @@ -447,6 +495,12 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo print(stringIntakeAndFoodsWithTime(proteinIntakeAndFoodsWithoutTime, start, end)); } + public void printProteinIntake(int proteinIntake, LocalDateTime start, LocalDateTime end) { + String proteinIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(proteinIntake, + "protein", "g"); + print(stringIntakeAndFoodsWithTime(proteinIntakeAndFoodsWithoutTime, start, end)); + } + /** * Prints the total amount of proteins consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a start date. @@ -467,6 +521,11 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo printProteinIntakeAndFoods(proteinIntake, recalculatedFoods, start, end); } + public void printProteinIntake(int proteinIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printProteinIntake(proteinIntake, start, end); + } + /** * Prints the total amount of fats consumed by the user and the list of food items which had * their nutritional information recalculated by DietBook if any. @@ -483,6 +542,10 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods) { recalculatedFoods)); } + public void printFatIntake(int fatIntake) { + print(stringOneIntakeAndFoodsWithoutTime(fatIntake,"fat","g")); + } + /** * Prints the total amount of fats consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a certain time period. @@ -505,6 +568,12 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, print(stringIntakeAndFoodsWithTime(fatIntakeAndFoodsWithoutTime, start, end)); } + public void printFatIntake(int fatIntake, LocalDateTime start, LocalDateTime end) { + String fatIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(fatIntake, + "fat", "g"); + print(stringIntakeAndFoodsWithTime(fatIntakeAndFoodsWithoutTime, start, end)); + } + /** * Prints the total amount of fats consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a start date. @@ -525,6 +594,11 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, printFatIntakeAndFoods(fatIntake, recalculatedFoods, start, end); } + public void printFatIntake(int fatIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printFatIntake(fatIntake, start, end); + } + /** * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and the * list of food items which had their nutritional information recalculated by DietBook if any. @@ -545,6 +619,12 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei fatIntake, recalculatedFoods)); } + public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake) { + print(stringAllIntakeAndFoodsWithoutTime(calorieIntake, carbIntake, proteinIntake, + fatIntake)); + } + /** * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and a * list of the foods which had their nutritional information recalculated by DietBook if any, given a @@ -575,6 +655,13 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); } + public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake, LocalDateTime start, LocalDateTime end) { + String allIntakeAndFoodsWithoutTime = stringAllIntakeAndFoodsWithoutTime(calorieIntake, + carbIntake, proteinIntake, fatIntake); + print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); + } + /** * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and a * list of the foods which had their nutritional information recalculated by DietBook if any, given a @@ -604,6 +691,12 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei end); } + public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, int fatIntake, + LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printAllIntake(calorieIntake, carbIntake, proteinIntake, fatIntake, start, end); + } + // Helper methods for system related commands or messages /** @@ -776,6 +869,16 @@ private String stringOneIntakeAndFoodsWithoutTime(int nutrientIntake, String nut return stringNutrientIntake + LINE_SEPARATOR + message; } + private String stringOneIntakeAndFoodsWithoutTime(int nutrientIntake, String nutrientType, + String nutrientUnit) { + performAssertionsForStringInputs(nutrientType,"Nutrient Type"); + performAssertionsForStringInputs(nutrientUnit, "Nutrient Unit"); + performAssertionsForNutritionalIntake(nutrientIntake, nutrientType); + + String stringNutrientIntake = stringNutritionalIntake(nutrientIntake, nutrientType, nutrientUnit); + return stringNutrientIntake; + } + /** * Returns a string representation of the total amount of a nutrient or all nutrientS consumed by the * user during a given time period and the list of food items recorded during the same time period @@ -835,6 +938,27 @@ private String stringAllIntakeAndFoodsWithoutTime(int calorieIntake, int carbInt } + private String stringAllIntakeAndFoodsWithoutTime(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake) { + performAssertionsForNutritionalIntake(carbIntake, "carbohydrate"); + performAssertionsForNutritionalIntake(calorieIntake, "calorie"); + performAssertionsForNutritionalIntake(proteinIntake, "protein"); + performAssertionsForNutritionalIntake(fatIntake, "fat"); + + + String stringCarbIntake = stringNutritionalIntake(carbIntake,"carbohydrate", "g"); + String stringCalorieIntake = stringNutritionalIntake(calorieIntake,"calorie", + "kcal"); + String stringProteinIntake = stringNutritionalIntake(proteinIntake,"protein", "g"); + String stringFatIntake = stringNutritionalIntake(fatIntake,"fat", "g"); + + return stringCalorieIntake + LINE_SEPARATOR + + stringCarbIntake + LINE_SEPARATOR + + stringProteinIntake + LINE_SEPARATOR + + stringFatIntake + LINE_SEPARATOR; + + } + // Other helper methods /** From 87aa8c7c0bf7893974c9e08a27bd81fae4c94831 Mon Sep 17 00:00:00 2001 From: yuqiaoluolong Date: Tue, 27 Oct 2020 23:00:11 +0800 Subject: [PATCH 213/271] resolved name violation --- .../java/seedu/dietbook/calculator/CalculatorTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/dietbook/calculator/CalculatorTest.java b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java index bd0d3a5d47..d2cd6e7b10 100644 --- a/src/test/java/seedu/dietbook/calculator/CalculatorTest.java +++ b/src/test/java/seedu/dietbook/calculator/CalculatorTest.java @@ -56,10 +56,10 @@ void calculateFat_foodListOfThreeItems_sumOfFat() { @Test void calculateRecomendedCalorieIntake_aPerson_recomendationOfCalorieIntake() { - Person Harry = new Person("Harry", Gender.MALE, 19, 182, 66, 69, 75, ActivityLevel.LOW); - Person Erica = new Person("Erica", Gender.FEMALE, 20, 168, 52, 50, 45, ActivityLevel.MEDIUM); + Person harry = new Person("Harry", Gender.MALE, 19, 182, 66, 69, 75, ActivityLevel.LOW); + Person erica = new Person("Erica", Gender.FEMALE, 20, 168, 52, 50, 45, ActivityLevel.MEDIUM); Calculator calculator = new Calculator(new ArrayList()); - assertEquals(2728, calculator.calculateRecomendation(Harry)); - assertEquals(1752, calculator.calculateRecomendation(Erica)); + assertEquals(2728, calculator.calculateRecomendation(harry)); + assertEquals(1752, calculator.calculateRecomendation(erica)); } } From 55d5b07434f811b9653d791960030a438a06329f Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Tue, 27 Oct 2020 23:03:15 +0800 Subject: [PATCH 214/271] copy paste --- .../java/seedu/dietbook/food/FoodTest.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/test/java/seedu/dietbook/food/FoodTest.java b/src/test/java/seedu/dietbook/food/FoodTest.java index d423c7f1d0..91b917608c 100644 --- a/src/test/java/seedu/dietbook/food/FoodTest.java +++ b/src/test/java/seedu/dietbook/food/FoodTest.java @@ -1,11 +1,25 @@ package seedu.dietbook.food; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + class FoodTest { private Food testFood; - public static void main(String[] args) { - Food food = new Food("Kobe Beef", 480,50,40,30); - System.out.println(food); + @BeforeEach + public void setUp() { + testFood = new Food("Kobe Beef", 480,50,40,30); + } + + @Test + public void footTest() { + assertEquals(480, testFood.getCalorie()); + assertEquals(50, testFood.getCarbohydrate()); + assertEquals(40, testFood.getProtein()); + assertEquals(30, testFood.getFat()); } } \ No newline at end of file From 3f63e1ddb8a6864c7c2c0aa39f5bfb8324df1de9 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Tue, 27 Oct 2020 23:09:01 +0800 Subject: [PATCH 215/271] Fix checkstyle error --- src/main/java/seedu/dietbook/Ui.java | 157 ++++++++++++++------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index bfc4f3cded..a03565a0af 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -306,6 +306,86 @@ public void printCalorieRecommendation(String name, int calorieRecommendation) { + "Here is your daily recommended calorie intake: " + calorieRecommendation + "kcal"); } + public void printCarbIntake(int carbIntake) { + print(stringOneIntakeAndFoodsWithoutTime(carbIntake,"carbohydrate", + "g")); + } + + public void printCarbIntake(int carbIntake, LocalDateTime start, LocalDateTime end) { + String carbIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(carbIntake, + "carbohydrate", "g"); + print(stringIntakeAndFoodsWithTime(carbIntakeAndFoodsWithoutTime, start, end)); + } + + public void printCarbIntake(int carbIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printCarbIntake(carbIntake, start, end); + } + + public void printCalorieIntake(int calorieIntake) { + print(stringOneIntakeAndFoodsWithoutTime(calorieIntake,"calorie","kcal")); + } + + public void printCalorieIntake(int calorieIntake, LocalDateTime start, LocalDateTime end) { + String calorieIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(calorieIntake, + "calorie", "kcal"); + print(stringIntakeAndFoodsWithTime(calorieIntakeAndFoodsWithoutTime, start, end)); + } + + public void printCalorieIntake(int calorieIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printCalorieIntake(calorieIntake, start, end); + } + + public void printProteinIntake(int proteinIntake) { + print(stringOneIntakeAndFoodsWithoutTime(proteinIntake,"protein","g")); + } + + public void printProteinIntake(int proteinIntake, LocalDateTime start, LocalDateTime end) { + String proteinIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(proteinIntake, + "protein", "g"); + print(stringIntakeAndFoodsWithTime(proteinIntakeAndFoodsWithoutTime, start, end)); + } + + public void printProteinIntake(int proteinIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printProteinIntake(proteinIntake, start, end); + } + + public void printFatIntake(int fatIntake) { + print(stringOneIntakeAndFoodsWithoutTime(fatIntake,"fat","g")); + } + + public void printFatIntake(int fatIntake, LocalDateTime start, LocalDateTime end) { + String fatIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(fatIntake, + "fat", "g"); + print(stringIntakeAndFoodsWithTime(fatIntakeAndFoodsWithoutTime, start, end)); + } + + public void printFatIntake(int fatIntake, LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printFatIntake(fatIntake, start, end); + } + + public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake) { + print(stringAllIntakeAndFoodsWithoutTime(calorieIntake, carbIntake, proteinIntake, + fatIntake)); + } + + public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, + int fatIntake, LocalDateTime start, LocalDateTime end) { + String allIntakeAndFoodsWithoutTime = stringAllIntakeAndFoodsWithoutTime(calorieIntake, + carbIntake, proteinIntake, fatIntake); + print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); + } + + public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, int fatIntake, + LocalDateTime start) { + LocalDateTime end = LocalDateTime.now(); + printAllIntake(calorieIntake, carbIntake, proteinIntake, fatIntake, start, end); + } + /** * Prints the total amount of carbohydrates consumed by the user and the list of food items which had * their nutritional information recalculated by DietBook if any. @@ -322,11 +402,6 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods) { "g", recalculatedFoods)); } - public void printCarbIntake(int carbIntake) { - print(stringOneIntakeAndFoodsWithoutTime(carbIntake,"carbohydrate", - "g")); - } - /** * Prints the total amount of carbohydrates consumed by the user and a list of the foods which had * their nutritional information recalculated by DietBook if any, given a certain time period. @@ -349,12 +424,6 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods, print(stringIntakeAndFoodsWithTime(carbIntakeAndFoodsWithoutTime, start, end)); } - public void printCarbIntake(int carbIntake, LocalDateTime start, LocalDateTime end) { - String carbIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(carbIntake, - "carbohydrate", "g"); - print(stringIntakeAndFoodsWithTime(carbIntakeAndFoodsWithoutTime, start, end)); - } - /** * Prints the total amount of carbohydrates consumed by the user and a list of the foods which had * their nutritional information recalculated by DietBook if any, given a start date. @@ -375,10 +444,6 @@ public void printCarbIntakeAndFoods(int carbIntake, String recalculatedFoods, printCarbIntakeAndFoods(carbIntake, recalculatedFoods, start, end); } - public void printCarbIntake(int carbIntake, LocalDateTime start) { - LocalDateTime end = LocalDateTime.now(); - printCarbIntake(carbIntake, start, end); - } /** * Prints the total amount of calories consumed by the user and the list of food items which had @@ -396,10 +461,6 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo recalculatedFoods)); } - public void printCalorieIntake(int calorieIntake) { - print(stringOneIntakeAndFoodsWithoutTime(calorieIntake,"calorie","kcal")); - } - /** * Prints the total amount of calories consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a certain time period. @@ -422,12 +483,6 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo print(stringIntakeAndFoodsWithTime(calorieIntakeAndFoodsWithoutTime, start, end)); } - public void printCalorieIntake(int calorieIntake, LocalDateTime start, LocalDateTime end) { - String calorieIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(calorieIntake, - "calorie", "kcal"); - print(stringIntakeAndFoodsWithTime(calorieIntakeAndFoodsWithoutTime, start, end)); - } - /** * Prints the total amount of calories consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a start date. @@ -448,10 +503,6 @@ public void printCalorieIntakeAndFoods(int calorieIntake, String recalculatedFoo printCalorieIntakeAndFoods(calorieIntake, recalculatedFoods, start, end); } - public void printCalorieIntake(int calorieIntake, LocalDateTime start) { - LocalDateTime end = LocalDateTime.now(); - printCalorieIntake(calorieIntake, start, end); - } /** * Prints the total amount of proteins consumed by the user and the list of food items which had @@ -469,10 +520,6 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo recalculatedFoods)); } - public void printProteinIntake(int proteinIntake) { - print(stringOneIntakeAndFoodsWithoutTime(proteinIntake,"protein","g")); - } - /** * Prints the total amount of proteins consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a certain time period. @@ -495,12 +542,6 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo print(stringIntakeAndFoodsWithTime(proteinIntakeAndFoodsWithoutTime, start, end)); } - public void printProteinIntake(int proteinIntake, LocalDateTime start, LocalDateTime end) { - String proteinIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(proteinIntake, - "protein", "g"); - print(stringIntakeAndFoodsWithTime(proteinIntakeAndFoodsWithoutTime, start, end)); - } - /** * Prints the total amount of proteins consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a start date. @@ -521,10 +562,6 @@ public void printProteinIntakeAndFoods(int proteinIntake, String recalculatedFoo printProteinIntakeAndFoods(proteinIntake, recalculatedFoods, start, end); } - public void printProteinIntake(int proteinIntake, LocalDateTime start) { - LocalDateTime end = LocalDateTime.now(); - printProteinIntake(proteinIntake, start, end); - } /** * Prints the total amount of fats consumed by the user and the list of food items which had @@ -542,10 +579,6 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods) { recalculatedFoods)); } - public void printFatIntake(int fatIntake) { - print(stringOneIntakeAndFoodsWithoutTime(fatIntake,"fat","g")); - } - /** * Prints the total amount of fats consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a certain time period. @@ -568,12 +601,6 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, print(stringIntakeAndFoodsWithTime(fatIntakeAndFoodsWithoutTime, start, end)); } - public void printFatIntake(int fatIntake, LocalDateTime start, LocalDateTime end) { - String fatIntakeAndFoodsWithoutTime = stringOneIntakeAndFoodsWithoutTime(fatIntake, - "fat", "g"); - print(stringIntakeAndFoodsWithTime(fatIntakeAndFoodsWithoutTime, start, end)); - } - /** * Prints the total amount of fats consumed by the user and a list of the foods which had their * nutritional information recalculated by DietBook if any, given a start date. @@ -594,11 +621,6 @@ public void printFatIntakeAndFoods(int fatIntake, String recalculatedFoods, printFatIntakeAndFoods(fatIntake, recalculatedFoods, start, end); } - public void printFatIntake(int fatIntake, LocalDateTime start) { - LocalDateTime end = LocalDateTime.now(); - printFatIntake(fatIntake, start, end); - } - /** * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and the * list of food items which had their nutritional information recalculated by DietBook if any. @@ -619,12 +641,6 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei fatIntake, recalculatedFoods)); } - public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, - int fatIntake) { - print(stringAllIntakeAndFoodsWithoutTime(calorieIntake, carbIntake, proteinIntake, - fatIntake)); - } - /** * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and a * list of the foods which had their nutritional information recalculated by DietBook if any, given a @@ -655,13 +671,6 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); } - public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, - int fatIntake, LocalDateTime start, LocalDateTime end) { - String allIntakeAndFoodsWithoutTime = stringAllIntakeAndFoodsWithoutTime(calorieIntake, - carbIntake, proteinIntake, fatIntake); - print(stringIntakeAndFoodsWithTime(allIntakeAndFoodsWithoutTime, start, end)); - } - /** * Prints the total amount of calories, carbohydrates, fats and proteins consumed by the user and a * list of the foods which had their nutritional information recalculated by DietBook if any, given a @@ -691,12 +700,6 @@ public void printAllIntakeAndFoods(int calorieIntake, int carbIntake, int protei end); } - public void printAllIntake(int calorieIntake, int carbIntake, int proteinIntake, int fatIntake, - LocalDateTime start) { - LocalDateTime end = LocalDateTime.now(); - printAllIntake(calorieIntake, carbIntake, proteinIntake, fatIntake, start, end); - } - // Helper methods for system related commands or messages /** From 093a59359d0056513a8027afe2e1cfa2591baad7 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 11:07:54 +0800 Subject: [PATCH 216/271] fix bug getFoodListString StringBuilder missing "\n" --- src/main/java/seedu/dietbook/database/DataBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java index b9fa8c1e7b..d671260c6c 100644 --- a/src/main/java/seedu/dietbook/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -270,7 +270,7 @@ public String getFoodListString() { int foodnum = 0; for (Food food : foodlist) { foodnum++; - foodListString.append(" ").append(foodnum).append(". ").append(food.toString()); + foodListString.append(" ").append(foodnum).append(". ").append(food.toString()).append("\n"); } return foodListString.toString(); } From 5c8ad977ec517bec999003bcafea71a4cdb16972 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 18:15:19 +0800 Subject: [PATCH 217/271] UML diagram --- UML_diaghrams/week 11 DG.puml | 16 +++++++++++ docs/Zhong_Ming_developer_Guide/zm_DG.md | 34 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 UML_diaghrams/week 11 DG.puml create mode 100644 docs/Zhong_Ming_developer_Guide/zm_DG.md diff --git a/UML_diaghrams/week 11 DG.puml b/UML_diaghrams/week 11 DG.puml new file mode 100644 index 0000000000..043a2591a7 --- /dev/null +++ b/UML_diaghrams/week 11 DG.puml @@ -0,0 +1,16 @@ + + + + + +@startuml + +Alice -> Bob: Authentication Request +Bob --> Alice: Authentication Response + +Alice -> Bob: Another authentication Request +Alice <-- Bob: another authentication Response + +Alice -> Bob : insert laser probe +Alice <-- Bob : output cavity liquid +@enduml \ No newline at end of file diff --git a/docs/Zhong_Ming_developer_Guide/zm_DG.md b/docs/Zhong_Ming_developer_Guide/zm_DG.md new file mode 100644 index 0000000000..8faa7b38e6 --- /dev/null +++ b/docs/Zhong_Ming_developer_Guide/zm_DG.md @@ -0,0 +1,34 @@ +## Save/Load Feature + +The Save/Load feature is implemented by the saveload package. +At the base of the package, there is the Saver +and Loader class. + +### Architecture + +#### Saver class +Stores data in a internal table with length and height specified. +Handles the storage of its data by writing to a text file. +##### Constructor +Specifies the length and height of the internal Saver table +##### Main Methods +* Saver#save() saves the current data to the file in the folder with the given file name +* Saver#add() Store String data in the x,y position in the table + +#### Loader class +Loads data from a text file and stores it in a internal table just like the saver +##### Constructor +static method Loader.load(folder name , file name) : creates a Loader object with +a table storing the data found in the text file +##### Main Methods +* Loader#get() retrives the data stored in the loader + +#### FoodSaveLoadManager class +Built on top of Saver and Loader class to implement save/load functionality +for list of food items the user has input into the dietbook. Contains a instance +of both Saver and Loader . It has its own folder to work with, +the user only has to specify the file name. +##### Main Methods +* FoodSaveLoadManager#save saves the list of food objects to the specified file name +* FoodSaveLoadManager#load loads the file and returns the list of food objects stored inside it + From 3af64084410e779b92c518c875fa97604785501a Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Wed, 28 Oct 2020 18:17:18 +0800 Subject: [PATCH 218/271] Delete Duke.java --- src/main/java/seedu/dietbook/Duke.java | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/main/java/seedu/dietbook/Duke.java diff --git a/src/main/java/seedu/dietbook/Duke.java b/src/main/java/seedu/dietbook/Duke.java deleted file mode 100644 index e2af504b4b..0000000000 --- a/src/main/java/seedu/dietbook/Duke.java +++ /dev/null @@ -1,21 +0,0 @@ -package seedu.dietbook; - -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()); - } -} From 5b73b910fa6796392c63fbedf2b23d58b6123462 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 18:23:32 +0800 Subject: [PATCH 219/271] architecture diaghram --- UML_diaghrams/Architecture.puml | 8 ++++++++ docs/Zhong_Ming_developer_Guide/zm_DG.md | 1 + 2 files changed, 9 insertions(+) create mode 100644 UML_diaghrams/Architecture.puml diff --git a/UML_diaghrams/Architecture.puml b/UML_diaghrams/Architecture.puml new file mode 100644 index 0000000000..30c4607c3b --- /dev/null +++ b/UML_diaghrams/Architecture.puml @@ -0,0 +1,8 @@ +@startuml +object Saver +object Loader +object FoodSaveLoadManager +object PersonSaveLoadManager + + +@enduml diff --git a/docs/Zhong_Ming_developer_Guide/zm_DG.md b/docs/Zhong_Ming_developer_Guide/zm_DG.md index 8faa7b38e6..a56bdb5e6c 100644 --- a/docs/Zhong_Ming_developer_Guide/zm_DG.md +++ b/docs/Zhong_Ming_developer_Guide/zm_DG.md @@ -6,6 +6,7 @@ and Loader class. ### Architecture + #### Saver class Stores data in a internal table with length and height specified. Handles the storage of its data by writing to a text file. From d8c8d9f8d3ccd4726d229b37e60fac2fcc4c247e Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 18:53:28 +0800 Subject: [PATCH 220/271] finished words --- UML_diaghrams/Architecture.puml | 11 +++++++++++ .../{week 11 DG.puml => UML diagram.puml} | 7 ------- docs/Zhong_Ming_developer_Guide/zm_DG.md | 17 ++++++++++++++--- 3 files changed, 25 insertions(+), 10 deletions(-) rename UML_diaghrams/{week 11 DG.puml => UML diagram.puml} (71%) diff --git a/UML_diaghrams/Architecture.puml b/UML_diaghrams/Architecture.puml index 30c4607c3b..d4ec941ef8 100644 --- a/UML_diaghrams/Architecture.puml +++ b/UML_diaghrams/Architecture.puml @@ -3,6 +3,17 @@ object Saver object Loader object FoodSaveLoadManager object PersonSaveLoadManager +object Command +object File +File <-up-> Saver +File <-up-> Loader +Saver <-up-> FoodSaveLoadManager +Saver <-up-> PersonSaveLoadManager +Loader <-up-> FoodSaveLoadManager +Loader <-up-> PersonSaveLoadManager + +FoodSaveLoadManager <-up-> Command +PersonSaveLoadManager <-up-> Command @enduml diff --git a/UML_diaghrams/week 11 DG.puml b/UML_diaghrams/UML diagram.puml similarity index 71% rename from UML_diaghrams/week 11 DG.puml rename to UML_diaghrams/UML diagram.puml index 043a2591a7..1d58b9f108 100644 --- a/UML_diaghrams/week 11 DG.puml +++ b/UML_diaghrams/UML diagram.puml @@ -1,16 +1,9 @@ - - - @startuml - Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: another authentication Response - -Alice -> Bob : insert laser probe -Alice <-- Bob : output cavity liquid @enduml \ No newline at end of file diff --git a/docs/Zhong_Ming_developer_Guide/zm_DG.md b/docs/Zhong_Ming_developer_Guide/zm_DG.md index a56bdb5e6c..286af4164f 100644 --- a/docs/Zhong_Ming_developer_Guide/zm_DG.md +++ b/docs/Zhong_Ming_developer_Guide/zm_DG.md @@ -5,7 +5,9 @@ At the base of the package, there is the Saver and Loader class. ### Architecture - +Note only the Saver and Loader class is flexible. They can be adapted to new situations without modifying +the code. The FoodSaveLoadManager and PersonSaveLoadManager are written specifically for this version. They +will have to be modified/replaced for future versions. #### Saver class Stores data in a internal table with length and height specified. @@ -30,6 +32,15 @@ for list of food items the user has input into the dietbook. Contains a instance of both Saver and Loader . It has its own folder to work with, the user only has to specify the file name. ##### Main Methods -* FoodSaveLoadManager#save saves the list of food objects to the specified file name -* FoodSaveLoadManager#load loads the file and returns the list of food objects stored inside it +* FoodSaveLoadManager#save() saves the list of food objects to the specified file name +* FoodSaveLoadManager#load() loads the file and returns the list of food objects stored inside it + +#### PersonSaveLoadManager class +Built on top of Saver and Loader class to implement save/load functionality for user information +Same as FoodSaveLoadManager, it has its own folder to work with, the user only has to specify the file name +Unlike the FoodSaveLoadManager, it stores the data inside itself and can be updated. +##### Main Methods +* PersonSaveLoadManager#save() save the current state into the file +* PersonSaveLoadManager#load() loads the file +* Setters and Getters for all the personal data in this current version From 08b941b4c8dc46015d864194f0c99b3b4f7463ff Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 19:39:05 +0800 Subject: [PATCH 221/271] draw UML diaghrams --- .gitignore | 2 ++ UML_diaghrams/FoodSaveLoadManager_load.puml | 24 +++++++++++++++++++++ UML_diaghrams/FoodSaveLoadManager_save.puml | 24 +++++++++++++++++++++ UML_diaghrams/UML diagram.puml | 16 +++++++++----- docs/Zhong_Ming_developer_Guide/zm_DG.md | 3 +++ 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 UML_diaghrams/FoodSaveLoadManager_load.puml create mode 100644 UML_diaghrams/FoodSaveLoadManager_save.puml diff --git a/.gitignore b/.gitignore index f69985ef1f..1fafd04fd6 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ bin/ /text-ui-test/ACTUAL.txt text-ui-test/EXPECTED-UNIX.TXT +docs/Zhong_Ming_developer_Guide/Architecture.png +*.png diff --git a/UML_diaghrams/FoodSaveLoadManager_load.puml b/UML_diaghrams/FoodSaveLoadManager_load.puml new file mode 100644 index 0000000000..51669578f2 --- /dev/null +++ b/UML_diaghrams/FoodSaveLoadManager_load.puml @@ -0,0 +1,24 @@ +@startuml + +-> FoodSaveLoadManager : load() +activate FoodSaveLoadManager + +FoodSaveLoadManager -> Loader : static load() + +activate Loader +Loader -> FileLoader : load() + +activate FileLoader +loop all lines + activate Scanner + FileLoader -> Scanner : readline() + Scanner --> FileLoader : line data + destroy Scanner +end +FileLoader --> Loader : FileLoader +deactivate FileLoader + +Loader --> FoodSaveLoadManager : FileLoader +deactivate Loader +deactivate FoodSaveLoadManager +@enduml \ No newline at end of file diff --git a/UML_diaghrams/FoodSaveLoadManager_save.puml b/UML_diaghrams/FoodSaveLoadManager_save.puml new file mode 100644 index 0000000000..ea1c8a4805 --- /dev/null +++ b/UML_diaghrams/FoodSaveLoadManager_save.puml @@ -0,0 +1,24 @@ +@startuml +-> FoodSaveLoadManager : save +activate FoodSaveLoadManager + + +loop all food items + loop every entry in a food object + activate Saver + FoodSaveLoadManager -> Saver : add() + end +end + +FoodSaveLoadManager -> Saver : save() +deactivate Saver + +activate FileWriter +loop all entries in Saver table + Saver -> FileWriter : write() +end +destroy FileWriter + +deactivate FoodSaveLoadManager + +@enduml \ No newline at end of file diff --git a/UML_diaghrams/UML diagram.puml b/UML_diaghrams/UML diagram.puml index 1d58b9f108..c82d8be9d3 100644 --- a/UML_diaghrams/UML diagram.puml +++ b/UML_diaghrams/UML diagram.puml @@ -1,9 +1,15 @@ - @startuml -Alice -> Bob: Authentication Request -Bob --> Alice: Authentication Response +-> FoodSaveLoadManager : save + +loop all food items + loop every entry in a food object + FoodSaveLoadManager -> Saver : add() + end +end -Alice -> Bob: Another authentication Request -Alice <-- Bob: another authentication Response +FoodSaveLoadManager -> Saver : save() +loop all entries in Saver table + Saver -> FileWriter : write() +end @enduml \ No newline at end of file diff --git a/docs/Zhong_Ming_developer_Guide/zm_DG.md b/docs/Zhong_Ming_developer_Guide/zm_DG.md index 286af4164f..56fd3b7570 100644 --- a/docs/Zhong_Ming_developer_Guide/zm_DG.md +++ b/docs/Zhong_Ming_developer_Guide/zm_DG.md @@ -10,8 +10,10 @@ the code. The FoodSaveLoadManager and PersonSaveLoadManager are written specific will have to be modified/replaced for future versions. #### Saver class +![Alt text](Architecture.png) Stores data in a internal table with length and height specified. Handles the storage of its data by writing to a text file. + ##### Constructor Specifies the length and height of the internal Saver table ##### Main Methods @@ -44,3 +46,4 @@ Unlike the FoodSaveLoadManager, it stores the data inside itself and can be upda * PersonSaveLoadManager#load() loads the file * Setters and Getters for all the personal data in this current version +#### UML diaghram From 59643b96f7fd46e39a3f058c7922fb833a0159eb Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 19:50:50 +0800 Subject: [PATCH 222/271] complete DG --- docs/Zhong_Ming_developer_Guide/zm_DG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/Zhong_Ming_developer_Guide/zm_DG.md b/docs/Zhong_Ming_developer_Guide/zm_DG.md index 56fd3b7570..50abef666a 100644 --- a/docs/Zhong_Ming_developer_Guide/zm_DG.md +++ b/docs/Zhong_Ming_developer_Guide/zm_DG.md @@ -47,3 +47,8 @@ Unlike the FoodSaveLoadManager, it stores the data inside itself and can be upda * Setters and Getters for all the personal data in this current version #### UML diaghram +##### FoodSaveLoadManager#save() +![Alt text](FoodSaveLoadManager_save.png) +##### FoodSaveLoadManager#load() +![Alt text](FoodSaveLoadManager_load.png) +similiar diaghrams for PersonSaveLoadManager \ No newline at end of file From 63f6a8570de6af512defcdd15d2e3dc7e5eb34c2 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 19:53:36 +0800 Subject: [PATCH 223/271] diaghrams --- .gitignore | 3 +-- .../Zhong_Ming_developer_Guide/Architecture.png | Bin 0 -> 43003 bytes .../FoodSaveLoadManager_load.png | Bin 0 -> 77795 bytes .../FoodSaveLoadManager_save.png | Bin 0 -> 75922 bytes 4 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 docs/Zhong_Ming_developer_Guide/Architecture.png create mode 100644 docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_load.png create mode 100644 docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png diff --git a/.gitignore b/.gitignore index 1fafd04fd6..ea7ac5150a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,4 @@ bin/ /text-ui-test/ACTUAL.txt text-ui-test/EXPECTED-UNIX.TXT -docs/Zhong_Ming_developer_Guide/Architecture.png -*.png + diff --git a/docs/Zhong_Ming_developer_Guide/Architecture.png b/docs/Zhong_Ming_developer_Guide/Architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..1ca758c26adedd91685225c66df5578ba73afbcc GIT binary patch literal 43003 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%0Agux07_eCdzyRD<{cnP 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 literal 0 HcmV?d00001 diff --git a/docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png b/docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png new file mode 100644 index 0000000000000000000000000000000000000000..61891d2a8d921406abaf721cc2d7ec66c4a22801 GIT binary patch literal 75922 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

RP~Nt3!$haqVXk7PW`bqQ4ER70K@A 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

RP~Nt3!$haqVXk7PW`bqQ4ER70K@A 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�*kGnH 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 Saver +and Loader class. + +### Architecture +![Alt text](Architecture.png) +Note only the Saver and Loader class is flexible. They can be adapted to new situations without modifying +the code. The FoodSaveLoadManager and PersonSaveLoadManager are written specifically for this version. They +will have to be modified/replaced for future versions. + +#### Saver class + +Stores data in a internal table with length and height specified. +Handles the storage of its data by writing to a text file. + +##### Constructor +Specifies the length and height of the internal Saver table +##### Main Methods +* Saver#save() saves the current data to the file in the folder with the given file name +* Saver#add() Store String data in the x,y position in the table + +#### Loader class +Loads data from a text file and stores it in a internal table just like the saver +##### Constructor +static method Loader.load(folder name , file name) : creates a Loader object with +a table storing the data found in the text file +##### Main Methods +* Loader#get() retrives the data stored in the loader + +#### FoodSaveLoadManager class +Built on top of Saver and Loader class to implement save/load functionality +for list of food items the user has input into the dietbook. Contains a instance +of both Saver and Loader . It has its own folder to work with, +the user only has to specify the file name. +##### Main Methods +* FoodSaveLoadManager#save() saves the list of food objects to the specified file name +* FoodSaveLoadManager#load() loads the file and returns the list of food objects stored inside it + +#### PersonSaveLoadManager class +Built on top of Saver and Loader class to implement save/load functionality for user information +Same as FoodSaveLoadManager, it has its own folder to work with, the user only has to specify the file name +Unlike the FoodSaveLoadManager, it stores the data inside itself and can be updated. +##### Main Methods +* PersonSaveLoadManager#save() save the current state into the file +* PersonSaveLoadManager#load() loads the file +* Setters and Getters for all the personal data in this current version + +#### UML diaghram +##### FoodSaveLoadManager#save() +![Alt text](FoodSaveLoadManager_save.png) +##### FoodSaveLoadManager#load() +![Alt text](FoodSaveLoadManager_load.png) +similiar diaghrams for PersonSaveLoadManager \ No newline at end of file From 7cd69c4de11e0a9be6068db82e86f4ad683aacef Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 20:30:41 +0800 Subject: [PATCH 226/271] rename folders --- .../{ => save_load_feature}/Architecture.puml | 0 .../FoodSaveLoadManager_load.puml | 0 .../FoodSaveLoadManager_save.puml | 0 .../{ => save_load_feature}/UML diagram.puml | 0 .../Architecture.png | Bin .../FoodSaveLoadManager_load.png | Bin .../FoodSaveLoadManager_save.png | Bin .../zm_DG.md | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename UML_diaghrams/{ => save_load_feature}/Architecture.puml (100%) rename UML_diaghrams/{ => save_load_feature}/FoodSaveLoadManager_load.puml (100%) rename UML_diaghrams/{ => save_load_feature}/FoodSaveLoadManager_save.puml (100%) rename UML_diaghrams/{ => save_load_feature}/UML diagram.puml (100%) rename docs/{Zhong_Ming_developer_Guide => save_load_feature}/Architecture.png (100%) rename docs/{Zhong_Ming_developer_Guide => save_load_feature}/FoodSaveLoadManager_load.png (100%) rename docs/{Zhong_Ming_developer_Guide => save_load_feature}/FoodSaveLoadManager_save.png (100%) rename docs/{Zhong_Ming_developer_Guide => save_load_feature}/zm_DG.md (100%) diff --git a/UML_diaghrams/Architecture.puml b/UML_diaghrams/save_load_feature/Architecture.puml similarity index 100% rename from UML_diaghrams/Architecture.puml rename to UML_diaghrams/save_load_feature/Architecture.puml diff --git a/UML_diaghrams/FoodSaveLoadManager_load.puml b/UML_diaghrams/save_load_feature/FoodSaveLoadManager_load.puml similarity index 100% rename from UML_diaghrams/FoodSaveLoadManager_load.puml rename to UML_diaghrams/save_load_feature/FoodSaveLoadManager_load.puml diff --git a/UML_diaghrams/FoodSaveLoadManager_save.puml b/UML_diaghrams/save_load_feature/FoodSaveLoadManager_save.puml similarity index 100% rename from UML_diaghrams/FoodSaveLoadManager_save.puml rename to UML_diaghrams/save_load_feature/FoodSaveLoadManager_save.puml diff --git a/UML_diaghrams/UML diagram.puml b/UML_diaghrams/save_load_feature/UML diagram.puml similarity index 100% rename from UML_diaghrams/UML diagram.puml rename to UML_diaghrams/save_load_feature/UML diagram.puml diff --git a/docs/Zhong_Ming_developer_Guide/Architecture.png b/docs/save_load_feature/Architecture.png similarity index 100% rename from docs/Zhong_Ming_developer_Guide/Architecture.png rename to docs/save_load_feature/Architecture.png diff --git a/docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_load.png b/docs/save_load_feature/FoodSaveLoadManager_load.png similarity index 100% rename from docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_load.png rename to docs/save_load_feature/FoodSaveLoadManager_load.png diff --git a/docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png b/docs/save_load_feature/FoodSaveLoadManager_save.png similarity index 100% rename from docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png rename to docs/save_load_feature/FoodSaveLoadManager_save.png diff --git a/docs/Zhong_Ming_developer_Guide/zm_DG.md b/docs/save_load_feature/zm_DG.md similarity index 100% rename from docs/Zhong_Ming_developer_Guide/zm_DG.md rename to docs/save_load_feature/zm_DG.md From e8cde0b9c70af3859366d49c5ba3158a45c9f411 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 20:30:59 +0800 Subject: [PATCH 227/271] add save load feature part into developerGuide.md --- docs/DeveloperGuide.md | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0ec3db103d..5899b377f5 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -3,7 +3,61 @@ ## Design & implementation {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +## Save/Load Feature +The Save/Load feature is implemented by the saveload package. +At the base of the package, there is the Saver +and Loader class. + +### Architecture +![Alt text](save_load_feature/Architecture.png) +Note only the Saver and Loader class is flexible. They can be adapted to new situations without modifying +the code. The FoodSaveLoadManager and PersonSaveLoadManager are written specifically for this version. They +will have to be modified/replaced for future versions. + +#### Saver class + +Stores data in a internal table with length and height specified. +Handles the storage of its data by writing to a text file. + +##### Constructor +Specifies the length and height of the internal Saver table +##### Main Methods +* Saver#save() saves the current data to the file in the folder with the given file name +* Saver#add() Store String data in the x,y position in the table + +#### Loader class +Loads data from a text file and stores it in a internal table just like the saver +##### Constructor +static method Loader.load(folder name , file name) : creates a Loader object with +a table storing the data found in the text file +##### Main Methods +* Loader#get() retrives the data stored in the loader + +#### FoodSaveLoadManager class +Built on top of Saver and Loader class to implement save/load functionality +for list of food items the user has input into the dietbook. Contains a instance +of both Saver and Loader . It has its own folder to work with, +the user only has to specify the file name. +##### Main Methods +* FoodSaveLoadManager#save() saves the list of food objects to the specified file name +* FoodSaveLoadManager#load() loads the file and returns the list of food objects stored inside it + +#### PersonSaveLoadManager class +Built on top of Saver and Loader class to implement save/load functionality for user information +Same as FoodSaveLoadManager, it has its own folder to work with, the user only has to specify the file name +Unlike the FoodSaveLoadManager, it stores the data inside itself and can be updated. +##### Main Methods +* PersonSaveLoadManager#save() save the current state into the file +* PersonSaveLoadManager#load() loads the file +* Setters and Getters for all the personal data in this current version + +#### UML diaghram +##### FoodSaveLoadManager#save() +![Alt text](save_load_feature/FoodSaveLoadManager_save.png) +##### FoodSaveLoadManager#load() +![Alt text](save_load_feature/FoodSaveLoadManager_load.png) +similiar diaghrams for PersonSaveLoadManager ## Product scope ### Target user profile From 1ce49482ae18a460eacda80c1983a0de9ecc370d Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Wed, 28 Oct 2020 22:19:55 +0800 Subject: [PATCH 228/271] Command recommend and editinfo a few bug fixes as well --- src/main/java/seedu/dietbook/Manager.java | 10 +- .../seedu/dietbook/checker/InputChecker.java | 2 +- .../dietbook/command/EditInfoCommand.java | 25 ++++ .../seedu/dietbook/command/InfoCommand.java | 1 - .../dietbook/command/RecommendCommand.java | 25 ++++ .../java/seedu/dietbook/parser/Parser.java | 120 +++++++++++++++--- 6 files changed, 164 insertions(+), 19 deletions(-) create mode 100644 src/main/java/seedu/dietbook/command/EditInfoCommand.java create mode 100644 src/main/java/seedu/dietbook/command/RecommendCommand.java diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 291497877e..da5f9f73e8 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -6,11 +6,13 @@ import seedu.dietbook.command.Command; import seedu.dietbook.command.DataCommand; import seedu.dietbook.command.DeleteCommand; +import seedu.dietbook.command.EditInfoCommand; import seedu.dietbook.command.ExitCommand; import seedu.dietbook.command.HelpCommand; import seedu.dietbook.command.InfoCommand; import seedu.dietbook.command.ListCommand; import seedu.dietbook.command.NameCommand; +import seedu.dietbook.command.RecommendCommand; import seedu.dietbook.command.UserinfoCommand; import seedu.dietbook.list.FoodList; import seedu.dietbook.person.ActivityLevel; @@ -21,8 +23,6 @@ import seedu.dietbook.exception.DietException; import seedu.dietbook.parser.Parser; -import java.util.Scanner; - /** * Manager class of the program. * The manager class takes in the checked and processed input and carry out the command specified. @@ -44,11 +44,13 @@ public class Manager { public static final String COMMAND_CLEAR = "clear"; public static final String COMMAND_DATA = "data"; public static final String COMMAND_DELETE = "delete"; + public static final String COMMAND_EDIT_INFO = "editinfo"; public static final String COMMAND_EXIT = "exit"; public static final String COMMAND_HELP = "help"; public static final String COMMAND_INFO = "info"; public static final String COMMAND_LIST = "list"; public static final String COMMAND_NAME = "name"; + public static final String COMMAND_RECOMMEND = "recommend"; public static final String COMMAND_USERINFO = "userinfo"; public Manager(FoodList foodlist, DataBase dataBase) { @@ -114,6 +116,8 @@ public Command manage(String userInput) throws DietException { return new DataCommand(); case COMMAND_DELETE: return new DeleteCommand(Parser.getCommandIndex(userInput)); + case COMMAND_EDIT_INFO: + return new EditInfoCommand(userInput); case COMMAND_EXIT: return new ExitCommand(); case COMMAND_HELP: @@ -124,6 +128,8 @@ public Command manage(String userInput) throws DietException { return new ListCommand(); case COMMAND_NAME: return new NameCommand(Parser.getCommandParam(userInput)); + case COMMAND_RECOMMEND: + return new RecommendCommand(getPerson()); case COMMAND_USERINFO: return new UserinfoCommand(); default: diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index a1b8edaf28..718b7a5f80 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -46,7 +46,7 @@ public static void checkEmpty(String userInput, String command) throws DietExcep */ public static void checkEmptyOption(String[] input) throws DietException { if (input.length > 1) { - if (input[1].length() > 1) { + if (input[1].trim().length() > 1) { if (input[1].trim().charAt(1) == '/') { throw new DietException("Error! Option specified with empty field!"); } diff --git a/src/main/java/seedu/dietbook/command/EditInfoCommand.java b/src/main/java/seedu/dietbook/command/EditInfoCommand.java new file mode 100644 index 0000000000..86bc326e3d --- /dev/null +++ b/src/main/java/seedu/dietbook/command/EditInfoCommand.java @@ -0,0 +1,25 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; +import seedu.dietbook.parser.Parser; + +public class EditInfoCommand extends Command { + String userInput; + + public EditInfoCommand(String userInput) { + this.userInput = userInput; + } + + @Override + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } + Parser.executeEditInfo(this.userInput, manager); + ui.printEditedPersonInfo(manager.getPerson().toString()); + } +} diff --git a/src/main/java/seedu/dietbook/command/InfoCommand.java b/src/main/java/seedu/dietbook/command/InfoCommand.java index 98defd4e61..ab6daae046 100644 --- a/src/main/java/seedu/dietbook/command/InfoCommand.java +++ b/src/main/java/seedu/dietbook/command/InfoCommand.java @@ -2,7 +2,6 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; -import seedu.dietbook.checker.InputChecker; import seedu.dietbook.exception.DietException; import seedu.dietbook.parser.Parser; diff --git a/src/main/java/seedu/dietbook/command/RecommendCommand.java b/src/main/java/seedu/dietbook/command/RecommendCommand.java new file mode 100644 index 0000000000..ae26da133f --- /dev/null +++ b/src/main/java/seedu/dietbook/command/RecommendCommand.java @@ -0,0 +1,25 @@ +package seedu.dietbook.command; + +import seedu.dietbook.Manager; +import seedu.dietbook.Ui; +import seedu.dietbook.exception.DietException; +import seedu.dietbook.person.Person; + +public class RecommendCommand extends Command { + Person person; + + public RecommendCommand(Person person) { + this.person = person; + } + + @Override + public void execute(Manager manager, Ui ui) throws DietException { + if (commandCount == 1) { + throw new DietException("Please enter your name first!"); + } else if (commandCount == 2) { + throw new DietException("Please enter your basic information first!"); + } + int recommendation = manager.getCalculator().calculateRecomendation(this.person); + ui.printCalorieRecommendation(this.person.getName(), recommendation); + } +} diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 99bfdcc386..4006612be4 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -15,13 +15,13 @@ */ public class Parser { - public static final String COMMAND_NAME = "name"; - public static final String COMMAND_INFO = "info"; public static final String COMMAND_ADD = "add"; public static final String COMMAND_CALCULATE = "calculate"; + public static final String COMMAND_EDIT_INFO = "editinfo"; + public static final String COMMAND_INFO = "info"; + public static final String COMMAND_NAME = "name"; public static final String[] PARAM_INFO = {"g/","a/","h/","l/","o/","t/","c/"}; - - + public static final String[] PARAM_EDIT_INFO = {"n/","g/","a/","h/","l/","o/","t/","c/"}; /** * Returns the command of a user input. @@ -33,6 +33,24 @@ public static String getCommand(String userInput) { return userInput.split(" ")[0]; } + /** + * Returns the index after the command of a user input, e.g. delete 3. + * + * @param userInput user input. + * @return index part of the user input. + * @throws DietException when the user input is of a wrong format. + */ + public static int getCommandIndex(String userInput) throws DietException { + String command = getCommand(userInput); + + InputChecker.checkEmpty(userInput, command); + try { + return Integer.parseInt(userInput.split(" ")[1]); + } catch (NumberFormatException e) { + throw new DietException("OOPS!!! No integer index detected!"); + } + } + /** * Returns the subsequent parameter after the command from the user input. * @@ -56,6 +74,8 @@ public static String getCommandParam(String userInput) throws DietException { case COMMAND_INFO: InputChecker.checkInfoParam(userInput); return userInput.substring(userInput.indexOf(' ') + 1); + case COMMAND_EDIT_INFO: + return userInput.substring(userInput.indexOf(' ') + 1); default: return null; } @@ -150,7 +170,7 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw InputChecker.checkGender(processGender); if (processGender.equals("F")) { gender = Gender.FEMALE; - } else { + } else if (processGender.equals("O")) { gender = Gender.OTHERS; } break; @@ -195,20 +215,90 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw } /** - * Returns the index after the command of a user input, e.g. delete 3. + * Processes the parameters for info command of user input and updates the Person object. * * @param userInput user input. - * @return index part of the user input. + * @param manager the manager object. * @throws DietException when the user input is of a wrong format. */ - public static int getCommandIndex(String userInput) throws DietException { - String command = getCommand(userInput); - - InputChecker.checkEmpty(userInput, command); - try { - return Integer.parseInt(userInput.split(" ")[1]); - } catch (NumberFormatException e) { - throw new DietException("OOPS!!! No integer index detected!"); + public static void executeEditInfo(String userInput, Manager manager) throws DietException { + Gender gender; + ActivityLevel actLvl; + String name; + int age; + int height; + int orgWeight; + int currWeight; + int tarWeight; + String trimmedParam; + String[] processedParam; + InputChecker.checkRepeatedOption(getCommand(userInput), getCommandParam(userInput)); + for (String param : PARAM_EDIT_INFO) { + if (getCommandParam(userInput).contains(param)) { + processedParam = getCommandParam(userInput).split(param); + InputChecker.checkEmptyOption(processedParam); + trimmedParam = processedParam[1].trim(); + if (processedParam[1].contains("/")) { + trimmedParam = processedParam[1].substring(0, processedParam[1].indexOf("/") - 2).trim(); + } + switch (param) { + case "g/": + String processGender = trimmedParam; + InputChecker.checkGender(processGender); + if (processGender.equals("F")) { + gender = Gender.FEMALE; + } else { + gender = Gender.OTHERS; + } + manager.getPerson().setGender(gender); + break; + case "n/": + name = trimmedParam; + manager.getPerson().setName(name); + break; + case "a/": + age = Integer.parseInt(trimmedParam); + InputChecker.checkAgeLimit(age); + manager.getPerson().setAge(age); + break; + case "h/": + height = Integer.parseInt(trimmedParam); + InputChecker.checkHeightLimit(height); + manager.getPerson().setHeight(height); + break; + case "o/": + orgWeight = Integer.parseInt(trimmedParam); + InputChecker.checkWeightLimit(orgWeight); + manager.getPerson().setOriginalWeight(orgWeight); + break; + case "c/": + currWeight = Integer.parseInt(trimmedParam); + InputChecker.checkWeightLimit(currWeight); + manager.getPerson().setCurrentWeight(currWeight); + break; + case "t/": + tarWeight = Integer.parseInt(trimmedParam); + InputChecker.checkWeightLimit(tarWeight); + manager.getPerson().setTargetWeight(tarWeight); + break; + default: + String processActLvl = trimmedParam; + InputChecker.checkActivity(processActLvl); + if (processActLvl.equals("1")) { + actLvl = ActivityLevel.NONE; + } else if (processActLvl.equals("2")) { + actLvl = ActivityLevel.LOW; + } else if (processActLvl.equals("3")) { + actLvl = ActivityLevel.MEDIUM; + } else if (processActLvl.equals("4")) { + actLvl = ActivityLevel.HIGH; + } else { + actLvl = ActivityLevel.EXTREME; + } + manager.getPerson().setActivityLevel(actLvl); + break; + } + } } } } From 9f088b8e2ca8ee2554fa55b53407ac755bbca6b2 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Wed, 28 Oct 2020 22:23:32 +0800 Subject: [PATCH 229/271] Update Parser.java --- src/main/java/seedu/dietbook/parser/Parser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 4006612be4..c52dc0c0d3 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -215,7 +215,8 @@ public static void executeProcessedInfo(String userInput, Manager manager) throw } /** - * Processes the parameters for info command of user input and updates the Person object. + * Processes the parameters for editinfo command of user input. + * The specified parameters are used to update the Person object. * * @param userInput user input. * @param manager the manager object. From 088746bc9b4bf4012c954eae0f6c7b474f496ed1 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Wed, 28 Oct 2020 22:53:21 +0800 Subject: [PATCH 230/271] Update help command output --- src/main/java/seedu/dietbook/Ui.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index c5ff4030ec..46932a6bde 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -696,8 +696,11 @@ private String getUserRelatedCommands() { * @return A string representation of a list of food list related commands that users can input. */ private String getFoodListRelatedCommands() { - return " To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] " - + "[p/PROTEIN] [f/FAT]" + LINE_SEPARATOR + return " To add a food not in the database that was just consumed: add x/PORTION_SIZE n/FOOD_NAME " + + "k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT]" + LINE_SEPARATOR + + " To add a food not in the database consumed at a certain time: add x/PORTION_SIZE " + + "n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT] yyyy-mm-ddTHH:mm" + + LINE_SEPARATOR + " To view all food in DietBook: list" + LINE_SEPARATOR + " To view all food in DietBook recorded within a time period: list yyyy-mm-ddTHH:mm " + "yyyy-mm-ddTHH:mm" + LINE_SEPARATOR @@ -714,6 +717,8 @@ private String getFoodListRelatedCommands() { */ private String getDatabaseRelatedCommands() { return " To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE" + LINE_SEPARATOR + + " To add a food from the database consumed at a certain time: add n/FOOD_NAME " + + "x/PORTION_SIZE yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + " To view all food in the database: data" + LINE_SEPARATOR; } From 81a6782a8bb7f05624afb31cfc27194a091bf8d1 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:40:11 +0800 Subject: [PATCH 231/271] Add Ui component --- docs/DeveloperGuide.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 5899b377f5..97c8cb3685 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,6 +1,19 @@ # Developer Guide -## Design & implementation +## Design + +### UI component +![Ui component](/UML/Ui component.png) + +**API**: [`Ui.java`](https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/Ui.java) + +The `UI` component, +* Takes in user command and passes to the `Logic` components for command execution. +* Updates the user about any changes in the data after executing the command or errors encountered when executing the commands. + +The UI has a dependency with two enumeration class, `ActivityLevel` and `Gender` as descriptions of each + `ActivityLevel` and `Gender` is required. Increased coupling was sacrificed to reduce code duplicates and increase ease of code extension/editing. + {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} ## Save/Load Feature From 79ab1d09ebb8b185efb2bb68d1eef636d14e7ce9 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:43:05 +0800 Subject: [PATCH 232/271] Add UML diagrams --- docs/diagrams/Enter Info Step2.drawio | 1 + docs/diagrams/Enter Info Step2.png | Bin 0 -> 21962 bytes docs/diagrams/Enter Info Step3.drawio | 1 + docs/diagrams/Enter Info Step3.png | Bin 0 -> 22375 bytes docs/diagrams/EnterInfoStep1.drawio | 1 + docs/diagrams/EnterInfoStep1.png | Bin 0 -> 22108 bytes docs/diagrams/Info sequence diagram.drawio | 1 + docs/diagrams/Info sequence diagram.png | Bin 0 -> 47732 bytes docs/diagrams/Name sequence diagram.drawio | 1 + docs/diagrams/Name sequence diagram.png | Bin 0 -> 18183 bytes docs/diagrams/Ui component.drawio | 1 + docs/diagrams/Ui component.png | Bin 0 -> 10992 bytes 12 files changed, 6 insertions(+) create mode 100644 docs/diagrams/Enter Info Step2.drawio create mode 100644 docs/diagrams/Enter Info Step2.png create mode 100644 docs/diagrams/Enter Info Step3.drawio create mode 100644 docs/diagrams/Enter Info Step3.png create mode 100644 docs/diagrams/EnterInfoStep1.drawio create mode 100644 docs/diagrams/EnterInfoStep1.png create mode 100644 docs/diagrams/Info sequence diagram.drawio create mode 100644 docs/diagrams/Info sequence diagram.png create mode 100644 docs/diagrams/Name sequence diagram.drawio create mode 100644 docs/diagrams/Name sequence diagram.png create mode 100644 docs/diagrams/Ui component.drawio create mode 100644 docs/diagrams/Ui component.png diff --git a/docs/diagrams/Enter Info Step2.drawio b/docs/diagrams/Enter Info Step2.drawio new file mode 100644 index 0000000000..80e41442e8 --- /dev/null +++ b/docs/diagrams/Enter Info Step2.drawio @@ -0,0 +1 @@ +7Vlbc6M2FP41nmkf0kFgbO8jjrPZ6SRNZrbTpI9aLANTQKwsO3Z/fXVHAuw4jjfrpLyA9OnoSOcmcQ6D4LLYXBNYpbd4jvKB7803g2A28H3gjyfsxZGtRIafgAQSks0VUQ18zf5FCvQUusrmaOkQUoxzmlUuGOOyRDF1MEgIfnLJFjh3V61gglrA1xjmbfQhm9NUopPQq/EvKEtSvTLw1EgBNbEClimc4ycLCq4GwSXBmMpWsblEOVee1ouc93nHqNkYQSU9ZMLjd7KIwj+36V/T5O5pXKX+H3cXvuSyhvlKCaw2S7daA6icR1yRrBfncLnM4kEwTWmRMwCwJtpk9NFq/83a3m+h6s24J3i6s9WdkpLtoyD0vIkG5EzgAw3Uk0XPmX2PSFYgiogC2+rQ7gJJgugeHYSSDs0dT1BKvEaYrUK2jOCptr82f2qZXmME5ZBma9d/oHLDxLAzK9zjjO3Y91TIGH9RAeOPPJfFEq9IjNQs294NRsGnBqMwcBlJxbQYsYYldg0Jd3qBa4UdrjXKmbKmleNgo+8rHgLTgm0nKwdBxEaH1YY9PespLOxRtKEXMM8SRRczYzMPMDxYK1FvsdICC420F+MDF0tx2nA+YMIX2cVlpYEKkSXmS9/Lhhpn6lk15zBMLt6CqyaWkibyvIJspUj8IkcLKgf3CqNVok9aTRe0p5SwQGKVGX+a4d9xykT3Zhg5UwT3ZQXLzs3HOMdEbo8k3+AvnmB5yUXpav1qpBOWWsAiy7dyeoFLzJaJUZeMYfMqCpnHclScs6anPTgUPsyQGW/z1UPupiGLhedogaHVh85RbPyajYwUM8IfXKkMUEYLtWI1jZRfE0h/Zr1IkEqftolEL7HaivuqMRBEt7BkFxuxiYQ4TUp3VO/SJvA7tu2L24P3QINujQgL8YOUbIaMfuujOuSHoKEc1/bwtpbmAwuXZ3vN3B5Th7wZHFpj7Cw1eGKt37S+6BoXsEHXMRVdy4PN6SEDzA3pPuj6oOuD7o2D7pu5tXkGoW9JcMT9fya3vdb4+5cEk4wxhvnDh5EoXhEeiB9HIJl7vEqeRprKT7GM5e2RzA5mFFc8NlVPSjDFjGqRi1x2kfF0RuxZVR2Ar/qf1cU3+4LyNeJc3Yx3Z6qpTtJ9SaTO8saN5Gyo+laSCXTmZ2eZQE/syiidFO6l+dr4hKUAltXrAoBM6r3RaH9BgHUOzuhlBvxuMvqwYevAa5jw0Iw+BDuc5o0y+snrPWSnTc/EVsPgRNWXpq0C8La2AqDDWEeXX/ZURo4triTMVXioR9eysaeWUn9qnV8Z5Tjhb6Obqxdddj9eoOeU/KLrVtXlzujCbZ2d/oEXbvMAONl9C7pq768OKxiz0y+j2xu0ZnlMEEVOf5+tW2H3ngLq5u6hj6efGU/mo8aKJz9403gafrwfDoUqCVnFoXf8y+E4pez6CwHjfxzivhTal0L7Umj//6EPuj7o/gdB1/l92XX/n/RD9NzqqLoCtq+MOjnNV+hAmc0q09QGC67+Aw== \ No newline at end of file diff --git a/docs/diagrams/Enter Info Step2.png b/docs/diagrams/Enter Info Step2.png new file mode 100644 index 0000000000000000000000000000000000000000..4d7c1acef13cf5d1f507e9e570251421fa88cc76 GIT binary patch literal 21962 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 literal 0 HcmV?d00001 diff --git a/docs/diagrams/Enter Info Step3.drawio b/docs/diagrams/Enter Info Step3.drawio new file mode 100644 index 0000000000..9af0567ab0 --- /dev/null +++ b/docs/diagrams/Enter Info Step3.drawio @@ -0,0 +1 @@ +7Vlbc9o4FP41zHQf0rFsDPTRhDSdTtJkpjub7KNqhNHUtlxhCN5fv7pbsoEApSl0/ALSp6Mjnas4h15wna1vKSzm92SK0p7vTde9YNLzfeAPR+yLI5VE+h+ABBKKp4qoBr7i/5ACPYUu8RQtHMKSkLTEhQvGJM9RXDoYpJS8uGQzkrqnFjBBLeBrDNM2+oSn5Vyio9Cr8U8IJ3N9MvDUSgY1sQIWczglLxYU3PSCa0pIKUfZ+hqlXHlaL3Lfxy2r5mIU5eU+G55/0FkU/l3N/xknDy/DYu5/ebjyJZcVTJdKYHXZstIaQPk04opksziFiwWOe8F4XmYpAwAbojUun63xv2zsvQ/VbMI9wdOTSk/yklbPgtDzRhqQO4EPNFBvFjNn9yOiOEMlogpsq0O7C6QJKnfoIJR0aOp4glLiLSLsFFoxgpfa/tr8c8v0GqMohSVeuf4DlRsmhp054ZFgdmPfUyFj/EUFjD/wXBYLsqQxUrtsezcYBR8ajMLAZSQV02LEBpbYNSTc6QDXCje41iBlyhoXjoMNfix5CIwzdh2c94KIrfaLNfv0rE9hYa9E6/IKpjhRdDEzNvMAw4ONEvUtTpoRoZH2YXzhaiGyDecDRvyQbVyWGigQXRB+9KMcqHWmnmVzD8Pk4S24aGJz2kReV5CtFIlfpWhWysWdwmiV6Eyr6YL2lhxmSJwy4Z9m+TOMvzvEgu+igPnGa8ckJVRejCbf4DtPMLvmQmwa/WXkEjaawQynldyekZywY2K0Sbqw+QiFzFc5KjKsmWnfDYX3MmTCx/z0kDtoyKLgNVpgaHW6OYqNX7ORMWJW+AdXKgOUuUKtWE0j5dcE0pPZLBKk0pttIjFLrLHivmwsBNE9zNmTRm0iIU6T0l3Vt7QJ/A3X9sW7wWegQbdClAX3Xko2S0a/dZIOefozlMPaHl5laT6wcJnVa+b2mkrvZrFvrbEsavDEOr9pfTE1LmCDrmMqupYHm7whA8wN5i7ouqDrgu6Ng+6bea957aDfR66hg5/+M3notcqVKGAYXq4shGLGGKZPrkyjCxYpXlIejH+QRLL0aAh0oNc1ylSeyzCr2yNZHUxKUvAIVTMpwpgwqlkqatkZ5uWMuLTqOgBfzT+q52/yCaUrxLm6Fe/WUlPl011FpK7yho3irK/mVpEJdOVnV5lAb9xUUTol3KH12vCErQBW1esGgCzqvcFgd0OATfau6GUFfDEVfdiwdeA1TLhvRR+CLU7zRhX96Oc9ZKtNz8RW/eBE3ZemrQLwtrYCYIOxjm6/7OiMHNtcSZir8FCPbuVgRy+l/sF1fm2U44S/j+5uDnrsfr1Aryn5oOdW9eXO6MFt5U5/zwe3mQBO9t6CTb33nw4rGLPsh8vqDq1YNRNEkTPfZetW2F1SQN09PHXx9DvjyfyoseLJD940nvp/3h8OmWoMWS2iC/7L4TildP9CdA3RriF6zg3RLui6oOuC7rf9C/HK+3/SH6Ln1kfVHbBdbdTRaX6F9pTZrDZNbbDg5n8= \ No newline at end of file diff --git a/docs/diagrams/Enter Info Step3.png b/docs/diagrams/Enter Info Step3.png new file mode 100644 index 0000000000000000000000000000000000000000..9b263c15233b0ba96f0ba9b6bd3de8b25ec1771d GIT binary patch literal 22375 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

?C`6>hWp#eU}! zu9V-YC^xaO06wU|SHX9g8<7k?J?NU5v`f^E7HAlfE z_8^#oCZgWnJuawqgh%=$sRWwr5z-ZZVDe+INMu(VNXW88!GE<*dQe>fu|GY7se%}# z6?}bfyS9851a%jQ5mFMrSd*_@3V%R5{AeE9>zjk9HF9Q{VLGz+%Xg$n5>3r$Fi>r<6lQ+C;(t~N(*?>b|LPBpar!us1&>l;&m(2-g@2(W zBZC4Q7zMrKgN@=(4a_AU#(DSIu8pwr{(qZJ3Nl0>Z+uf-!~h3^vhXJi-C!c=$6mfm z?-KM#axh|E+$-&VME+RE$CtO;kcA|n89a(sFx%r%D*10%C^O<6u6wm9OQJRe!qTl{ za_dHW4UmFrNec-rk;kY)b(Q0cBWBMym;Tt&x$sEAFW!dx9OC6KY%OhAjT`|{6r|L?>hY&3j@iL9D1g7q$L zFSg-3>#T;8!5cDVK$i;lj!lqMwM7is_gi^HFL$dbE$1?A@^-tzuh`Y0@B}wpWi>U~ zIcf6_cTqWaujMI~H>vFv!$dk4RrAG3(KQi9Z%0}>;5Pd@W0}h;l3Sg#C|xa890$OY zWk>PN_po7DogB|eDm`-#vZa00rQkr>xTQ~ghm05e+Z|Cx%a>a%b_Lvg+EspQD0V%% zwjz#zK7GzXv>&k}N9!P#ZA|!^6X?qHyYi>UU(kX5z@llb(MDD7W${Yl7X;U41@FeN zZ%5wWiT@c({#$K3r>&aeHST-oRODudrm#-KpJ_Q(vSI4ZJMz_X7(1S3-5?7JCXEdF z#c9gQsYtBFXn@hXRzA9$X-Ps&GS5Z59n2Lfw=0A@bnd}6k`6(vV5d$`=3440q6}sB z@oty}afRd|OHS|eY#ZAaJ!n7?yo>$CS*u^cBj1Pjvh&REupDTNb$+*?k(yXk=ETkxIVezNw% z`937TFaPkdu=jNlO=0?IEmQ#Ny+~LHnD6}*qSr}WnWf3PG(pU##KnFwvFVwy6()#o z?(5d{X$srnJTjv6tY$(=i$Kww*PGLP--_U_%3v|QYVVUs-Ack;Y^)jaM{9|BC3GiB zSN@68$MhfW&Ks-~&5P)n3YV1* z|M<1>$koJuI-A8IG?P@R;6KNM&9tRtm~aNt1*#o3Zb`ROv!6kQ0c2j6k7bpFi_bg> zBlTyAd)1W+f0la0prF_2SE&S^Vq@`3UZ7OMN@!|r{pi-(guy^r=j(B)x$|v#d4eAw z3zpXtKoF7uzDY*J;ii+Iq7268f?7kg@&-r``_@0 z=_7|C>B|atuYHnIGW;zIQ$ZzA(!}-}Hf*cGF4IRoY_7q6U50{8^IrFzP;ygNz5O3D zMU{;FlY5`FoICd0o>R;IR}+2WKYv=cZ4Oeo{JFWpl++Ch)^Z7oJ9OUPe3o-9GS{Qf zoXp5+VUIk5P}-)P3>@Ny9X zN6m8fpD0lmWofEZD_L#z>h94$?750(5;If;d_uLqZ&a5_E~tDF&Q0zo6Z&@ zOBAU)!S;!u%HiusL_ov&wlj})kyJ%R@G5HE{-aMIF<2jXC=I9oP!)tyq{(NKAT88x z2*SaZ0=f8ePLNM%2u7N|^QVT08aOXXcw1=(Y|g-LwT`ufr*OLSL(`Qmc!;}JDnKsh z`j*T^had%}H6%v;fT>+FsAM7XLDc8Tefxl$_yp6k0iN#31X0DY={N{f(p<~`b&i7M zDPn3Ul?Mp)zO)ZWUAGYgEWKw_VFz_@Dv_xPqU?M6eiF3Sn+~GT9=7=6Fe0!d4KsZ` zC=m2kp%x$kPXjQZw~hLeHaO7Q80;D-7gS}L!|EB5sy?L4H`W(cWs@;T7bJAv=>X(m zw3M0&V)3bn#Yebm18ZcyT$-H)qB!x44dF~95$FQj@}U@&1|@^K=&6vcTS0Gus3~E1 zs)!WksX5m9pdksm>VI>DmPF4?Q0a%~f9ej+tbdZE8YL>&p78FB7$GLJS_uA;ZJbGs I)_y7f2Lb(QV*mgE literal 0 HcmV?d00001 diff --git a/docs/diagrams/EnterInfoStep1.drawio b/docs/diagrams/EnterInfoStep1.drawio new file mode 100644 index 0000000000..b861d31b57 --- /dev/null +++ b/docs/diagrams/EnterInfoStep1.drawio @@ -0,0 +1 @@ +7VlLb+M2EP41BtpDCj0s2z3KcXYXRdIE2KJJj1yZlghIopamHbu/vsOnKMlxHMdNnEAXifw4HHJepGY0CC+LzVeGquyGznE+CLz5ZhDOBkHgB+MJvASyVUg01EDKyFwT1cB38i/WoKfRFZnjZYOQU5pzUjXBhJYlTngDQ4zRxybZgubNVSuU4g7wPUF5F70nc54pdBJ5Nf4NkzQzK/ueHimQIdbAMkNz+uhA4dUgvGSUctUqNpc4F8ozelHzvjwxajfGcMkPmfDwky3i6K9t9vc0vX0cV1nw5+1FoLisUb7SAuvN8q3RAC7nsVAk9JIcLZckGYTTjBc5AD408YbwB6f9D7S93yLdmwlP8ExnazolZ9sHSeh5EwOomX7gG6CeLHuN2XeYkQJzzDSo9o3nHXPW+jH+g1iK+R6lRNY64NaYwipsC/Mea/sb82eO6Q3GcI44WTe3gbQbppadXeGOEthg4OmQsf6iAyYYeU0WS7piCdazXHu3GIW/txhFYZOR0kOHETQcsWtIutMLXCva4VqjHJQ1rRoONvq5EiEwLWA7pByEMYwOqw08PecpLexxvOEXKCeppkvAtuABlge0Uv2WKy2o1Eh3MTFwsZSnjeDjT8QiT3FZGaDCbEnF0neqocdBPav2HMDU4h24amMZayPPK8hVisIvcrzganCvMEYl5qQ1dGF3SokKLFeZiacd/oNmILo3o7gxRXJfVqjcufmE5pSp7bH0B/rFkywvhSi7Wr9a6aSlFqgg+VZNL2hJYZkE75Ixal9FEXisQOU5a3vGgyPpw4DMRFusHgk3jSAWnqP1La05Y45iE9RsVKTYEfEQSgVAGy0yijU0Sn5DoPwZerEkVT7tEsle6rQ191VrIIxvUAkXG3OJpDhtyuao2aVLEOzYdiBvD9HzW3RrzCDED1KyHbL6rY/qSByClnJc28PbOpoPHVyd7TVzd0wf8nZw6IzBWWrx1Fm/bX3ZtS7ggk3H1HQdD7anhwqwZkj3QdcHXR90bxx0P+ytLTIIc0v6R9z/Z3LbG41/fEkoI8AY5fefRqJkxUQgfh6BVO7xKnlaaao4xQjk7bHKDmacViI2dU9JMKVAtchlLrsgIp2Re9ZVBz/Q/S/64pt9w/kaC67NjFcnNurY3JtsdpNIk+WNW8nZUPedJNM3mZ+bZfpm4q6MspHCvTRfG5+wFABZvSkAqKTeG432FwSgc3xGr1Lic83oo5atQ69lwkMz+sh/wmneKKOfvN5DDrXpe9lqGJ6o+tK2Vei/ra18/5Tllz2VkWOLKym4igj1+Ktq7Kml1J9a51dGOU74m/j66kWX3f8v0HNKftF1q+tyZ3Thds7O4MALt30AnOy+9XfV3l8dViiB04/w7TVeQx4TxnGjv8/WnbD7SAF1fXvfx9N7xpP9qHHiKQjfNJ6Gn++HQ6FLQk5x6AP/cjhOKf1fiL4g2hdEz78g2gddH3R90L3bX4hnvgJO+jl6btVUUwfbV0ydnOZbdKDN5hRraoOFV/8B \ No newline at end of file diff --git a/docs/diagrams/EnterInfoStep1.png b/docs/diagrams/EnterInfoStep1.png new file mode 100644 index 0000000000000000000000000000000000000000..f7b3fc05804081a9604ae2a1e2dbf2088269345d GIT binary patch literal 22108 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 AI{*Lx literal 0 HcmV?d00001 diff --git a/docs/diagrams/Info sequence diagram.drawio b/docs/diagrams/Info sequence diagram.drawio new file mode 100644 index 0000000000..3a9c45f381 --- /dev/null +++ b/docs/diagrams/Info sequence diagram.drawio @@ -0,0 +1 @@ +7VrbcuI4EP0aqrIPoXzHPAK5B3Yym9rNzLxsKbYCqjGWSxYB5uu3Zcv4IkMMY8/MbjYPQWrLknX6+HS3oGdOlptrhqLFjPo46Bmav+mZFz3DMDTTgA9h2aaWoeWkhjkjfmrSc8Mj+YalUZPWFfFxXBrIKQ04icpGj4Yh9njJhhij6/KwFxqUV43QHCuGRw8FqvWJ+HyRWl1by+03mMwX2cq6Jq8sUTZYGuIF8um6YDIve+aEUcrT1nIzwYEAL8Mlve9qz9XdgzEc8iY3fL3bRK/rraHPJ0/al5u7e+Pq/twYpNO8omAld9wzR7fhC53Q5RKFvnx2vs0AgW1EorlaBlPyggMSQm8cYUaWmGMGVwJpfsht4/WCcPwYIU/cugaqgG3BlwH0dGiC9ziCW9iuHwQoislzsqoGFoa9FYvJK/4DxylJhJWuuFhpsnO+MKrASKxeMeN4UzBJoK4xhedkWxgirw6lzyRpLUf21zkFdo5eFNxvZjciSbv5burcM9CQzjnGUa7qqKprCoBGlIQ8eQZ73LMvKh6ijC/onIYoKPpIxe0wZRqjaZfRdOvAVLE0Bp1hOVSwxBvgF8dnQHl4o1nPgJm1FflNwRj7IA+ym8N4mVuLtEYBmYfijcAvsKlxDPwn4Xya9C4AsDEO/ZEQKeg+B9T7KohOV6GPfcllcAXbfpLTJZ3Pe1l+0FscsTk+OFASTGzwoFMZDhCHF7EstTU+krc+CCoWyGCXyOBUnBzTFfOwvCf3M6CEtoVhkt97V3G1ulVy0qTz5RTa7e90VplanZQ+IBYLPr1HFbXcqozqDWVU6+rVN3XVST9HRnd0aQ5n+c3ZIfeGjrqdYWnsk9EHRj0cx9gXicQZgX8ik4NFZuI54FPsVFtAQx/ApsRGrlzR8LIGvMpXyaVAjO4ZDloKsofPcZRArEmhVgW64D0BLYFUbiRl+JlyTpf1sruX7m8KZ+bIN4Wz4KfMJ9+ppXolstqO0UhNlYlM/Y2JUhSUiVrTTlOhUsRgrduQcAJRNAaUaDgDToHTz1pzOt4QngTXviF7SXTtDw1T9i82WSAWnW2hU3jlD+tl6oM2Im/3BBpUxaIpgXRLc/pmea5qLtw1h6y6+PsneZ+xVzedSvAd2M2Cr23YXQUM+5cJvtaxeFaCr6nXoamCORh2heVx9WATVaQRhktjH8WLpP5IS47sTMYt6OW51tecsmK6g/YUsyKEDSQ0ZVbrtYrjDPv2sPBXFjjL7bsnxttKRVyV3a6lUi2AFfIUiOEFKI6JVxa8pt47GMbsOv1pKbRV5O/UyFY9CmroqmML1j2P21bFav199+HT5cd7+vGv8OZiNpn68e15TS1kjmbZCci/NGoqkl5D0r0q72YV6tEHf21UrLVOUousbmLmG7jtJ1DjelVvVq+aXSHp/GeQHDRDso3ko/Zp1WotxiK8xzQ8u0NQWiXHp9cQQjDrz0bTSzAIKIQ1qfhFw618JuV+2hx5IPyEb6f4FQf96Yenlst8JcFooBDtF1+26ZTc6lSZ3zhEVYKHMlF76UQtHdTCC1b7HS3brNSzc3Ctb5dOwtPKXXTzxDPpbYu9+tTz16SBXf3eo3mm4h6eqGMaHFfdtV+RWKWKZDDMKpRjK5JTaPGdHBjq+oFCw9G0UwsNRWM0/Ydyovbr5TRSKOR4Fxmmblgnnst0l2I2qAZ/WmI0OC4x+nGnMvVpnPod4P+Z0QlyaFQSGvvEkKgbrnV4ppP1D7r5b3fS4fkvoMzLfwA= \ No newline at end of file diff --git a/docs/diagrams/Info sequence diagram.png b/docs/diagrams/Info sequence diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7436835d40ada89e7b59a66c988946f0694a93a4 GIT binary patch literal 47732 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 literal 0 HcmV?d00001 diff --git a/docs/diagrams/Name sequence diagram.drawio b/docs/diagrams/Name sequence diagram.drawio new file mode 100644 index 0000000000..cb20efcdd5 --- /dev/null +++ b/docs/diagrams/Name sequence diagram.drawio @@ -0,0 +1 @@ +7VnZbptAFP0aS+lDIhZj40cvSdMsVdUoStu3CdzAyAODhnFs9+t7MYNZ7RA7TiK5fgn3MhvnHM5wJx1zHCy+ChL5t9wF1jE0d9ExJx3D0DW9h3+SzDLNdPtmmvAEdVWjPHFH/0LWU2Vn1IW41FByziSNykmHhyE4spQjQvB5udkTZ+VZI+JBLXHnEFbPPlBX+mnWtrQ8fwnU87OZdU3dCUjWWCVin7h8XkiZ5x1zLDiX6VWwGANLwMtwSftdbLi7XpiAULbpML1aRM/zpaF74wftz+XVtXFxfdpNR3kmbKYeuGMOv5MAxjwISOiqpctlhgc+RZRczgJ2Q5+A0RCjUQSCBiBB4B2m0j/y3GjuUwl3EXGSrnNUCuZ8GTCMdLxE8iTBLmIdM0aimD6uZtUwI8CZiZg+w0+IU40kWT6TyUzjNfdJUj0RCAmLjVDpawJQucBxnWKJTbIOfcWZEq2ecTjPJbAm2i/Qb2ZJomTnrcfOmcELRc4riNL1OlNVbgqIRpyGcrUGa9SxJhWKuJA+93hIWJGkVsBtVtFGNK0ymHYTlnUo9e7BoDRqUMIC9SXhBCWPL7ToGDiyNqNfahCDi+6gwhzF8zxblDVh1AuTNwKe8KFGMeqfht7NKpogYCMI3WHiURg+Mu5ME6HzWeiCq7SMsIvlLzXcKvhdUnmynLI3EuHBNqr0PTkVwIjE97BstA0Uqa4/EiEWtGCVtNCrcBzzmXBA9clpRpDIstBMqXvjLLbWNEuumXS8XEHr59tdVFaTkd5mcjpGEzW7Za71bIiPM9HeJ/ZQayuYVSy1diZqHcxD+zUoY5DJh8PJFXGmdeMs4JqgQ/ELa6js8ZFLyYNmO9xgcy1UWEAms4M9vQuFWSLByOTzgnvVBjIHLwyUunhtoLfyKt2ukRcJnGsYTy+4uI9BfAuf+C3EMbrX8fBpajvyab000KH5HDRtPvf0OPedrl3ddz784z1bwafceFL1tN557KZdvA5mf3AoLOuFkKd2nqNwKaNaF+2861QHOrBLGQ1nDXvyxSPAWyOXxP6qZEqrpOwUyU6iBZVJ/XSqnWldFa9KqLP+oKfiyUKZzypYFoLCC7at6Gqhiz1FYNqDM2tQ+JWZ7Ov4OIWftZtCalLr6++rkIYi6r9CWhbWxjaFmLb2JgqpFNam/c4W0qKAK5DvMBLH1Cl/rryJt1tbaq09iay4dO0YrC1VtTPMlnb/2rOWDevd8bAFw/xEPG2e/1/BPP8H \ No newline at end of file diff --git a/docs/diagrams/Name sequence diagram.png b/docs/diagrams/Name sequence diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..f2817b6f667d80c09f3a180a32e1e02cf47901ee GIT binary patch literal 18183 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 literal 0 HcmV?d00001 diff --git a/docs/diagrams/Ui component.drawio b/docs/diagrams/Ui component.drawio new file mode 100644 index 0000000000..261a6e6d9a --- /dev/null +++ b/docs/diagrams/Ui component.drawio @@ -0,0 +1 @@ +5VhNc5swEP01HJMxYPxxtJ00bcedpuPJND3KoIAagVwh29Bf35WRAAGJndQfh5zQPkkr6b2VtMJyZ3F2x9Eq+sYCTC2nF2SWe2M5ju0MR/CRSF4g/bFdACEngWpUAQvyFyuwp9A1CXBqNBSMUUFWJuizJMG+MDDEOduazZ4YNUddoRC3gIWPaBv9SQIRFejI61X4Z0zCSI9s91RNjHRjBaQRCti2Brm3ljvjjImiFGczTCV5mpei36cXasuJcZyIQzr8XtDvm+fl1/ns4YezSbf0/j68spU8G0TXasVqtiLXFHC2TgIsvfQsd7qNiMCLFfJl7RZEBywSMQXLhmJ7VmqiG8wFzmqQmuUdZjEWPIcmutZVjOUNe1sJ4GgBojr5mmqkRA9L3xUvUFDUvIGmQQdLAwrDTp8YrLNO1+DPmumKq3QXzxNoYI9WWVUJpVB+H4j2A9MqXBUVLRGOTPGoQfGwTbHdRXH/VAwPT8TwnIXEvwzJ7rhB8sBrkTzu4Ng7FccH7HWcBBN5aoLlU5SmwJ2xvYENnj/WjV/yXLj2tHmTqXOisHJtZUQ81sq1XmBVnaSh+7woQcrW3Mf7g0kgHmKxf1vjwLgD2oLWBOvaFBrjmCJBNubN0aWiGuGekV1oZ3pvmfFS2tpFsW7Vq37SNx15piO3GVEFMS1Hu6Aql/3+ONN392uBVospuaMI3LgTSsIEsCUTgsW7ECqDka0wVE0DlEa7m6gIP50vjF6Llr3q/qdsjjc2t/l7ZWs5Gp5ZNvsjyWaP+9eewXeZc75VuA5XozNL534k6Vz7aNJ1uDq3dF6HdMfIfKyZY01AsnWMObDNEglMp9r5kuuGEx+0ICKf4418vF0kH21cfaUI+/LRk+VK9qlS/oNluYPdhvll9HAGB+gxOKse45YeD19aLMDyhJmwpoKzZzxjlHFAEpZgKRShtAEhdRT6QBqw3j4jYxIEcpjOB7D5RD6GAM7+N3C/g/93vIDBrH5CFKda9SvHvf0H \ No newline at end of file diff --git a/docs/diagrams/Ui component.png b/docs/diagrams/Ui component.png new file mode 100644 index 0000000000000000000000000000000000000000..b2cc3b560f7b6e14401502b3a7a57afae4829e47 GIT binary patch literal 10992 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 Date: Thu, 29 Oct 2020 00:43:29 +0800 Subject: [PATCH 233/271] Add enter user information feature --- docs/DeveloperGuide.md | 78 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 97c8cb3685..dcbec5e82a 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -14,8 +14,84 @@ The `UI` component, The UI has a dependency with two enumeration class, `ActivityLevel` and `Gender` as descriptions of each `ActivityLevel` and `Gender` is required. Increased coupling was sacrificed to reduce code duplicates and increase ease of code extension/editing. - +## Implementation {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} + +### [Proposed] Enter user information feature + +#### Proposed Implementation +The proposed feature utilised two commands words [`name`](UserGuide.md/####Entering username: `name`) and [`info`](UserGuide.md/####Entering user information: `info`) that allows users to enter their name using the [`name`](UserGuide.md/####Entering username: `name`) command and [`info`](UserGuide.md/####Entering user information: `info`) to enter other information, such as age, gender, height, activity level, original, current and target weight, separately. + +The proposed feature to enter user information is facilitated by `Manager` which stores a`Person` which stores all user information provided. It implements the following operation: + +* Manager#setPerson(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, ActivityLevel newActivityLevel) - Calls the method below to set the attribute values of the `Person` object. +* Person#setAll(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, ActivityLevel newActivityLevel) - Updates the attribute values of the `Person` object. + +Both operation are only executed by the `Manager` class of the `Logic` component. Only one instance of `Person` is ever instantiated. A default person is instantiated at the start with default attribute values and when the user enters their information for the first time during the set up, all the default values would be updated to the inputted values. Therefore, the command to enter the user information will result in a change in the attribute values and not the creation of a new `Person` object. + +Given below is the example usage scenario and how the feature works. + +Step 1. When the user launches the application for the first time. A default `Person` object will be initialised by `Manager` and the user will be prompted to enter their name. + +![Enter Info Step1](/UML/Enter Info Step1.png) + +Step 2. The user executes `name Jack` command to enter their name into DietBook. The `name` command calls `Manager#setName(Jack)`, to store the name in `Manager` first. After which, user will be prompted to enter all other details. + +![Enter Info Step2](/UML/Enter Info Step2.png) + +Step 3. The user executes a command like the following `info g/M a/21 h/175 o/85 c/85 t/75 l/2` to enter all other personal information including age, gender, height, activity level, original, current and target weight. The `info` command then calls `Parse#executeProcessedInfo(info g/M a/21 h/175 o/85 c/85 t/75 l/2, manager)` which would parse the user command, check input validity by using methods in `InputChecker` and calls `Manager#setPerson(Jack, Gender.MALE, 21, 175, 85, 85, 75, ActivityLevel.LOW)` which proceeds to call `Person#setAll(Jack, Gender.MALE, 21, 175, 85, 85, 75, ActivityLevel.LOW)`. + +![Enter Info Step3](/UML/Enter Info Step3.png) + +The following sequence diagrams shows how the feature works. + +`name` command + +![Name sequence diagram](/UML/Name sequence diagram.png) + +`info` command + +![Info sequence diagram](/UML/Info sequence diagram.png) + +#### Design considerations: + +Aspect: Whether to enter name and other information separately or together + +* **Alternative 1 (current choice)**: Enter name and other information separately + * Pros: Increase user interaction and engagement. + * Cons: Enter information using two commands. + +* **Alternative 2**: Enter name and other information together + * Pros: Enter all information at once. + * Cons: Increase user interaction and engagement. + +Aspect: Whether to use singleton pattern for Person class + +* **Alternative 1 (current choice)**: Did not use singleton pattern for `Person` + * Pros: Reduce coupling and increase testability. + * Cons: Risk of creating multiple `Person` object by mistake and there might be negative consequence in + creating multiple objects. + + However, there is minimal risk of creating multiple `Person` object by mistake and minimal negative + consequence in creating multiple objects as long as the `Manager` refers the correct instance of + `Person`. + +* **Alternative 2**: Use singleton pattern for `Person` + * Pros: Easy to implement, prevent the instantiation of more than one `Person` object. + * Cons: Increase coupling and reduce testability + +Aspect: Changing attribute values in `Person` object or creating new `Person` object + +* **Alternative 1 (current choice)**: Changing attribute values in `Person` object + * Pros: Reduce the number of objects being created to reduce memory usage and reduce the risk of creating + multiple objects which can potentially lead to negative consequences and bugs. + * Cons: Unable to write tests as method chains. + +* **Alternative 2**: Creating new `Person` object + * Pros: Ability to write tests as method chains. + * Cons: Creation of many objects, which take up memory spaces and ensure that only the correct `Person + ` instance is kept and referred to. + ## Save/Load Feature The Save/Load feature is implemented by the saveload package. From 5fd07febd20abce67eae4a218c3e72e4e9f0a508 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:44:50 +0800 Subject: [PATCH 234/271] Update target user --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index dcbec5e82a..89972680d1 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -151,7 +151,7 @@ similiar diaghrams for PersonSaveLoadManager ## Product scope ### Target user profile -{Describe the target user profile} +NUS students living on campus who would like to track their daily food and nutritional intake. ### Value proposition From ab9aa11b6c19a5a945776c343248830a1a021a4d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:45:04 +0800 Subject: [PATCH 235/271] Update non functional requirements --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 89972680d1..b30a366acf 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -166,7 +166,7 @@ NUS students living on campus who would like to track their daily food and nutri ## Non-Functional Requirements -{Give non-functional requirements} +1. Should work on any mainstream OS as long as `Java 11` is installed in the system. ## Glossary From 465d6bb0d1bbc6185d4efc5760b0539f28002782 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:45:14 +0800 Subject: [PATCH 236/271] Update glossary --- docs/DeveloperGuide.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b30a366acf..3ba53963a1 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -170,8 +170,7 @@ NUS students living on campus who would like to track their daily food and nutri ## Glossary -* *glossary item* - Definition +* *Mainstream OD* - Windows, Linux, Unix, OS-X +* *Food items* - Includes both food and drinks ## 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} From a52a92211d996b3c758a9b7d192b488d0d04017e Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:24:46 +0800 Subject: [PATCH 237/271] Change minor formatting (cherry picked from commit a809fbe8f057d50b6bd11c85471d865641a51a2d) --- docs/UserGuide.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index f5988acfa2..b7194bcf52 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -11,18 +11,19 @@ DietBook is a desktop application targeting NUS students living on campus, optim 1. Download the latest version of `dietbook.jar` from [here](https://github.com/AY2021S1-CS2113-T14-4/tp/releases). 1. Copy the file to the folder you want to use as the home folder for your DietBook. 1. Either double-click the jar file to start the application or navigate to the folder containing the jar file on command prompt and run the command `java -jar dietbook.jar`. -1. For first time users: - 1. A CLI, similar to the one shown below, should appear within a few seconds. Follow the instructions provided to setup DietBook or refer to [name](#Entering username: `name`) and [info](#Entering user information: `info`) for more detailed explanations.
- ![DietBook Welcome Message](/images/DietBookWelcomeMessage.PNG) +1. For first time users:
+A CLI, similar to the one shown below, should appear within a few seconds. Follow the instructions + provided to setup DietBook or refer to [name](####Entering username: `name`) and [info](####Entering user information: `info`) for more detailed explanations.
+ [DietBook Welcome Message](/images/DietBookWelcomeMessage.PNG) 1. Start using DietBook by typing any valid command and pressing Enter to execute it. -1. Refer to the [Features](#Features) section below for more details of each command. +1. Refer to the [Features](##Features) section below for more details of each command. ## Features Notes about the command format: * Words in `UPPER_CASE` are parameters to be supplied by the user.
-e.g. For `delete INDEX`, `delete 1`would be a valid command. +e.g. For `delete INDEX`, `delete 1` would be a valid command. * Parameters in square brackets are optional. However, if all parameters are optional, at least one parameter needs to be given. In such cases, any one of the parameters would be valid.
e.g. For `add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT]`, `add x/1 n/Toast k/120`, `add x/1 n/Toast k/120 c/18`, `add x/1 n/Toast k/120 c/18 p/3`, `add x/1 n/Toast k/120 @@ -36,7 +37,7 @@ e.g. `help` is a valid command but `Help` is not.
e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` is valid but `add N/mee x/1` is not. * A single spacing to separate command words, parameters, command word and parameters is required.
-e.g. For `calculate all`, `calculate all` is valid but `calculateall` and `calculate`         `all`is not.
+e.g. For `calculate all`, `calculate all` is valid but `calculateall` and `calculate`         `all` is not.
e.g. For `delete INDEX`, `delete 1` is valid if there is a food item with index 1 but`delete1` is not.
e.g. For `add n/FOOD_NAME x/PORTION_SIZE`, `add n/mee x/1` is valid but `add n/meex/1` is not.
From fbabae001af5a0457d0a6f6477ab0596acfb9b1d Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:50:14 +0800 Subject: [PATCH 238/271] Improve markdown code quality --- docs/DeveloperGuide.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 3ba53963a1..f687c6a833 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -69,12 +69,9 @@ Aspect: Whether to use singleton pattern for Person class * **Alternative 1 (current choice)**: Did not use singleton pattern for `Person` * Pros: Reduce coupling and increase testability. - * Cons: Risk of creating multiple `Person` object by mistake and there might be negative consequence in - creating multiple objects. + * Cons: Risk of creating multiple `Person` object by mistake and there might be negative consequence in creating multiple objects. - However, there is minimal risk of creating multiple `Person` object by mistake and minimal negative - consequence in creating multiple objects as long as the `Manager` refers the correct instance of - `Person`. + However, there is minimal risk of creating multiple `Person` object by mistake and minimal negative consequence in creating multiple objects as long as the `Manager` refers the correct instance of `Person`. * **Alternative 2**: Use singleton pattern for `Person` * Pros: Easy to implement, prevent the instantiation of more than one `Person` object. @@ -83,14 +80,12 @@ Aspect: Whether to use singleton pattern for Person class Aspect: Changing attribute values in `Person` object or creating new `Person` object * **Alternative 1 (current choice)**: Changing attribute values in `Person` object - * Pros: Reduce the number of objects being created to reduce memory usage and reduce the risk of creating - multiple objects which can potentially lead to negative consequences and bugs. + * Pros: Reduce the number of objects being created to reduce memory usage and reduce the risk of creating multiple objects which can potentially lead to negative consequences and bugs. * Cons: Unable to write tests as method chains. * **Alternative 2**: Creating new `Person` object * Pros: Ability to write tests as method chains. - * Cons: Creation of many objects, which take up memory spaces and ensure that only the correct `Person - ` instance is kept and referred to. + * Cons: Creation of many objects, which take up memory spaces and ensure that only the correct `Person` instance is kept and referred to. ## Save/Load Feature From bc695d9e1f698bbc4b47ae8f9e62b56df09046bb Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 00:52:24 +0800 Subject: [PATCH 239/271] Add table of contents --- docs/DeveloperGuide.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f687c6a833..ae85bf8f04 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,5 +1,8 @@ # Developer Guide +* Table of Contents +{:toc} + ## Design ### UI component From c1bd39becfefd116a0122c04fce9b154efec7934 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 01:41:31 +0800 Subject: [PATCH 240/271] Update diagrams and links --- docs/DeveloperGuide.md | 18 +++++++++--------- docs/UserGuide.md | 5 ++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index ae85bf8f04..61bbe1b534 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -6,7 +6,7 @@ ## Design ### UI component -![Ui component](/UML/Ui component.png) +![Ui component](diagrams/Ui component.png) **API**: [`Ui.java`](https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/Ui.java) @@ -14,8 +14,7 @@ The `UI` component, * Takes in user command and passes to the `Logic` components for command execution. * Updates the user about any changes in the data after executing the command or errors encountered when executing the commands. -The UI has a dependency with two enumeration class, `ActivityLevel` and `Gender` as descriptions of each - `ActivityLevel` and `Gender` is required. Increased coupling was sacrificed to reduce code duplicates and increase ease of code extension/editing. +The UI has a dependency with two enumeration class, [`ActivityLevel`](https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/person/ActivityLevel.java) and [`Gender`](https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/person/Gender.java) as descriptions of each [`ActivityLevel`](https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/person/ActivityLevel.java) and [`Gender`](https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/person/Gender.java) is required. Increased coupling was sacrificed to reduce code duplicates and increase ease of code extension/editing. ## Implementation {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} @@ -25,7 +24,8 @@ The UI has a dependency with two enumeration class, `ActivityLevel` and `Gender` #### Proposed Implementation The proposed feature utilised two commands words [`name`](UserGuide.md/####Entering username: `name`) and [`info`](UserGuide.md/####Entering user information: `info`) that allows users to enter their name using the [`name`](UserGuide.md/####Entering username: `name`) command and [`info`](UserGuide.md/####Entering user information: `info`) to enter other information, such as age, gender, height, activity level, original, current and target weight, separately. -The proposed feature to enter user information is facilitated by `Manager` which stores a`Person` which stores all user information provided. It implements the following operation: +The proposed feature to enter user information is facilitated by `Manager` which stores a [`Person`](https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/person/Person.java) which + stores all user information provided. It implements the following operation: * Manager#setPerson(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, ActivityLevel newActivityLevel) - Calls the method below to set the attribute values of the `Person` object. * Person#setAll(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, ActivityLevel newActivityLevel) - Updates the attribute values of the `Person` object. @@ -36,25 +36,25 @@ Given below is the example usage scenario and how the feature works. Step 1. When the user launches the application for the first time. A default `Person` object will be initialised by `Manager` and the user will be prompted to enter their name. -![Enter Info Step1](/UML/Enter Info Step1.png) +![Enter Info Step1](diagrams/Enter Info Step1.png) Step 2. The user executes `name Jack` command to enter their name into DietBook. The `name` command calls `Manager#setName(Jack)`, to store the name in `Manager` first. After which, user will be prompted to enter all other details. -![Enter Info Step2](/UML/Enter Info Step2.png) +![Enter Info Step2](diagrams/Enter Info Step2.png) Step 3. The user executes a command like the following `info g/M a/21 h/175 o/85 c/85 t/75 l/2` to enter all other personal information including age, gender, height, activity level, original, current and target weight. The `info` command then calls `Parse#executeProcessedInfo(info g/M a/21 h/175 o/85 c/85 t/75 l/2, manager)` which would parse the user command, check input validity by using methods in `InputChecker` and calls `Manager#setPerson(Jack, Gender.MALE, 21, 175, 85, 85, 75, ActivityLevel.LOW)` which proceeds to call `Person#setAll(Jack, Gender.MALE, 21, 175, 85, 85, 75, ActivityLevel.LOW)`. -![Enter Info Step3](/UML/Enter Info Step3.png) +![Enter Info Step3](diagrams/Enter Info Step3.png) The following sequence diagrams shows how the feature works. `name` command -![Name sequence diagram](/UML/Name sequence diagram.png) +![Name sequence diagram](diagrams/Name sequence diagram.png) `info` command -![Info sequence diagram](/UML/Info sequence diagram.png) +![Info sequence diagram](diagrams/Info sequence diagram.png) #### Design considerations: diff --git a/docs/UserGuide.md b/docs/UserGuide.md index b7194bcf52..87ff008b0c 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -12,9 +12,8 @@ DietBook is a desktop application targeting NUS students living on campus, optim 1. Copy the file to the folder you want to use as the home folder for your DietBook. 1. Either double-click the jar file to start the application or navigate to the folder containing the jar file on command prompt and run the command `java -jar dietbook.jar`. 1. For first time users:
-A CLI, similar to the one shown below, should appear within a few seconds. Follow the instructions - provided to setup DietBook or refer to [name](####Entering username: `name`) and [info](####Entering user information: `info`) for more detailed explanations.
- [DietBook Welcome Message](/images/DietBookWelcomeMessage.PNG) +A CLI, similar to the one shown below, should appear within a few seconds. Follow the instructions provided to setup DietBook or refer to [name](####Entering username: `name`) and [info](####Entering user information: `info`) for more detailed explanations.
+![DietBook Welcome Message](images/DietBookWelcomeMessage.PNG) 1. Start using DietBook by typing any valid command and pressing Enter to execute it. 1. Refer to the [Features](##Features) section below for more details of each command. From 0b8c6c07c0fa07dfd1ae9fd5f34b82fa4910f6c8 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 02:03:50 +0800 Subject: [PATCH 241/271] Update file names --- ...nterInfoStep1.drawio => Enter Info Step1.drawio} | 0 .../{EnterInfoStep1.png => Enter Info Step1.png} | Bin 2 files changed, 0 insertions(+), 0 deletions(-) rename docs/diagrams/{EnterInfoStep1.drawio => Enter Info Step1.drawio} (100%) rename docs/diagrams/{EnterInfoStep1.png => Enter Info Step1.png} (100%) diff --git a/docs/diagrams/EnterInfoStep1.drawio b/docs/diagrams/Enter Info Step1.drawio similarity index 100% rename from docs/diagrams/EnterInfoStep1.drawio rename to docs/diagrams/Enter Info Step1.drawio diff --git a/docs/diagrams/EnterInfoStep1.png b/docs/diagrams/Enter Info Step1.png similarity index 100% rename from docs/diagrams/EnterInfoStep1.png rename to docs/diagrams/Enter Info Step1.png From d0ce85399532bb0d6361bff84ef57ba06610c52e Mon Sep 17 00:00:00 2001 From: HengFuYuen <60005925+HengFuYuen@users.noreply.github.com> Date: Thu, 29 Oct 2020 02:14:10 +0800 Subject: [PATCH 242/271] Set theme jekyll-theme-architect --- docs/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_config.yml b/docs/_config.yml index 2f7efbeab5..3397c9a492 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-minimal \ No newline at end of file +theme: jekyll-theme-architect \ No newline at end of file From 8024fdbc42d83bd6fb562e064a84c3d62ea2551b Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Thu, 29 Oct 2020 02:19:04 +0800 Subject: [PATCH 243/271] Remove static referencing Calculator and FoodList no longer reference each other via static method/variables. Instance of FoodList passed to calculator as a parameter for now. --- .../seedu/dietbook/calculator/Calculator.java | 48 +++++++++---------- .../java/seedu/dietbook/list/FoodList.java | 6 +-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/main/java/seedu/dietbook/calculator/Calculator.java b/src/main/java/seedu/dietbook/calculator/Calculator.java index e8304fe278..266ed0781a 100644 --- a/src/main/java/seedu/dietbook/calculator/Calculator.java +++ b/src/main/java/seedu/dietbook/calculator/Calculator.java @@ -54,10 +54,10 @@ public int calculateCalorie() { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateCalorie(LocalDateTime startTime) { + public int calculateCalorie(FoodList foodList, LocalDateTime startTime) { int calorie = 0; - for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { - calorie += FoodList.getFoodsAfterDateTime(startTime).get(i).getCalorie(); + for (int i = 0; i < foodList.getFoodsAfterDateTime(startTime).size(); i++) { + calorie += foodList.getFoodsAfterDateTime(startTime).get(i).getCalorie(); } return calorie; } @@ -72,10 +72,10 @@ public int calculateCalorie(LocalDateTime startTime) { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateCalorie(LocalDateTime startTime, LocalDateTime endTime) { + public int calculateCalorie(FoodList foodList, LocalDateTime startTime, LocalDateTime endTime) { int calorie = 0; - for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { - calorie += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getCalorie(); + for (int i = 0; i < foodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + calorie += foodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getCalorie(); } return calorie; } @@ -98,10 +98,10 @@ public int calculateCarb() { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateCarb(LocalDateTime startTime) { + public int calculateCarb(FoodList foodList, LocalDateTime startTime) { int carb = 0; - for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { - carb += FoodList.getFoodsAfterDateTime(startTime).get(i).getCarbohydrate(); + for (int i = 0; i < foodList.getFoodsAfterDateTime(startTime).size(); i++) { + carb += foodList.getFoodsAfterDateTime(startTime).get(i).getCarbohydrate(); } return carb; } @@ -116,10 +116,10 @@ public int calculateCarb(LocalDateTime startTime) { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateCarb(LocalDateTime startTime, LocalDateTime endTime) { + public int calculateCarb(FoodList foodList, LocalDateTime startTime, LocalDateTime endTime) { int carb = 0; - for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { - carb += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getCarbohydrate(); + for (int i = 0; i < foodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + carb += foodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getCarbohydrate(); } return carb; } @@ -142,10 +142,10 @@ public int calculateProtein() { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateProtein(LocalDateTime startTime) { + public int calculateProtein(FoodList foodList, LocalDateTime startTime) { int protein = 0; - for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { - protein += FoodList.getFoodsAfterDateTime(startTime).get(i).getProtein(); + for (int i = 0; i < foodList.getFoodsAfterDateTime(startTime).size(); i++) { + protein += foodList.getFoodsAfterDateTime(startTime).get(i).getProtein(); } return protein; } @@ -160,10 +160,10 @@ public int calculateProtein(LocalDateTime startTime) { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateProtein(LocalDateTime startTime, LocalDateTime endTime) { + public int calculateProtein(FoodList foodList, LocalDateTime startTime, LocalDateTime endTime) { int protein = 0; - for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { - protein += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getProtein(); + for (int i = 0; i < foodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + protein += foodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getProtein(); } return protein; } @@ -186,10 +186,10 @@ public int calculateFat() { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateFat(LocalDateTime startTime) { + public int calculateFat(FoodList foodList, LocalDateTime startTime) { int fat = 0; - for (int i = 0; i < FoodList.getFoodsAfterDateTime(startTime).size(); i++) { - fat += FoodList.getFoodsAfterDateTime(startTime).get(i).getFat(); + for (int i = 0; i < foodList.getFoodsAfterDateTime(startTime).size(); i++) { + fat += foodList.getFoodsAfterDateTime(startTime).get(i).getFat(); } return fat; } @@ -204,10 +204,10 @@ public int calculateFat(LocalDateTime startTime) { * @return the value of total calorie of food items with time after * startTime in foodList. */ - public int calculateFat(LocalDateTime startTime, LocalDateTime endTime) { + public int calculateFat(FoodList foodList, LocalDateTime startTime, LocalDateTime endTime) { int fat = 0; - for (int i = 0; i < FoodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { - fat += FoodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getFat(); + for (int i = 0; i < foodList.getFoodsInDateTimeRange(startTime, endTime).size(); i++) { + fat += foodList.getFoodsInDateTimeRange(startTime, endTime).get(i).getFat(); } return fat; } diff --git a/src/main/java/seedu/dietbook/list/FoodList.java b/src/main/java/seedu/dietbook/list/FoodList.java index 59a5dbabfb..fae627557c 100644 --- a/src/main/java/seedu/dietbook/list/FoodList.java +++ b/src/main/java/seedu/dietbook/list/FoodList.java @@ -13,7 +13,7 @@ * This is a stateful object. */ public class FoodList { - private static ArrayList foodEntries; + private ArrayList foodEntries; /** * Default constructor that instantiates FoodList with an empty foodentry arraylist. @@ -121,7 +121,7 @@ public List getPortionedFoods() { /** * Obtain list of foods consumed after specified timing. */ - public static List getFoodsAfterDateTime(LocalDateTime dateTime) { + public List getFoodsAfterDateTime(LocalDateTime dateTime) { List entriesAfterDateTime = FoodListManager.filterListByDate(foodEntries, dateTime); return FoodListManager.listToFoods(entriesAfterDateTime); } @@ -137,7 +137,7 @@ public List getPortionedFoodsAfterDateTime(LocalDateTime dateTime) { /** * Obtain list of foods consumed within the range of a specified timing. */ - public static List getFoodsInDateTimeRange(LocalDateTime start, LocalDateTime end) { + public List getFoodsInDateTimeRange(LocalDateTime start, LocalDateTime end) { List entriesInRange = FoodListManager.filterListByDate(foodEntries, start, end); return FoodListManager.listToFoods(entriesInRange); } From 1a58bc13e805b142b05284de13ff0ce51ffadc6f Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Thu, 29 Oct 2020 02:19:55 +0800 Subject: [PATCH 244/271] Delete Food.java in Test Redundant old file mistakenly added. Likely due to merge conflict resolution. --- src/test/java/seedu/dietbook/food/Food.java | 44 --------------------- 1 file changed, 44 deletions(-) delete mode 100644 src/test/java/seedu/dietbook/food/Food.java diff --git a/src/test/java/seedu/dietbook/food/Food.java b/src/test/java/seedu/dietbook/food/Food.java deleted file mode 100644 index 505588e82b..0000000000 --- a/src/test/java/seedu/dietbook/food/Food.java +++ /dev/null @@ -1,44 +0,0 @@ -package seedu.dietbook.food; - - -public class Food { - private final String name; - private final int calorie; - private final int carbohydrate; - private final int protein; - private final int fats; - - public Food(String name, int calorie, int carbohydrate, int protein, int fats) { - this.name = name; - this.calorie = calorie; - this.carbohydrate = carbohydrate; - this.protein = protein; - this.fats = fats; - } - - public int getFat() { - return fats; - } - - public String getName() { - return name; - } - - public int getCalorie() { - return calorie; - } - - public int getCarbohydrate() { - return carbohydrate; - } - - public int getProtein() { - return protein; - } - - @Override - public String toString() { - return name + " | calorie : " + calorie + " | protein : " + protein + " | carbohydrate : " + carbohydrate - + " | fats : " + fats; - } -} From 99f7e94d21526cb6654f50d8f1ce354f33f999d4 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 02:22:57 +0800 Subject: [PATCH 245/271] Add dataSuccessfullySavedMessage method --- src/main/java/seedu/dietbook/Ui.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index 89f861bbb1..b124ad381e 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -112,6 +112,13 @@ public void printInitialisationCompleteMessage() { print("Thank you! DietBook has been initialised " + getStartMessage()); } + /** + * Prints a message informing the user that DietBook has successfully saved all their data. + */ + public void dataSuccessfullySavedMessage() { + print("Your data has been saved successfully."); + } + /** * Prints the welcome back message when user reboots up DietBook after the first initialisation. From 61c0f212ae0cbf0bbdde7ec9074062f30411719c Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Thu, 29 Oct 2020 02:35:29 +0800 Subject: [PATCH 246/271] add toString version of datetime support methods -Tweak test method execution order for robustness of `LocalDateTime.now()` - add methods to fetch portion of list in string representation using dates. --- .../java/seedu/dietbook/list/FoodList.java | 22 +++++++++++++++++++ .../seedu/dietbook/list/FoodListTest.java | 15 +++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/list/FoodList.java b/src/main/java/seedu/dietbook/list/FoodList.java index fae627557c..3807882b12 100644 --- a/src/main/java/seedu/dietbook/list/FoodList.java +++ b/src/main/java/seedu/dietbook/list/FoodList.java @@ -158,6 +158,7 @@ public List getPortionSizes() { return FoodListManager.listToPortionSizes(foodEntries); } + /** * Obtain list of LocalDateTimes for when the entries were made. * (For storage purposes) @@ -171,4 +172,25 @@ public String toString() { return FoodListManager.listToString(foodEntries); } + /** + * Returns toString representation of the segmented list based on DateTime. + * @param dateTime Start DateTime. + * @return string representation of FoodList + */ + public String getAfterDateTimeToString(LocalDateTime dateTime) { + List entriesAfterDateTime = FoodListManager.filterListByDate(foodEntries, dateTime); + return FoodListManager.listToString(entriesAfterDateTime); + } + + /** + * Returns toString representation of the segmented list based on DateTime (within a range of 2 datetimes). + * @param start start DateTime. + * @param end end DateTime. + * @return string representation of FoodList + */ + public String getInDateTimeRangeToString(LocalDateTime start, LocalDateTime end) { + List entriesInRange = FoodListManager.filterListByDate(foodEntries, start, end); + return FoodListManager.listToString(entriesInRange); + } + } diff --git a/src/test/java/seedu/dietbook/list/FoodListTest.java b/src/test/java/seedu/dietbook/list/FoodListTest.java index 3b7325f856..a4072423f9 100644 --- a/src/test/java/seedu/dietbook/list/FoodListTest.java +++ b/src/test/java/seedu/dietbook/list/FoodListTest.java @@ -61,11 +61,14 @@ void dateComparisonTest() { @Test void dateFilterAfterTest() { + assertEquals(list.toString(), list.getAfterDateTimeToString(LocalDateTime.MIN)); + LocalDateTime timeNow = LocalDateTime.now(); assertTrue(list.getFoodsAfterDateTime(timeNow).size() == 0); - assertEquals(list.getFoodsAfterDateTime(LocalDateTime.MIN).toString(), - list.getFoods().toString()); + assertEquals(list.getFoods().toString(), + list.getFoodsAfterDateTime(LocalDateTime.MIN).toString()); + // add new entries: if (! LocalDateTime.now().isAfter(timeNow)) { // Execution is too fast that now() = timeNow. @@ -77,11 +80,17 @@ void dateFilterAfterTest() { } list.addFood(1, food); assertEquals(food.toString(), list.getFoodsAfterDateTime(timeNow).get(0).toString()); + } @Test void dateFilterRangeTest() { + + assertEquals(list.getPortionedFoods().toString(), + list.getPortionedFoodsInDateTimeRange(LocalDateTime.MIN, LocalDateTime.MAX).toString()); + assertEquals(list.toString(), list.getInDateTimeRangeToString(LocalDateTime.MIN, LocalDateTime.MAX)); + LocalDateTime timeNow = LocalDateTime.now(); if (! LocalDateTime.now().isAfter(timeNow)) { // Execution is too fast that now() = timeNow. @@ -95,8 +104,6 @@ void dateFilterRangeTest() { assertTrue(list.getFoodsInDateTimeRange(timeNow, LocalDateTime.MAX).size() == 0); - assertEquals(list.getPortionedFoods().toString(), - list.getPortionedFoodsInDateTimeRange(LocalDateTime.MIN, LocalDateTime.MAX).toString()); } @Test From 3ab299d47b89afb1dbef317efa1629bbc11fc254 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 29 Oct 2020 02:44:33 +0800 Subject: [PATCH 247/271] Feature Updates -command EditInfo -command recommend -add date time support for calculate --- src/main/java/seedu/dietbook/Manager.java | 2 +- .../seedu/dietbook/checker/InputChecker.java | 25 ++++ .../dietbook/command/CalculateCommand.java | 112 ++++++++++++++---- .../seedu/dietbook/command/ExitCommand.java | 46 +++++++ .../seedu/dietbook/command/ListCommand.java | 30 ++++- .../dietbook/command/UserinfoCommand.java | 1 - .../java/seedu/dietbook/parser/Parser.java | 2 + .../saveload/PersonSaveLoadManager.java | 2 +- 8 files changed, 196 insertions(+), 24 deletions(-) diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index da5f9f73e8..94f77807f2 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -125,7 +125,7 @@ public Command manage(String userInput) throws DietException { case COMMAND_INFO: return new InfoCommand(userInput); case COMMAND_LIST: - return new ListCommand(); + return new ListCommand(userInput); case COMMAND_NAME: return new NameCommand(Parser.getCommandParam(userInput)); case COMMAND_RECOMMEND: diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 718b7a5f80..43a0d8069a 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -1,6 +1,7 @@ package seedu.dietbook.checker; import seedu.dietbook.exception.DietException; +import seedu.dietbook.parser.Parser; /** * InputChecker class of the program. @@ -90,6 +91,18 @@ public static void checkAddParam(String userInput) throws DietException { } } + /** + * Takes in user input to check if the expected number of parameter is present for the calculate command. + * + * @param param parameter part of user input. + * @throws DietException when number of parameter is not as expected. + */ + public static void checkCalculateParam(String[] param) throws DietException { + if (param.length > 3) { + throw new DietException("Incorrect calculate statement"); + } + } + /** * Takes in user input to check if the expected number and type of parameter for the info command is present. * @@ -104,6 +117,18 @@ public static void checkInfoParam(String userInput) throws DietException { } } + /** + * Takes in user input to check if the expected number of parameter is present for the list command. + * + * @param param parameter part of user input. + * @throws DietException when number of parameter is not as expected. + */ + public static void checkList(String[] param) throws DietException { + if (param.length > 3) { + throw new DietException("Incorrect list statement"); + } + } + /** * Takes in an integer from food to check if the value is within the logical limit. * diff --git a/src/main/java/seedu/dietbook/command/CalculateCommand.java b/src/main/java/seedu/dietbook/command/CalculateCommand.java index 890aaa643f..feb2b44aaa 100644 --- a/src/main/java/seedu/dietbook/command/CalculateCommand.java +++ b/src/main/java/seedu/dietbook/command/CalculateCommand.java @@ -2,8 +2,12 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.calculator.Calculator; +import seedu.dietbook.checker.InputChecker; import seedu.dietbook.exception.DietException; +import java.time.LocalDateTime; + public class CalculateCommand extends Command { int calorie; int carb; @@ -21,32 +25,100 @@ public CalculateCommand(int calorie, int carb, int protein, int fat, String para @Override public void execute(Manager manager, Ui ui) throws DietException { + LocalDateTime startTime; + LocalDateTime endTime; + int calorie; + int carb; + int protein; + int fat; if (commandCount == 1) { throw new DietException("Please enter your name first!"); } else if (commandCount == 2) { throw new DietException("Please enter your basic information first!"); } manager.setCalculator(); - switch (this.param) { - case "all": - //ui.printAllIntakeAndFoods(); - //ui.printAllNutrientIntake(this.calorie, this.carb, this.protein, this.fat); - break; - case "calorie": - //ui.printCalorieIntakeAndFoods(); - //ui.printCalorieIntake(this.calorie); - break; - case "carbohydrate": - //ui.printCarbIntakeAndFoods(); - //ui.printCarbohydrateIntake(this.carb); - break; - case "protein": - //ui.printProteinIntakeAndFoods(); - //ui.printProteinIntake(this.protein); - break; - default: - //ui.printFatIntakeAndFoods(); - //ui.printFatIntake(this.fat); + String[] processedParam = this.param.split("\\s+"); + InputChecker.checkCalculateParam(processedParam); + try { + switch (processedParam[0]) { + case "all": + if (processedParam.length == 1) { + ui.printAllIntake(this.calorie, this.carb, this.protein, this.fat); + } else if (processedParam.length == 2) { + startTime = LocalDateTime.parse(processedParam[1]); + calorie = manager.getCalculator().calculateCalorie(startTime); + carb = manager.getCalculator().calculateCarb(startTime); + protein = manager.getCalculator().calculateProtein(startTime); + fat = manager.getCalculator().calculateFat(startTime); + ui.printAllIntake(calorie, carb, protein, fat, startTime); + } else if (processedParam.length == 3) { + startTime = LocalDateTime.parse(processedParam[1]); + endTime = LocalDateTime.parse(processedParam[2]); + calorie = manager.getCalculator().calculateCalorie(startTime, endTime); + carb = manager.getCalculator().calculateCarb(startTime, endTime); + protein = manager.getCalculator().calculateProtein(startTime, endTime); + fat = manager.getCalculator().calculateFat(startTime, endTime); + ui.printAllIntake(calorie, carb, protein, fat, startTime, endTime); + } + break; + case "calorie": + if (processedParam.length == 1) { + ui.printCalorieIntake(this.calorie); + } else if (processedParam.length == 2) { + startTime = LocalDateTime.parse(processedParam[1]); + calorie = manager.getCalculator().calculateCalorie(startTime); + ui.printCalorieIntake(calorie, startTime); + } else if (processedParam.length == 3) { + startTime = LocalDateTime.parse(processedParam[1]); + endTime = LocalDateTime.parse(processedParam[2]); + calorie = manager.getCalculator().calculateCalorie(startTime, endTime); + ui.printCalorieIntake(calorie, startTime, endTime); + } + break; + case "carbohydrate": + if (processedParam.length == 1) { + ui.printCarbIntake(this.carb); + } else if (processedParam.length == 2) { + startTime = LocalDateTime.parse(processedParam[1]); + carb = manager.getCalculator().calculateCarb(startTime); + ui.printCarbIntake(carb, startTime); + } else if (processedParam.length == 3) { + startTime = LocalDateTime.parse(processedParam[1]); + endTime = LocalDateTime.parse(processedParam[2]); + carb = manager.getCalculator().calculateCarb(startTime, endTime); + ui.printCarbIntake(carb, startTime, endTime); + } + break; + case "protein": + if (processedParam.length == 1) { + ui.printProteinIntake(this.protein); + } else if (processedParam.length == 2) { + startTime = LocalDateTime.parse(processedParam[1]); + protein = manager.getCalculator().calculateProtein(startTime); + ui.printProteinIntake(protein, startTime); + } else if (processedParam.length == 3) { + startTime = LocalDateTime.parse(processedParam[1]); + endTime = LocalDateTime.parse(processedParam[2]); + protein = manager.getCalculator().calculateProtein(startTime, endTime); + ui.printProteinIntake(protein, startTime, endTime); + } + break; + default: + if (processedParam.length == 1) { + ui.printFatIntake(this.fat); + } else if (processedParam.length == 2) { + startTime = LocalDateTime.parse(processedParam[1]); + fat = manager.getCalculator().calculateFat(startTime); + ui.printFatIntake(fat, startTime); + } else if (processedParam.length == 3) { + startTime = LocalDateTime.parse(processedParam[1]); + endTime = LocalDateTime.parse(processedParam[2]); + fat = manager.getCalculator().calculateFat(startTime, endTime); + ui.printFatIntake(fat, startTime, endTime); + } + } + } catch (Exception e) { + throw new DietException("Wrong date time format! (Format: yyyy-mm-ddTHH:mm)"); } } } diff --git a/src/main/java/seedu/dietbook/command/ExitCommand.java b/src/main/java/seedu/dietbook/command/ExitCommand.java index 31b14601e7..c1d4eddb4a 100644 --- a/src/main/java/seedu/dietbook/command/ExitCommand.java +++ b/src/main/java/seedu/dietbook/command/ExitCommand.java @@ -3,11 +3,57 @@ import seedu.dietbook.DietBook; import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.person.ActivityLevel; +import seedu.dietbook.person.Gender; +import seedu.dietbook.saveload.PersonSaveLoadManager; +import seedu.dietbook.saveload.FoodSaveLoadManager; public class ExitCommand extends Command { + PersonSaveLoadManager personSave; + FoodSaveLoadManager foodSave; + + public ExitCommand() { + this.personSave = new PersonSaveLoadManager(); + this.foodSave = new FoodSaveLoadManager(); + } + @Override public void execute(Manager manager, Ui ui) { ui.printExitMessage(); + ActivityLevel actLvl = manager.getPerson().getActivityLevel(); + int actLvlInt = 1; + if (actLvl.equals(ActivityLevel.NONE)) { + actLvlInt = 1; + } else if (actLvl.equals(ActivityLevel.LOW)) { + actLvlInt = 2; + } else if (actLvl.equals(ActivityLevel.MEDIUM)) { + actLvlInt = 3; + } else if (actLvl.equals(ActivityLevel.HIGH)) { + actLvlInt = 4; + } else if (actLvl.equals(ActivityLevel.EXTREME)) { + actLvlInt = 5; + } + + Gender gender = manager.getPerson().getGender(); + String genderString = "Male"; + if (gender.equals(Gender.MALE)) { + genderString = "Male"; + } else if (gender.equals(Gender.FEMALE)) { + genderString = "Female"; + } else { + genderString = "Others"; + } + + personSave.setActivityLevel(actLvlInt); + personSave.setAge(manager.getPerson().getAge()); + personSave.setCurrentWeight(manager.getPerson().getCurrentWeight()); + personSave.setGender(genderString); + personSave.setHeight(manager.getPerson().getHeight()); + personSave.setName(manager.getPerson().getName()); + personSave.setOriginalWeight(manager.getPerson().getOriginalWeight()); + personSave.setTargetWeight(manager.getPerson().getTargetWeight()); + personSave.save("resources/UserInfo.txt"); + foodSave.save("resources/FoodList.txt", manager.getFoodList().getFoods()); DietBook.isExit = true; } } diff --git a/src/main/java/seedu/dietbook/command/ListCommand.java b/src/main/java/seedu/dietbook/command/ListCommand.java index d3e7e44541..6f11e58c90 100644 --- a/src/main/java/seedu/dietbook/command/ListCommand.java +++ b/src/main/java/seedu/dietbook/command/ListCommand.java @@ -2,16 +2,44 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; +import seedu.dietbook.checker.InputChecker; import seedu.dietbook.exception.DietException; +import java.time.LocalDateTime; + public class ListCommand extends Command { + String userInput; + + public ListCommand(String userInput) { + this.userInput = userInput; + } + @Override public void execute(Manager manager, Ui ui) throws DietException { + LocalDateTime startTime; + LocalDateTime endTime; if (commandCount == 1) { throw new DietException("Please enter your name first!"); } else if (commandCount == 2) { throw new DietException("Please enter your basic information first!"); } - ui.printFoodList(manager.getFoodList().toString()); + String[] processedInput = this.userInput.split("\\s+"); + InputChecker.checkList(processedInput); + if (processedInput.length == 1) { + ui.printFoodList(manager.getFoodList().toString()); + } else { + try { + if (processedInput.length == 2) { + startTime = LocalDateTime.parse(processedInput[1]); + ui.printFoodList(manager.getFoodList().toString(), startTime); + } else if (processedInput.length == 3) { + startTime = LocalDateTime.parse(processedInput[1]); + endTime = LocalDateTime.parse(processedInput[2]); + ui.printFoodList(manager.getFoodList().toString(), startTime, endTime); + } + } catch (Exception e) { + throw new DietException("Wrong date time format! (Format: yyyy-mm-ddTHH:mm)"); + } + } } } diff --git a/src/main/java/seedu/dietbook/command/UserinfoCommand.java b/src/main/java/seedu/dietbook/command/UserinfoCommand.java index fe2bb1f786..f7892f1d02 100644 --- a/src/main/java/seedu/dietbook/command/UserinfoCommand.java +++ b/src/main/java/seedu/dietbook/command/UserinfoCommand.java @@ -4,7 +4,6 @@ import seedu.dietbook.Ui; import seedu.dietbook.exception.DietException; -import java.io.DataInput; public class UserinfoCommand extends Command { @Override diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index c52dc0c0d3..1c3fb02f38 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -7,6 +7,8 @@ import seedu.dietbook.Manager; import seedu.dietbook.checker.InputChecker; +import java.time.LocalDateTime; + /** * Parser class of the program. * The parser class takes in user input and process it into command data that manager can use. diff --git a/src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java b/src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java index d0650997f8..996dddfe7b 100644 --- a/src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java +++ b/src/main/java/seedu/dietbook/saveload/PersonSaveLoadManager.java @@ -101,7 +101,7 @@ public void save(String fileName) { this.saver.add(Integer.toString(this.originalWeight), ORIGINAL_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW); this.saver.add(Integer.toString(this.currentWeight), CURRENT_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW); this.saver.add(Integer.toString(this.targetWeight), TARGET_WEIGHT_ENTRY_INDEX, PERSON_DATA_ROW); - this.saver.add(Integer.toString(this.currentWeight), ACTIVITY_LEVEL_ENTRY_INDEX, PERSON_DATA_ROW); + this.saver.add(Integer.toString(this.activityLevel), ACTIVITY_LEVEL_ENTRY_INDEX, PERSON_DATA_ROW); this.saver.save(PERSON_FOLDER_NAME, fileName); } From ad5424ddde06dca5506c8f489e153a39eff2327c Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 29 Oct 2020 07:25:48 +0800 Subject: [PATCH 248/271] Database Printing --- src/main/java/seedu/dietbook/DietBook.java | 72 ++++++++++++++++++- src/main/java/seedu/dietbook/Manager.java | 6 ++ .../dietbook/command/CalculateCommand.java | 32 ++++----- .../seedu/dietbook/command/DataCommand.java | 2 +- .../seedu/dietbook/command/ExitCommand.java | 9 +-- .../seedu/dietbook/command/ListCommand.java | 6 +- .../java/seedu/dietbook/parser/Parser.java | 8 +++ 7 files changed, 110 insertions(+), 25 deletions(-) diff --git a/src/main/java/seedu/dietbook/DietBook.java b/src/main/java/seedu/dietbook/DietBook.java index 6d78746e80..6a512a954d 100644 --- a/src/main/java/seedu/dietbook/DietBook.java +++ b/src/main/java/seedu/dietbook/DietBook.java @@ -4,6 +4,10 @@ import seedu.dietbook.list.FoodList; import seedu.dietbook.exception.DietException; import seedu.dietbook.command.Command; +import seedu.dietbook.person.ActivityLevel; +import seedu.dietbook.person.Gender; +import seedu.dietbook.saveload.FoodSaveLoadManager; +import seedu.dietbook.saveload.PersonSaveLoadManager; /** * Main class of the program. @@ -12,6 +16,7 @@ * @author tikimonarch */ +import java.io.File; import java.io.FileNotFoundException; public class DietBook { @@ -19,6 +24,8 @@ public class DietBook { private Ui ui; private Manager manager; private DataBase dataBase; + private PersonSaveLoadManager loadPerson; + private FoodSaveLoadManager loadFood; public static boolean isExit = false; /** @@ -26,17 +33,78 @@ public class DietBook { */ public DietBook() { ui = new Ui(); + loadFood = new FoodSaveLoadManager(); + loadPerson = new PersonSaveLoadManager(); foodList = new FoodList(); dataBase = new DataBase(); manager = new Manager(foodList, dataBase); - } + } + + /** + * Method to load Person data. + */ + public void loadPerson() { + try { + loadPerson.load("resources/UserInfo.txt"); + ActivityLevel actLvl = ActivityLevel.NONE; + int actLvlInt = loadPerson.getActivityLevel(); + if (actLvlInt == 1) { + actLvl = ActivityLevel.NONE; + } else if (actLvlInt == 2) { + actLvl = ActivityLevel.LOW; + } else if (actLvlInt == 3) { + actLvl = ActivityLevel.MEDIUM; + } else if (actLvlInt == 4) { + actLvl = ActivityLevel.HIGH; + } else if (actLvlInt == 5) { + actLvl = ActivityLevel.EXTREME; + } + + Gender gender; + String genderString = loadPerson.getGender(); + if (genderString.equals("Male")) { + gender = Gender.MALE; + } else if (genderString.equals("Female")) { + gender = Gender.FEMALE; + } else { + gender = Gender.OTHERS; + } + manager.getPerson().setAll(loadPerson.getName(), gender, loadPerson.getAge(), + loadPerson.getHeight(), loadPerson.getOriginalWeight(), loadPerson.getCurrentWeight(), + loadPerson.getTargetWeight(), actLvl); + + } catch (FileNotFoundException e) { + ui.printErrorMessage("Person data file not found!"); + } catch (IllegalAccessException e) { + ui.printErrorMessage(e.getMessage()); + } + } + + /** + * Method to load DietBook FoodList data. + */ + public void loadFood() { + try { + loadFood.load("resources/UserInfo.txt"); + loadFood.getFoodList(); + //foodList = new FoodList(loadFood.getFoodList()); + ui.printWelcomeBackMessage(manager.getPerson().getName()); + } catch (FileNotFoundException e) { + ui.printErrorMessage("FoodList data file not found!"); + } catch (IllegalAccessException e) { + ui.printErrorMessage(e.getMessage()); + } + + } /** * Main method to run the program. */ - public static void main(String[] args) throws FileNotFoundException { + public static void main(String[] args) { DietBook dietBook = new DietBook(); dietBook.ui.printWelcomeMessage(); + //dietBook.loadPerson(); + //dietBook.loadFood(); while (!isExit) { try { diff --git a/src/main/java/seedu/dietbook/Manager.java b/src/main/java/seedu/dietbook/Manager.java index 94f77807f2..dacedc03f1 100644 --- a/src/main/java/seedu/dietbook/Manager.java +++ b/src/main/java/seedu/dietbook/Manager.java @@ -23,6 +23,8 @@ import seedu.dietbook.exception.DietException; import seedu.dietbook.parser.Parser; +import java.util.ArrayList; + /** * Manager class of the program. * The manager class takes in the checked and processed input and carry out the command specified. @@ -66,6 +68,10 @@ public FoodList getFoodList() { return this.foodList; } + public void setFoodList(FoodList foodList) { + this.foodList = foodList; + } + public Person getPerson() { return this.person; } diff --git a/src/main/java/seedu/dietbook/command/CalculateCommand.java b/src/main/java/seedu/dietbook/command/CalculateCommand.java index feb2b44aaa..5b767ad184 100644 --- a/src/main/java/seedu/dietbook/command/CalculateCommand.java +++ b/src/main/java/seedu/dietbook/command/CalculateCommand.java @@ -46,18 +46,18 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printAllIntake(this.calorie, this.carb, this.protein, this.fat); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); - calorie = manager.getCalculator().calculateCalorie(startTime); - carb = manager.getCalculator().calculateCarb(startTime); - protein = manager.getCalculator().calculateProtein(startTime); - fat = manager.getCalculator().calculateFat(startTime); + calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime); + carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime); + protein = manager.getCalculator().calculateProtein(manager.getFoodList(), startTime); + fat = manager.getCalculator().calculateFat(manager.getFoodList(), startTime); ui.printAllIntake(calorie, carb, protein, fat, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); endTime = LocalDateTime.parse(processedParam[2]); - calorie = manager.getCalculator().calculateCalorie(startTime, endTime); - carb = manager.getCalculator().calculateCarb(startTime, endTime); - protein = manager.getCalculator().calculateProtein(startTime, endTime); - fat = manager.getCalculator().calculateFat(startTime, endTime); + calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime, endTime); + carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime, endTime); + protein = manager.getCalculator().calculateProtein(manager.getFoodList(), startTime, endTime); + fat = manager.getCalculator().calculateFat(manager.getFoodList(), startTime, endTime); ui.printAllIntake(calorie, carb, protein, fat, startTime, endTime); } break; @@ -66,12 +66,12 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printCalorieIntake(this.calorie); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); - calorie = manager.getCalculator().calculateCalorie(startTime); + calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime); ui.printCalorieIntake(calorie, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); endTime = LocalDateTime.parse(processedParam[2]); - calorie = manager.getCalculator().calculateCalorie(startTime, endTime); + calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime, endTime); ui.printCalorieIntake(calorie, startTime, endTime); } break; @@ -80,12 +80,12 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printCarbIntake(this.carb); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); - carb = manager.getCalculator().calculateCarb(startTime); + carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime); ui.printCarbIntake(carb, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); endTime = LocalDateTime.parse(processedParam[2]); - carb = manager.getCalculator().calculateCarb(startTime, endTime); + carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime, endTime); ui.printCarbIntake(carb, startTime, endTime); } break; @@ -94,12 +94,12 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printProteinIntake(this.protein); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); - protein = manager.getCalculator().calculateProtein(startTime); + protein = manager.getCalculator().calculateProtein(manager.getFoodList(), startTime); ui.printProteinIntake(protein, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); endTime = LocalDateTime.parse(processedParam[2]); - protein = manager.getCalculator().calculateProtein(startTime, endTime); + protein = manager.getCalculator().calculateProtein(manager.getFoodList(), startTime, endTime); ui.printProteinIntake(protein, startTime, endTime); } break; @@ -108,12 +108,12 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printFatIntake(this.fat); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); - fat = manager.getCalculator().calculateFat(startTime); + fat = manager.getCalculator().calculateFat(manager.getFoodList(), startTime); ui.printFatIntake(fat, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); endTime = LocalDateTime.parse(processedParam[2]); - fat = manager.getCalculator().calculateFat(startTime, endTime); + fat = manager.getCalculator().calculateFat(manager.getFoodList(), startTime, endTime); ui.printFatIntake(fat, startTime, endTime); } } diff --git a/src/main/java/seedu/dietbook/command/DataCommand.java b/src/main/java/seedu/dietbook/command/DataCommand.java index a5a708d898..1171366dbd 100644 --- a/src/main/java/seedu/dietbook/command/DataCommand.java +++ b/src/main/java/seedu/dietbook/command/DataCommand.java @@ -14,6 +14,6 @@ public void execute(Manager manager, Ui ui) throws DietException { throw new DietException("Please enter your basic information first!"); } manager.getDataBase().init(); - //ui.printDatabase(manager.getDataBase().getFoodList()); + ui.printDatabase(manager.getDataBase().getFoodListString()); } } diff --git a/src/main/java/seedu/dietbook/command/ExitCommand.java b/src/main/java/seedu/dietbook/command/ExitCommand.java index c1d4eddb4a..1d3897d831 100644 --- a/src/main/java/seedu/dietbook/command/ExitCommand.java +++ b/src/main/java/seedu/dietbook/command/ExitCommand.java @@ -19,7 +19,6 @@ public ExitCommand() { @Override public void execute(Manager manager, Ui ui) { - ui.printExitMessage(); ActivityLevel actLvl = manager.getPerson().getActivityLevel(); int actLvlInt = 1; if (actLvl.equals(ActivityLevel.NONE)) { @@ -35,7 +34,7 @@ public void execute(Manager manager, Ui ui) { } Gender gender = manager.getPerson().getGender(); - String genderString = "Male"; + String genderString; if (gender.equals(Gender.MALE)) { genderString = "Male"; } else if (gender.equals(Gender.FEMALE)) { @@ -52,8 +51,10 @@ public void execute(Manager manager, Ui ui) { personSave.setName(manager.getPerson().getName()); personSave.setOriginalWeight(manager.getPerson().getOriginalWeight()); personSave.setTargetWeight(manager.getPerson().getTargetWeight()); - personSave.save("resources/UserInfo.txt"); - foodSave.save("resources/FoodList.txt", manager.getFoodList().getFoods()); + personSave.save("UserInfo.txt"); + foodSave.save("FoodList.txt", manager.getFoodList().getFoods()); + ui.dataSuccessfullySavedMessage(); DietBook.isExit = true; + ui.printExitMessage(); } } diff --git a/src/main/java/seedu/dietbook/command/ListCommand.java b/src/main/java/seedu/dietbook/command/ListCommand.java index 6f11e58c90..9cd41a26bd 100644 --- a/src/main/java/seedu/dietbook/command/ListCommand.java +++ b/src/main/java/seedu/dietbook/command/ListCommand.java @@ -4,6 +4,7 @@ import seedu.dietbook.Ui; import seedu.dietbook.checker.InputChecker; import seedu.dietbook.exception.DietException; +import seedu.dietbook.list.FoodList; import java.time.LocalDateTime; @@ -18,6 +19,7 @@ public ListCommand(String userInput) { public void execute(Manager manager, Ui ui) throws DietException { LocalDateTime startTime; LocalDateTime endTime; + FoodList foodList = manager.getFoodList(); if (commandCount == 1) { throw new DietException("Please enter your name first!"); } else if (commandCount == 2) { @@ -31,11 +33,11 @@ public void execute(Manager manager, Ui ui) throws DietException { try { if (processedInput.length == 2) { startTime = LocalDateTime.parse(processedInput[1]); - ui.printFoodList(manager.getFoodList().toString(), startTime); + ui.printFoodList(foodList.getAfterDateTimeToString(startTime), startTime); } else if (processedInput.length == 3) { startTime = LocalDateTime.parse(processedInput[1]); endTime = LocalDateTime.parse(processedInput[2]); - ui.printFoodList(manager.getFoodList().toString(), startTime, endTime); + ui.printFoodList(foodList.getInDateTimeRangeToString(startTime,endTime), startTime, endTime); } } catch (Exception e) { throw new DietException("Wrong date time format! (Format: yyyy-mm-ddTHH:mm)"); diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 1c3fb02f38..3e0c4db12c 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -1,5 +1,7 @@ package seedu.dietbook.parser; +import seedu.dietbook.database.DataBase; +import seedu.dietbook.food.Food; import seedu.dietbook.list.FoodList; import seedu.dietbook.person.Gender; import seedu.dietbook.person.ActivityLevel; @@ -100,6 +102,7 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws int protein = -1; int fat = -1; String trimmedParam; + //String[] databaseCheck = getCommandParam(userInput).trim().split("/");; String[] processedParam; String[] paramList = {"x/", "n/", "k/", "c/", "p/", "f/"}; InputChecker.checkRepeatedOption(getCommand(userInput), getCommandParam(userInput)); @@ -138,6 +141,11 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws } } } + //if (databaseCheck.length == 3) { + // DataBase dataBase = new DataBase(); + // Food searchedFood = dataBase.searchFoodByName(foodName); + // return foodList.addFood(portionSize, searchedFood); + //} return foodList.addFood(portionSize, foodName, calorie, carb, protein, fat); } From a13a65844cde172d757517c48e892321437b00d1 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 29 Oct 2020 07:40:59 +0800 Subject: [PATCH 249/271] Update ExitCommand.java --- .../seedu/dietbook/command/ExitCommand.java | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/main/java/seedu/dietbook/command/ExitCommand.java b/src/main/java/seedu/dietbook/command/ExitCommand.java index 1d3897d831..089f670a25 100644 --- a/src/main/java/seedu/dietbook/command/ExitCommand.java +++ b/src/main/java/seedu/dietbook/command/ExitCommand.java @@ -19,42 +19,42 @@ public ExitCommand() { @Override public void execute(Manager manager, Ui ui) { - ActivityLevel actLvl = manager.getPerson().getActivityLevel(); - int actLvlInt = 1; - if (actLvl.equals(ActivityLevel.NONE)) { - actLvlInt = 1; - } else if (actLvl.equals(ActivityLevel.LOW)) { - actLvlInt = 2; - } else if (actLvl.equals(ActivityLevel.MEDIUM)) { - actLvlInt = 3; - } else if (actLvl.equals(ActivityLevel.HIGH)) { - actLvlInt = 4; - } else if (actLvl.equals(ActivityLevel.EXTREME)) { - actLvlInt = 5; - } + //ActivityLevel actLvl = manager.getPerson().getActivityLevel(); + //int actLvlInt = 1; + //if (actLvl.equals(ActivityLevel.NONE)) { + // actLvlInt = 1; + //} else if (actLvl.equals(ActivityLevel.LOW)) { + // actLvlInt = 2; + //} else if (actLvl.equals(ActivityLevel.MEDIUM)) { + // actLvlInt = 3; + //} else if (actLvl.equals(ActivityLevel.HIGH)) { + // actLvlInt = 4; + //} else if (actLvl.equals(ActivityLevel.EXTREME)) { + // actLvlInt = 5; + //} - Gender gender = manager.getPerson().getGender(); - String genderString; - if (gender.equals(Gender.MALE)) { - genderString = "Male"; - } else if (gender.equals(Gender.FEMALE)) { - genderString = "Female"; - } else { - genderString = "Others"; - } + //Gender gender = manager.getPerson().getGender(); + //String genderString; + //if (gender.equals(Gender.MALE)) { + // genderString = "Male"; + //} else if (gender.equals(Gender.FEMALE)) { + // genderString = "Female"; + //} else { + // genderString = "Others"; + //} - personSave.setActivityLevel(actLvlInt); - personSave.setAge(manager.getPerson().getAge()); - personSave.setCurrentWeight(manager.getPerson().getCurrentWeight()); - personSave.setGender(genderString); - personSave.setHeight(manager.getPerson().getHeight()); - personSave.setName(manager.getPerson().getName()); - personSave.setOriginalWeight(manager.getPerson().getOriginalWeight()); - personSave.setTargetWeight(manager.getPerson().getTargetWeight()); - personSave.save("UserInfo.txt"); - foodSave.save("FoodList.txt", manager.getFoodList().getFoods()); - ui.dataSuccessfullySavedMessage(); - DietBook.isExit = true; + //personSave.setActivityLevel(actLvlInt); + //personSave.setAge(manager.getPerson().getAge()); + //personSave.setCurrentWeight(manager.getPerson().getCurrentWeight()); + //personSave.setGender(genderString); + //personSave.setHeight(manager.getPerson().getHeight()); + //personSave.setName(manager.getPerson().getName()); + //personSave.setOriginalWeight(manager.getPerson().getOriginalWeight()); + //personSave.setTargetWeight(manager.getPerson().getTargetWeight()); + //personSave.save("UserInfo.txt"); + //foodSave.save("FoodList.txt", manager.getFoodList().getFoods()); + //ui.dataSuccessfullySavedMessage(); ui.printExitMessage(); + DietBook.isExit = true; } } From 60fc25c9869859c35fd9718fee20e0ff2a198d8e Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 09:07:37 +0800 Subject: [PATCH 250/271] Add case where gender is male --- src/main/java/seedu/dietbook/parser/Parser.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 3e0c4db12c..4ab9ff58f5 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -258,6 +258,8 @@ public static void executeEditInfo(String userInput, Manager manager) throws Die InputChecker.checkGender(processGender); if (processGender.equals("F")) { gender = Gender.FEMALE; + } else if (processGender.equals("M")) { + gender = Gender.MALE; } else { gender = Gender.OTHERS; } From e563a49c1fe57890d85daac5e043f8e858f77435 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 29 Oct 2020 11:19:18 +0800 Subject: [PATCH 251/271] Bug Fixes --- src/main/java/seedu/dietbook/DietBook.java | 1 + src/main/java/seedu/dietbook/command/DataCommand.java | 1 - src/main/java/seedu/dietbook/parser/Parser.java | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/DietBook.java b/src/main/java/seedu/dietbook/DietBook.java index 6a512a954d..e11065a3c0 100644 --- a/src/main/java/seedu/dietbook/DietBook.java +++ b/src/main/java/seedu/dietbook/DietBook.java @@ -37,6 +37,7 @@ public DietBook() { loadPerson = new PersonSaveLoadManager(); foodList = new FoodList(); dataBase = new DataBase(); + dataBase.init(); manager = new Manager(foodList, dataBase); } diff --git a/src/main/java/seedu/dietbook/command/DataCommand.java b/src/main/java/seedu/dietbook/command/DataCommand.java index 1171366dbd..adabf27c11 100644 --- a/src/main/java/seedu/dietbook/command/DataCommand.java +++ b/src/main/java/seedu/dietbook/command/DataCommand.java @@ -13,7 +13,6 @@ public void execute(Manager manager, Ui ui) throws DietException { } else if (commandCount == 2) { throw new DietException("Please enter your basic information first!"); } - manager.getDataBase().init(); ui.printDatabase(manager.getDataBase().getFoodListString()); } } diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 3e0c4db12c..d2a306fd6e 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -98,9 +98,9 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws int portionSize = 1; String foodName = "Food Name"; int calorie = 0; - int carb = -1; - int protein = -1; - int fat = -1; + int carb = 0; + int protein = 0; + int fat = 0; String trimmedParam; //String[] databaseCheck = getCommandParam(userInput).trim().split("/");; String[] processedParam; From 917c55089951896a1a54dfd46289c855b19e3bcb Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 12:23:12 +0800 Subject: [PATCH 252/271] Update help command message --- src/main/java/seedu/dietbook/Ui.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/Ui.java b/src/main/java/seedu/dietbook/Ui.java index b124ad381e..49c2282c52 100644 --- a/src/main/java/seedu/dietbook/Ui.java +++ b/src/main/java/seedu/dietbook/Ui.java @@ -819,9 +819,9 @@ private String getFoodListRelatedCommands() { * @return A string representation of a list of database related commands that users can input. */ private String getDatabaseRelatedCommands() { - return " To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE" + LINE_SEPARATOR - + " To add a food from the database consumed at a certain time: add n/FOOD_NAME " - + "x/PORTION_SIZE yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + return " [Coming Soon] To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE" + LINE_SEPARATOR + + " [Coming Soon] To add a food from the database consumed at a certain time: add " + + "n/FOOD_NAME x/PORTION_SIZE yyyy-mm-ddTHH:mm" + LINE_SEPARATOR + " To view all food in the database: data" + LINE_SEPARATOR; } From b7ba81bc5980b94f92b32fe957af041acfcf2cbd Mon Sep 17 00:00:00 2001 From: mxksowie <34589654+mxksowie@users.noreply.github.com> Date: Thu, 29 Oct 2020 12:58:03 +0800 Subject: [PATCH 253/271] add addFoodAtDateTime Method overload that accepts food object directly. For save-loading and adding from database. --- .../java/seedu/dietbook/list/FoodList.java | 23 +++++++++++++++---- .../seedu/dietbook/list/FoodListTest.java | 7 ++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/dietbook/list/FoodList.java b/src/main/java/seedu/dietbook/list/FoodList.java index 3807882b12..5e38fa46fc 100644 --- a/src/main/java/seedu/dietbook/list/FoodList.java +++ b/src/main/java/seedu/dietbook/list/FoodList.java @@ -31,11 +31,10 @@ protected FoodList(ArrayList entries) { /** * Adds food of portion size directly into the foodlist as an entry. - * When date functionality is added, this method will need to be overhauled. - * The adding feature will be largely pushed to FoodListManager (to figure out dates) + * Mainly for adding food directly from the data base of foods. * @param portionSize integer to designate number of servings * @param food food object to be added - * @return string representation of the food object added + * @return string representation of the entry added */ public String addFood(int portionSize, Food food) { FoodEntry entry = new DatedFoodEntry(portionSize, food); @@ -60,7 +59,7 @@ public String addFood(int portionSize, String name, int calorie, * Currently just throws a not found exception when called in this manner. * @param portionSize integer to designate number of servings * @param name food object to be added - * @return string representation of the food object added + * @return string representation of entry added * @throws FoodNotFoundException custom exception to indicate search for food in database failed. */ public String addFood(int portionSize, String name) throws FoodNotFoundException { @@ -69,7 +68,7 @@ public String addFood(int portionSize, String name) throws FoodNotFoundException /** - * Add add method for baglogged entries. + * Add add method for backlogged entries. * Allows specificiation of time via LocalDateTime param. * @param dateTime User specified time for backlogged entry. */ @@ -81,6 +80,20 @@ public String addFoodAtDateTime(int portionSize, String name, int calorie, return entry.toString(); } + /** + * Truncated add method for the purpose of save-loading (allows adding food object directly). + * Can also be used to add backlogged entry via database. + * @param portionSize integer to designate number of servings + * @param food Food object to be added (from the save-load/database) + * @param dateTime Save-loaded date-time or user specified time for backlogged entry. + * @return string representation of entry added. + */ + public String addFoodAtDateTime(int portionSize, Food food, LocalDateTime dateTime) { + FoodEntry entry = new DatedFoodEntry(portionSize, food, dateTime); + foodEntries.add(entry); + return entry.toString(); + } + /** * Deletes the the entry of the list at the provided index. * index starts from 1 (not 0). i.e. is User's understanding of index. diff --git a/src/test/java/seedu/dietbook/list/FoodListTest.java b/src/test/java/seedu/dietbook/list/FoodListTest.java index a4072423f9..60a62dd4f7 100644 --- a/src/test/java/seedu/dietbook/list/FoodListTest.java +++ b/src/test/java/seedu/dietbook/list/FoodListTest.java @@ -113,4 +113,11 @@ void getFoodEntryProperties_standardList_FoodEntryProperties() { assertEquals(list.getFoods().get(0), food); } + @Test + void addAndRetrieveEntryAtDateTime_entryAddedAtDateTimeMax_entryAtDateTimeMax() { + list.addFoodAtDateTime(2, food, LocalDateTime.MAX); + assertEquals(food, list.getFoodsAfterDateTime(LocalDateTime.now()).get(0)); + + } + } From 5c97f7933fb17417e62e1611770fd68f7a1b6732 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Thu, 29 Oct 2020 13:25:39 +0800 Subject: [PATCH 254/271] Put Examples of Usage for adding controling food items into the User Guide --- docs/UserGuide.md | 114 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index f5988acfa2..13d7bcc5fc 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -167,41 +167,107 @@ Got it! I've updated your personal information: ### Features related to the food database -To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE -To view all food in the database: data +* To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE +* To view all food in the database: data ### Features related to the food list -To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT] -To view all food in DietBook: list -To view all food in DietBook recorded within a time period: list yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm -To view all food in DietBook recorded from a certain date until now: list yyyy-mm-ddTHH:mm -To delete a food from DietBook: delete INDEX -To delete all food items from the DietBook: clear - +* To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT] + * Examples of usage : + * Example 1 : add x/1 n/Salty Chicken Rice k/300 c/10 p/20 f/50 + * Output of Example 1 : + ``` + Got it! I've added this food item: + Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + ``` + * Example 2 : add x/2 n/Chilli Pepper Crab k/400 c/10 p/10 f/20 + * Output of Example 2 : + ``` + Got it! I've added this food item: + Chilli Pepper Crab | calorie : 400 | protein : 10 | carbohydrate : 10 | fats : 20 -- (2) + ``` + +* To view all food in DietBook: list + * Example of usage : list + * Output : + ``` + Here are the food items in DietBook: + 1. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 2. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 3. Chilli Pepper Crab | calorie : 400 | protein : 10 | carbohydrate : 10 | fats : 20 -- (2) + ``` +* To view all food in DietBook recorded within a time period: list yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + * Example of usage : list 2020-10-29T11:30 2020-10-29T16:40 + * Output : + ``` + Here are the food items recorded in DietBook between 29 Oct 2020 1130 and 29 Oct 2020 1640: + 1. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 2. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 3. Chilli Pepper Crab | calorie : 400 | protein : 10 | carbohydrate : 10 | fats : 20 -- (2) + ``` + +* To view all food in DietBook recorded from a certain date until now: list yyyy-mm-ddTHH:mm + * Example of usage : list 1066-10-14T08:00 + * Output : + ``` + Here are the food items recorded in DietBook between 14 Oct 1066 0800 and 29 Oct 2020 1317: + 1. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 2. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 3. Chilli Pepper Crab | calorie : 400 | protein : 10 | carbohydrate : 10 | fats : 20 -- (2) + ``` +* To delete a food from DietBook: delete INDEX + * Example of usage : delete 2 + * Output : + ``` + Noted. I've removed this food item: + Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + ``` + * The list after delete is done : + ``` + Here are the food items in DietBook: + 1. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 2. Chilli Pepper Crab | calorie : 400 | protein : 10 | carbohydrate : 10 | fats : 20 -- (2) + ``` +* To delete all food items from the DietBook: clear + * Example of usage : clear + * Output : + ``` + All previous data has been deleted... + DietBook is now empty. + ``` + * Before clearing : + ``` + Here are the food items in DietBook: + 1. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 2. Chilli Pepper Crab | calorie : 400 | protein : 10 | carbohydrate : 10 | fats : 20 -- (2) + ``` + * After clearing : + ``` + DietBook is currently empty. + ``` ### Features related to nutritional intake and recommendation To get recommended calorie intake: recommend - To calculate carbohydrate intake: calculate carbohydrate - To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm + * To calculate carbohydrate intake: calculate carbohydrate + * To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + * To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm - To calculate calorie intake: calculate calorie - To calculate calorie intake within a time period: calculate calorie yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - To calculate calorie intake from a certain date until now: calculate calorie yyyy-mm-ddTHH:mm + * To calculate calorie intake: calculate calorie + * To calculate calorie intake within a time period: calculate calorie yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + * To calculate calorie intake from a certain date until now: calculate calorie yyyy-mm-ddTHH:mm - To calculate protein intake: calculate protein - To calculate protein intake within a time period: calculate protein yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - To calculate protein intake from a certain date until now: calculate protein yyyy-mm-ddTHH:mm + * To calculate protein intake: calculate protein + * To calculate protein intake within a time period: calculate protein yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + * To calculate protein intake from a certain date until now: calculate protein yyyy-mm-ddTHH:mm - To calculate fat intake: calculate fat - To calculate fat intake within a time period: calculate fat yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - To calculate fat intake from a certain date until now: calculate fat yyyy-mm-ddTHH:mm + * To calculate fat intake: calculate fat + * To calculate fat intake within a time period: calculate fat yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + * To calculate fat intake from a certain date until now: calculate fat yyyy-mm-ddTHH:mm - To calculate all nutritional intake: calculate all - To calculate all nutritional intake within a time period: calculate all yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - To calculate all nutritional intake from a certain date until now: calculate all yyyy-mm-ddTHH:mm + * To calculate all nutritional intake: calculate all + * To calculate all nutritional intake within a time period: calculate all yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + * To calculate all nutritional intake from a certain date until now: calculate all yyyy-mm-ddTHH:mm ### Other features From 0e12c980ac45a107174023d73df69d0383de6a68 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Thu, 29 Oct 2020 13:48:47 +0800 Subject: [PATCH 255/271] Add examples of usage to UserGuide section --- docs/UserGuide.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index d0d7afc813..8104eee790 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -248,11 +248,54 @@ Got it! I've updated your personal information: ### Features related to nutritional intake and recommendation To get recommended calorie intake: recommend + * Example of usage : + * Output : + ``` + Hi Jack! + Here is your daily recommended calorie intake: 2607kcal + ``` + +We use the following list as an example, to set up the list we have the following sequence of inputs + +add x/1 n/Salty Chicken Rice k/300 c/10 p/20 f/50 +add x/2 n/Chilli Pepper Crab k/400 c/10 p/10 f/20 +add x/1 n/Steak Buns k/500 c/20 p/50 f/10 +add x/3 n/Sweat potato tea k/300 c/30 p/0 f/0 +add x/1 n/Chicken Wing Noodles k/400 c/10 p/30 f/10 +list + +``` +Here are the food items in DietBook: + 1. Salty Chicken Rice | calorie : 300 | protein : 20 | carbohydrate : 10 | fats : 50 -- (1) + 2. Chilli Pepper Crab | calorie : 400 | protein : 10 | carbohydrate : 10 | fats : 20 -- (2) + 3. Steak Buns | calorie : 500 | protein : 50 | carbohydrate : 20 | fats : 10 -- (1) + 4. Sweat potato tea | calorie : 300 | protein : 0 | carbohydrate : 30 | fats : 0 -- (3) + 5. Chicken Wing Noodles | calorie : 400 | protein : 30 | carbohydrate : 10 | fats : 10 -- (1) +``` * To calculate carbohydrate intake: calculate carbohydrate + Input : calculate carbohydrate + Output : + ``` + Total carbohydrate intake: 80g + ``` * To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - * To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm + Input : calculate carbohydrate 2020-10-29T08:00 2020-10-29T17:00 + Output : + ``` + Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1700 + Total carbohydrate intake: 80g + ``` + * To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm + Input : calculate carbohydrate 2020-10-29T08:00 + Output : + ``` + Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1340 + + Total carbohydrate intake: 80g + ``` +Similar Inputs and outputs for the following * To calculate calorie intake: calculate calorie * To calculate calorie intake within a time period: calculate calorie yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm * To calculate calorie intake from a certain date until now: calculate calorie yyyy-mm-ddTHH:mm @@ -266,8 +309,36 @@ To get recommended calorie intake: recommend * To calculate fat intake from a certain date until now: calculate fat yyyy-mm-ddTHH:mm * To calculate all nutritional intake: calculate all + Input : calculate all + OutPut : + ``` + Total calorie intake: 1900kcal + Total carbohydrate intake: 80g + Total protein intake: 110g + Total fat intake: 90g + ``` * To calculate all nutritional intake within a time period: calculate all yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + Input : calculate all 2020-10-29T08:00 2020-10-29T17:00 + OutPut : + ``` + Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1700 + + Total calorie intake: 1900kcal + Total carbohydrate intake: 80g + Total protein intake: 110g + Total fat intake: 90g + ``` * To calculate all nutritional intake from a certain date until now: calculate all yyyy-mm-ddTHH:mm + Input : calculate all 2020-10-29T08:00 + OutPut : + ``` + Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1345 + + Total calorie intake: 1900kcal + Total carbohydrate intake: 80g + Total protein intake: 110g + Total fat intake: 90g + ``` ### Other features From cd4ea6df207d4054f427bb158f92c6b8f815aff1 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Thu, 29 Oct 2020 13:50:12 +0800 Subject: [PATCH 256/271] minor fixes --- docs/UserGuide.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 8104eee790..1a3fe23b11 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -274,22 +274,22 @@ Here are the food items in DietBook: ``` * To calculate carbohydrate intake: calculate carbohydrate - Input : calculate carbohydrate - Output : + * Input : calculate carbohydrate + * Output : ``` Total carbohydrate intake: 80g ``` * To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - Input : calculate carbohydrate 2020-10-29T08:00 2020-10-29T17:00 - Output : + * Input : calculate carbohydrate 2020-10-29T08:00 2020-10-29T17:00 + * Output : ``` Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1700 Total carbohydrate intake: 80g ``` * To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm - Input : calculate carbohydrate 2020-10-29T08:00 - Output : + * Input : calculate carbohydrate 2020-10-29T08:00 + * Output : ``` Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1340 @@ -309,8 +309,8 @@ Similar Inputs and outputs for the following * To calculate fat intake from a certain date until now: calculate fat yyyy-mm-ddTHH:mm * To calculate all nutritional intake: calculate all - Input : calculate all - OutPut : + * Input : calculate all + * OutPut : ``` Total calorie intake: 1900kcal Total carbohydrate intake: 80g @@ -318,8 +318,8 @@ Similar Inputs and outputs for the following Total fat intake: 90g ``` * To calculate all nutritional intake within a time period: calculate all yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - Input : calculate all 2020-10-29T08:00 2020-10-29T17:00 - OutPut : + * Input : calculate all 2020-10-29T08:00 2020-10-29T17:00 + * OutPut : ``` Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1700 @@ -329,8 +329,8 @@ Similar Inputs and outputs for the following Total fat intake: 90g ``` * To calculate all nutritional intake from a certain date until now: calculate all yyyy-mm-ddTHH:mm - Input : calculate all 2020-10-29T08:00 - OutPut : + * Input : calculate all 2020-10-29T08:00 + * OutPut : ``` Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1345 From ae409f59fc7f53cadf38187758602dbccbf8c4d5 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 29 Oct 2020 13:58:39 +0800 Subject: [PATCH 257/271] Update UserGuide.md --- docs/UserGuide.md | 77 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 87ff008b0c..e64a907d03 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -205,9 +205,80 @@ To get recommended calorie intake: recommend ### Other features - To view a list of valid commands: help - To exit DietBook: exit - Saving +#### To view a list of valid commands: help: `help` + +Displays the helping guide for commands. + +Format: `help` + +Output example: +``` +Listed below are the valid commands for DietBook: + +For user information related commands + To view user information: userinfo + To edit user information: editinfo [n/NAME] [g/GENDER] [a/AGE] [h/HEIGHT] [o/ORIGINAL_WEIGHT] [c/CURRENT_WEIGHT] [t/TARGET_WEIGHT] [l/ACTIVITY_LEVEL] + +For database related commands + [Coming Soon] To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE + [Coming Soon] To add a food from the database consumed at a certain time: add n/FOOD_NAME x/PORTION_SIZE yyyy-mm-ddTHH:mm + To view all food in the database: data + +For food list related commands + To add a food not in the database that was just consumed: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT] + To add a food not in the database consumed at a certain time: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT] yyyy-mm-ddTHH:mm + To view all food in DietBook: list + To view all food in DietBook recorded within a time period: list yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To view all food in DietBook recorded from a certain date until now: list yyyy-mm-ddTHH:mm + To delete a food from DietBook: delete INDEX + To delete all food items from the DietBook: clear + +For nutritional intake and recommendation related commands + To get recommended calorie intake: recommend + + To calculate carbohydrate intake: calculate carbohydrate + To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm + + To calculate calorie intake: calculate calorie + To calculate calorie intake within a time period: calculate calorie yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate calorie intake from a certain date until now: calculate calorie yyyy-mm-ddTHH:mm + + To calculate protein intake: calculate protein + To calculate protein intake within a time period: calculate protein yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate protein intake from a certain date until now: calculate protein yyyy-mm-ddTHH:mm + + To calculate fat intake: calculate fat + To calculate fat intake within a time period: calculate fat yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate fat intake from a certain date until now: calculate fat yyyy-mm-ddTHH:mm + + To calculate all nutritional intake: calculate all + To calculate all nutritional intake within a time period: calculate all yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + To calculate all nutritional intake from a certain date until now: calculate all yyyy-mm-ddTHH:mm + +For other system related commands + To view a list of valid commands: help + To exit DietBook: exit +``` + #### To exit DietBook: `exit` + + Exits the DietBook. + + Format: `exit` + + Output example: + ``` + Bye! Hope to see you again soon! + ``` + + #### Saving the DietBook: `Coming soon!` + + Saves the DietBook data when the exit command have been input. The saved data is in 2 files: UserInfo.txt and FoodList.txt. + + Output example: + ``` + Your data has been saved successfully. + ``` #### Adding a todo: `todo` Adds a new item to the list of todo items. From 4e99bb82dff1a0e33a823275d2b7997120d05257 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 29 Oct 2020 21:41:18 +0800 Subject: [PATCH 258/271] Add command with date time --- .../seedu/dietbook/checker/InputChecker.java | 31 +++++++++++++++++++ .../java/seedu/dietbook/parser/Parser.java | 9 ++++++ 2 files changed, 40 insertions(+) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 43a0d8069a..4f887e0c28 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -3,6 +3,8 @@ import seedu.dietbook.exception.DietException; import seedu.dietbook.parser.Parser; +import java.time.LocalDateTime; + /** * InputChecker class of the program. * This class checks the validity of the user input and throws an exception if input is not as intended/expected. @@ -77,6 +79,35 @@ public static void checkRepeatedOption(String command, String options) throws Di } } + /** + * Takes in user input to check if date format is present. + * + * @param userInput user input. + * @return boolean whereby true if date present, false otherwise. + */ + public static boolean checkDate(String userInput) throws DietException { + String[] processedInput = userInput.split("\\s+"); + if (processedInput[processedInput.length - 1].contains("T")) { + return true; + } else { + return false; + } + } + + /** + * Takes in string format of date time to check if date format is correct. + * + * @param dateString string form of a potential date time. + * @throws DietException if date format is wrong. + */ + public static void checkDateValidity(String dateString) throws DietException { + try { + LocalDateTime.parse(dateString); + } catch (Exception e) { + throw new DietException("Wrong date time format!"); + } + } + /** * Takes in user input to check if the expected number and type of parameter for the add command is present. * diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index d5b2eef077..56dfe329eb 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -111,8 +111,11 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws processedParam = getCommandParam(userInput).split(param); InputChecker.checkEmptyOption(processedParam); trimmedParam = processedParam[1].trim(); + if (processedParam[1].contains("/")) { trimmedParam = processedParam[1].substring(0, processedParam[1].indexOf("/") - 2).trim(); + } else if (trimmedParam.split("\\s+").length == 2) { + trimmedParam = trimmedParam.split("\\s+")[0]; } switch (param) { case "x/": @@ -141,6 +144,12 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws } } } + if (InputChecker.checkDate(userInput)) { + processedParam = userInput.split("\\s+"); + InputChecker.checkDateValidity(processedParam[processedParam.length - 1]); + LocalDateTime time = LocalDateTime.parse(processedParam[processedParam.length - 1]); + return foodList.addFoodAtDateTime(portionSize, foodName, calorie, carb, protein, fat, time); + } //if (databaseCheck.length == 3) { // DataBase dataBase = new DataBase(); // Food searchedFood = dataBase.searchFoodByName(foodName); From 8c2a70284d0633ed88a1188486863ff70c2af209 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Thu, 29 Oct 2020 22:08:00 +0800 Subject: [PATCH 259/271] Future date exception --- .../java/seedu/dietbook/checker/InputChecker.java | 12 ++++++++++++ .../seedu/dietbook/command/CalculateCommand.java | 13 +++++++++++-- .../java/seedu/dietbook/command/ListCommand.java | 4 +++- src/main/java/seedu/dietbook/parser/Parser.java | 1 + 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/dietbook/checker/InputChecker.java b/src/main/java/seedu/dietbook/checker/InputChecker.java index 4f887e0c28..c68e6afa71 100644 --- a/src/main/java/seedu/dietbook/checker/InputChecker.java +++ b/src/main/java/seedu/dietbook/checker/InputChecker.java @@ -108,6 +108,18 @@ public static void checkDateValidity(String dateString) throws DietException { } } + /** + * Takes in a date time object and see if it is a future date. + * + * @param time a date time class object. + * @throws DietException if date is in the future. + */ + public static void checkFutureDate(LocalDateTime time) throws DietException { + if (time.isAfter(LocalDateTime.now())) { + throw new DietException("The date cannot be in the future!"); + } + } + /** * Takes in user input to check if the expected number and type of parameter for the add command is present. * diff --git a/src/main/java/seedu/dietbook/command/CalculateCommand.java b/src/main/java/seedu/dietbook/command/CalculateCommand.java index 5b767ad184..6eb01e27b2 100644 --- a/src/main/java/seedu/dietbook/command/CalculateCommand.java +++ b/src/main/java/seedu/dietbook/command/CalculateCommand.java @@ -2,7 +2,6 @@ import seedu.dietbook.Manager; import seedu.dietbook.Ui; -import seedu.dietbook.calculator.Calculator; import seedu.dietbook.checker.InputChecker; import seedu.dietbook.exception.DietException; @@ -46,6 +45,7 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printAllIntake(this.calorie, this.carb, this.protein, this.fat); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime); carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime); protein = manager.getCalculator().calculateProtein(manager.getFoodList(), startTime); @@ -53,6 +53,7 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printAllIntake(calorie, carb, protein, fat, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); endTime = LocalDateTime.parse(processedParam[2]); calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime, endTime); carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime, endTime); @@ -66,10 +67,12 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printCalorieIntake(this.calorie); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime); ui.printCalorieIntake(calorie, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); endTime = LocalDateTime.parse(processedParam[2]); calorie = manager.getCalculator().calculateCalorie(manager.getFoodList(), startTime, endTime); ui.printCalorieIntake(calorie, startTime, endTime); @@ -80,10 +83,12 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printCarbIntake(this.carb); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime); ui.printCarbIntake(carb, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); endTime = LocalDateTime.parse(processedParam[2]); carb = manager.getCalculator().calculateCarb(manager.getFoodList(), startTime, endTime); ui.printCarbIntake(carb, startTime, endTime); @@ -94,10 +99,12 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printProteinIntake(this.protein); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); protein = manager.getCalculator().calculateProtein(manager.getFoodList(), startTime); ui.printProteinIntake(protein, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); endTime = LocalDateTime.parse(processedParam[2]); protein = manager.getCalculator().calculateProtein(manager.getFoodList(), startTime, endTime); ui.printProteinIntake(protein, startTime, endTime); @@ -108,17 +115,19 @@ public void execute(Manager manager, Ui ui) throws DietException { ui.printFatIntake(this.fat); } else if (processedParam.length == 2) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); fat = manager.getCalculator().calculateFat(manager.getFoodList(), startTime); ui.printFatIntake(fat, startTime); } else if (processedParam.length == 3) { startTime = LocalDateTime.parse(processedParam[1]); + InputChecker.checkFutureDate(startTime); endTime = LocalDateTime.parse(processedParam[2]); fat = manager.getCalculator().calculateFat(manager.getFoodList(), startTime, endTime); ui.printFatIntake(fat, startTime, endTime); } } } catch (Exception e) { - throw new DietException("Wrong date time format! (Format: yyyy-mm-ddTHH:mm)"); + throw new DietException("Wrong date time format (Format: yyyy-mm-ddTHH:mm) or future date entered!"); } } } diff --git a/src/main/java/seedu/dietbook/command/ListCommand.java b/src/main/java/seedu/dietbook/command/ListCommand.java index 9cd41a26bd..933e42289e 100644 --- a/src/main/java/seedu/dietbook/command/ListCommand.java +++ b/src/main/java/seedu/dietbook/command/ListCommand.java @@ -33,14 +33,16 @@ public void execute(Manager manager, Ui ui) throws DietException { try { if (processedInput.length == 2) { startTime = LocalDateTime.parse(processedInput[1]); + InputChecker.checkFutureDate(startTime); ui.printFoodList(foodList.getAfterDateTimeToString(startTime), startTime); } else if (processedInput.length == 3) { startTime = LocalDateTime.parse(processedInput[1]); endTime = LocalDateTime.parse(processedInput[2]); + InputChecker.checkFutureDate(startTime); ui.printFoodList(foodList.getInDateTimeRangeToString(startTime,endTime), startTime, endTime); } } catch (Exception e) { - throw new DietException("Wrong date time format! (Format: yyyy-mm-ddTHH:mm)"); + throw new DietException("Wrong date time format (Format: yyyy-mm-ddTHH:mm) or future date entered!"); } } } diff --git a/src/main/java/seedu/dietbook/parser/Parser.java b/src/main/java/seedu/dietbook/parser/Parser.java index 56dfe329eb..9fbcddaa74 100644 --- a/src/main/java/seedu/dietbook/parser/Parser.java +++ b/src/main/java/seedu/dietbook/parser/Parser.java @@ -148,6 +148,7 @@ public static String getProcessedAdd(String userInput, FoodList foodList) throws processedParam = userInput.split("\\s+"); InputChecker.checkDateValidity(processedParam[processedParam.length - 1]); LocalDateTime time = LocalDateTime.parse(processedParam[processedParam.length - 1]); + InputChecker.checkFutureDate(time); return foodList.addFoodAtDateTime(portionSize, foodName, calorie, carb, protein, fat, time); } //if (databaseCheck.length == 3) { From 15f3458db13966ac31e7d815828cc1ed6cfcc9ec Mon Sep 17 00:00:00 2001 From: HengFuYuen <60005925+HengFuYuen@users.noreply.github.com> Date: Thu, 29 Oct 2020 22:30:08 +0800 Subject: [PATCH 260/271] 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 3397c9a492..8b13789179 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-architect \ No newline at end of file + From 48c9fd4ffc7a322fb1fa0ccb18771d6f9b7cb297 Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 22:43:51 +0800 Subject: [PATCH 261/271] Fix major formatting issues --- docs/UserGuide.md | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3fdbb301bf..56945867c1 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -248,21 +248,22 @@ Got it! I've updated your personal information: ### Features related to nutritional intake and recommendation To get recommended calorie intake: recommend - * Example of usage : - * Output : +* Example of usage : +* Output : ``` Hi Jack! Here is your daily recommended calorie intake: 2607kcal ``` We use the following list as an example, to set up the list we have the following sequence of inputs - +``` add x/1 n/Salty Chicken Rice k/300 c/10 p/20 f/50 add x/2 n/Chilli Pepper Crab k/400 c/10 p/10 f/20 add x/1 n/Steak Buns k/500 c/20 p/50 f/10 add x/3 n/Sweat potato tea k/300 c/30 p/0 f/0 add x/1 n/Chicken Wing Noodles k/400 c/10 p/30 f/10 list +``` ``` Here are the food items in DietBook: @@ -416,20 +417,6 @@ For other system related commands ``` Your data has been saved successfully. ``` - -#### 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 From a66165be49284ba2fcf938be74d6fc8fb53f8efd Mon Sep 17 00:00:00 2001 From: HengFuYuen Date: Thu, 29 Oct 2020 22:59:32 +0800 Subject: [PATCH 262/271] Fix formatting --- docs/UserGuide.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3fdbb301bf..51a36c93c2 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -279,22 +279,24 @@ Here are the food items in DietBook: ``` Total carbohydrate intake: 80g ``` - * To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm - * Input : calculate carbohydrate 2020-10-29T08:00 2020-10-29T17:00 - * Output : +* To calculate carbohydrate intake within a time period: calculate carbohydrate yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm + * Input : calculate carbohydrate 2020-10-29T08:00 2020-10-29T17:00 + * Output : ``` Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1700 Total carbohydrate intake: 80g ``` - * To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm - * Input : calculate carbohydrate 2020-10-29T08:00 - * Output : + +* To calculate carbohydrate intake from a certain date until now: calculate carbohydrate yyy-mm-ddTHH:mm + * Input : calculate carbohydrate 2020-10-29T08:00 + * Output : ``` Time period: between 29 Oct 2020 0800 and 29 Oct 2020 1340 Total carbohydrate intake: 80g ``` + Similar Inputs and outputs for the following * To calculate calorie intake: calculate calorie * To calculate calorie intake within a time period: calculate calorie yyyy-mm-ddTHH:mm yyyy-mm-ddTHH:mm @@ -413,6 +415,7 @@ For other system related commands Saves the DietBook data when the exit command have been input. The saved data is in 2 files: UserInfo.txt and FoodList.txt. Output example: + ``` Your data has been saved successfully. ``` From 6d4887b82a690b4fe4d276de9c149551ee195d61 Mon Sep 17 00:00:00 2001 From: tikimonarch Date: Fri, 30 Oct 2020 11:36:18 +0800 Subject: [PATCH 263/271] Update UserGuide.md --- docs/UserGuide.md | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 87f7778fc9..035c9e037c 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -167,9 +167,43 @@ Got it! I've updated your personal information: ### Features related to the food database -* To add a food from the database: add n/FOOD_NAME x/PORTION_SIZE -* To view all food in the database: data - +#### To view all food in the database: `data` + +Displays a list of provided food database. + +Format: `data` + +Output example: +``` +Here are the food items in the database: + 1. Prawn Mee Soup(Dry)(Large) | calorie : 490 | protein : 0 | carbohydrate : 0 | fats : 0 + 2. Prawn Mee Soup(Dry)(Small) | calorie : 390 | protein : 0 | carbohydrate : 0 | fats : 0 + 3. Fried Hokkien Prawn Mee(Large) | calorie : 470 | protein : 0 | carbohydrate : 0 | fats : 0 + 4. Fried Hokkien Prawn Mee(Small) | calorie : 350 | protein : 0 | carbohydrate : 0 | fats : 0 + 5. Clay Pot Chicken | calorie : 440 | protein : 0 | carbohydrate : 0 | fats : 0 + 6. Black Pepper Chicken | calorie : 490 | protein : 0 | carbohydrate : 0 | fats : 0 + 7. Ayam Penyet Set | calorie : 699 | protein : 0 | carbohydrate : 0 | fats : 0 + 8. Steamed Chicken Set | calorie : 475 | protein : 0 | carbohydrate : 0 | fats : 0 + 9. Ikan Grouper Penyet Set | calorie : 669 | protein : 0 | carbohydrate : 0 | fats : 0 + 10. Bouillabaisse with cock crab and poached lobster | calorie : 520 | protein : 35 | carbohydrate : 45 | fats : 56 + 11. Chicken wings with Reblochon pomme pur??e | calorie : 450 | protein : 32 | carbohydrate : 25 | fats : 66 + 12. Sea bass with prawn tortellini, fennel pur??e and white wine sauce | calorie : 530 | protein : 25 | carbohydrate : 76 | fats : 43 +``` + +#### To add a food from the database: `add` `Coming Soon!` + +Adds a desired food in the database into the DietBook. + +Format: `add n/FOOD_NAME x/PORTION_SIZE` + +Example of Usage: +* `add n/Prawn Mee x/1` adds the first instance of food with a name that contains Prawn Mee with a portion of 1. + +Output example: +```Here are the food items in DietBook: + 1. Prawn Mee Soup(Dry)(Large) | calorie : 490 | protein : 0 | carbohydrate : 0 | fats : 0 -- (1) +``` + ### Features related to the food list * To add you own food: add x/PORTION_SIZE n/FOOD_NAME k/CALORIE [c/CARBOHYDRATE] [p/PROTEIN] [f/FAT] From e6c036df936246d104309796355bb2abe90f4cd8 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 4 Nov 2020 20:22:25 +0800 Subject: [PATCH 264/271] edit data base --- src/main/resources/data.txt | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/resources/data.txt b/src/main/resources/data.txt index 7a211bc4e1..5b0dc3139d 100644 --- a/src/main/resources/data.txt +++ b/src/main/resources/data.txt @@ -26,22 +26,25 @@ &%START Science canteen Halal Mini Wok -Prawn Mee Soup(Dry)(Large)|490|0|0|0 -Prawn Mee Soup(Dry)(Small)|390|0|0|0 -Fried Hokkien Prawn Mee(Large)|470|0|0|0 -Fried Hokkien Prawn Mee(Small)|350|0|0|0 -Clay Pot Chicken|440|0|0|0 -Black Pepper Chicken|490|0|0|0 +Prawn Mee Soup(Dry)(Large)|490|30|20|26 +Prawn Mee Soup(Dry)(Small)|390|25|15|19 +Fried Hokkien Prawn Mee(Large)|470|40|20|20 +Fried Hokkien Prawn Mee(Small)|350|30|15|15 +Clay Pot Chicken|440|34|15|15 +Black Pepper Chicken|490|34|16|16 &%UP Ayam Penyet -Ayam Penyet Set|699|0|0|0 -Steamed Chicken Set |475|0|0|0 -Ikan Grouper Penyet Set|669|0|0|0 +Ayam Penyet Set|699|45|30|30 +Steamed Chicken Set |475|35|20|20 +Ikan Grouper Penyet Set|669|50|40|50 &%UP -Michelin Star Restaurant -Bouillabaisse with cock crab and poached lobster|520|45|35|56 -Chicken wings with Reblochon pomme purée|450|25|32|66 -Sea bass with prawn tortellini, fennel purée and white wine sauce|530|76|25|43 +Korean +kimchi fried rice|520|45|35|56 +ginseng chicken|450|25|32|66 +ramen|530|76|25|43 +&%UP +Gong Cha + &%UP &%UP &%STOP From 0ad3d535b4499629cac610e1e3778209f49c8878 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 4 Nov 2020 20:26:26 +0800 Subject: [PATCH 265/271] update data base --- src/main/java/seedu/dietbook/database/data.txt | 13 +++++++++---- src/main/resources/data.txt | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/dietbook/database/data.txt b/src/main/java/seedu/dietbook/database/data.txt index 7a211bc4e1..122f849a47 100644 --- a/src/main/java/seedu/dietbook/database/data.txt +++ b/src/main/java/seedu/dietbook/database/data.txt @@ -38,10 +38,15 @@ Ayam Penyet Set|699|0|0|0 Steamed Chicken Set |475|0|0|0 Ikan Grouper Penyet Set|669|0|0|0 &%UP -Michelin Star Restaurant -Bouillabaisse with cock crab and poached lobster|520|45|35|56 -Chicken wings with Reblochon pomme purée|450|25|32|66 -Sea bass with prawn tortellini, fennel purée and white wine sauce|530|76|25|43 +Korean +kimchi fried rice|520|45|35|56 +ginseng chicken|450|25|32|66 +ramen|530|76|25|43 +&%UP +Gong Cha +gong cha green tea|100|0|0|0 +gong cha ooloong tea|100|0|0|0 +gong cha bubble tea|200|0|0|0 &%UP &%UP &%STOP diff --git a/src/main/resources/data.txt b/src/main/resources/data.txt index 5b0dc3139d..6dd0327f19 100644 --- a/src/main/resources/data.txt +++ b/src/main/resources/data.txt @@ -44,7 +44,9 @@ ginseng chicken|450|25|32|66 ramen|530|76|25|43 &%UP Gong Cha - +gong cha green tea|100|0|0|0 +gong cha ooloong tea|100|0|0|0 +gong cha bubble tea|200|0|0|0 &%UP &%UP &%STOP From 221662a6211d6f2f8f1fbb3f761a56d211c19902 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:07:33 +0800 Subject: [PATCH 266/271] implement and test search food by index function in data base --- .../seedu/dietbook/database/DataBase.java | 9 ++++++++ .../seedu/dietbook/database/DataBaseTest.java | 22 +++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java index d671260c6c..713e70809b 100644 --- a/src/main/java/seedu/dietbook/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -123,6 +123,15 @@ public void printAllData() { // -------- Search functions -------- + /** + * This method returns the ith food item from the entire list of food from the data base + * @param index entry number of the food + * @return food object + */ + public Food searchFoodByIndex(int index){ + return foodStream().skip(index - 1).findFirst().orElseThrow(); + } + /** * This method searchs the whole data base and returns the first food item whose name contains the provided string. * ( CASE SENSITIVE ! ) diff --git a/src/test/java/seedu/dietbook/database/DataBaseTest.java b/src/test/java/seedu/dietbook/database/DataBaseTest.java index d1823de021..458f5c9155 100644 --- a/src/test/java/seedu/dietbook/database/DataBaseTest.java +++ b/src/test/java/seedu/dietbook/database/DataBaseTest.java @@ -12,12 +12,26 @@ public static void main(String[] args) { database.printAllData(); // ---- Using stream version to print ----- - System.out.println("------------ printing using food stream ------------"); - database.foodStream().forEach(System.out::println); + // System.out.println("------------ printing using food stream ------------"); + // database.foodStream().forEach(System.out::println); // ---- Printing out as list ----- - System.out.println("---------- printing food using list --------------"); - database.getFoodList().forEach(System.out::println); + // System.out.println("---------- printing food using list --------------"); + // database.getFoodList().forEach(System.out::println); + + // ---- get food list string ---- + System.out.print(database.getFoodListString()); + + // ---- search food by index test ---- + System.out.println("-------- testing the searchFoodByIndex function --------"); + System.out.println("Input : 1 ## OutPut : " + database.searchFoodByIndex(1)); + System.out.println("Input : 10 ## Output : " + database.searchFoodByIndex(10)); + System.out.println("Trying a negative test case : Input : 10000"); + try { + database.searchFoodByIndex(10000); + } catch (NoSuchElementException e){ + System.out.println("The index is too high!" + e); + } // ---- search food by name test ----- try { From 30b2195b2d426849b6f9b44fc776accd2e7d96bb Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:18:01 +0800 Subject: [PATCH 267/271] passed check style --- src/main/java/seedu/dietbook/database/DataBase.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/dietbook/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java index 713e70809b..0af08fffb7 100644 --- a/src/main/java/seedu/dietbook/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -121,14 +121,9 @@ public void printAllData() { System.out.println("Finished Printing out all data"); } - // -------- Search functions -------- - - /** - * This method returns the ith food item from the entire list of food from the data base - * @param index entry number of the food - * @return food object - */ - public Food searchFoodByIndex(int index){ + // ----- Food search functions ------- + + public Food searchFoodByIndex(int index) { return foodStream().skip(index - 1).findFirst().orElseThrow(); } From 03e0bee8262d6f77d0cf5cacf5a0d397c9cd869c Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:21:35 +0800 Subject: [PATCH 268/271] fix check style --- src/main/java/seedu/dietbook/database/DataBase.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/dietbook/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java index 0af08fffb7..70115d872a 100644 --- a/src/main/java/seedu/dietbook/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -122,10 +122,6 @@ public void printAllData() { } // ----- Food search functions ------- - - public Food searchFoodByIndex(int index) { - return foodStream().skip(index - 1).findFirst().orElseThrow(); - } /** * This method searchs the whole data base and returns the first food item whose name contains the provided string. @@ -137,6 +133,10 @@ public Food searchFoodByIndex(int index) { public Food searchFoodByName(String food) { return foodStream().filter(x -> x.getName().contains(food)).findFirst().orElseThrow(); } + + public Food searchFoodByIndex(int index) { + return foodStream().skip(index - 1).findFirst().orElseThrow(); + } /** * This method searchs the whole data base and returns all of the food whose name contains the provided string. From a3aa5725f48e3c2bed29cfe59e8b42c2522afe12 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:21:43 +0800 Subject: [PATCH 269/271] no message --- src/main/java/seedu/dietbook/database/DataBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/dietbook/database/DataBase.java b/src/main/java/seedu/dietbook/database/DataBase.java index 70115d872a..cd40ca85d5 100644 --- a/src/main/java/seedu/dietbook/database/DataBase.java +++ b/src/main/java/seedu/dietbook/database/DataBase.java @@ -133,7 +133,7 @@ public void printAllData() { public Food searchFoodByName(String food) { return foodStream().filter(x -> x.getName().contains(food)).findFirst().orElseThrow(); } - + public Food searchFoodByIndex(int index) { return foodStream().skip(index - 1).findFirst().orElseThrow(); } From 3084624f21ffaf7aa3d7b94bad2cab81e3d0d24f Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:24:33 +0800 Subject: [PATCH 270/271] fix test check style --- src/test/java/seedu/dietbook/database/DataBaseTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/dietbook/database/DataBaseTest.java b/src/test/java/seedu/dietbook/database/DataBaseTest.java index 458f5c9155..ecff6b75fc 100644 --- a/src/test/java/seedu/dietbook/database/DataBaseTest.java +++ b/src/test/java/seedu/dietbook/database/DataBaseTest.java @@ -29,7 +29,7 @@ public static void main(String[] args) { System.out.println("Trying a negative test case : Input : 10000"); try { database.searchFoodByIndex(10000); - } catch (NoSuchElementException e){ + } catch (NoSuchElementException e) { System.out.println("The index is too high!" + e); } From 9485a2c438ecd1b16037e4d4c2538a3d523089d3 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Sun, 8 Nov 2020 12:34:41 +0800 Subject: [PATCH 271/271] copy resources over to test --- src/test/resources/data.txt | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/resources/data.txt diff --git a/src/test/resources/data.txt b/src/test/resources/data.txt new file mode 100644 index 0000000000..6dd0327f19 --- /dev/null +++ b/src/test/resources/data.txt @@ -0,0 +1,53 @@ +##################################################################### +# 3 LEVEL DATA BASE # +# Canteen -----> Store ------> Food # +# Commands : # +# &%START : start reading data from the data base # +# &%STOP : stop reading data from the data base # +# &%UP : goes down 1 level e.g. Canteen ---> Store # +# &%DOWN : goes down 1 level e.g. Canteen ---> Store # +# &%ADD format : adds the item with the given format # +# # +# Comments : any line that starts with # is ignored # +# # +# Canteen format : {name} # +# Store format : {name} # +# Food format : {name}|{Calorie}|{Carb}|{Protein}|{Fat} # +##################################################################### + +###################################################################### +# Version 0.1 : # +# there is only UP, once a store or canteen is # +# specified we automatically go down 1 level , for this version # +# there is no going out of a store and then coming back to add more# +# Units : Calorie : kcal : Carbs : g Protein : g : Fats : g # +###################################################################### + +&%START +Science canteen +Halal Mini Wok +Prawn Mee Soup(Dry)(Large)|490|30|20|26 +Prawn Mee Soup(Dry)(Small)|390|25|15|19 +Fried Hokkien Prawn Mee(Large)|470|40|20|20 +Fried Hokkien Prawn Mee(Small)|350|30|15|15 +Clay Pot Chicken|440|34|15|15 +Black Pepper Chicken|490|34|16|16 +&%UP +Ayam Penyet +Ayam Penyet Set|699|45|30|30 +Steamed Chicken Set |475|35|20|20 +Ikan Grouper Penyet Set|669|50|40|50 +&%UP +Korean +kimchi fried rice|520|45|35|56 +ginseng chicken|450|25|32|66 +ramen|530|76|25|43 +&%UP +Gong Cha +gong cha green tea|100|0|0|0 +gong cha ooloong tea|100|0|0|0 +gong cha bubble tea|200|0|0|0 +&%UP +&%UP +&%STOP +

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�*kGnH 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 Date: Wed, 28 Oct 2020 19:57:48 +0800 Subject: [PATCH 224/271] complete architecture --- docs/Zhong_Ming_developer_Guide/zm_DG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Zhong_Ming_developer_Guide/zm_DG.md b/docs/Zhong_Ming_developer_Guide/zm_DG.md index 50abef666a..0ecbca8d7f 100644 --- a/docs/Zhong_Ming_developer_Guide/zm_DG.md +++ b/docs/Zhong_Ming_developer_Guide/zm_DG.md @@ -5,12 +5,13 @@ At the base of the package, there is the Saver and Loader class. ### Architecture +![Alt text](Architecture.png) Note only the Saver and Loader class is flexible. They can be adapted to new situations without modifying the code. The FoodSaveLoadManager and PersonSaveLoadManager are written specifically for this version. They will have to be modified/replaced for future versions. #### Saver class -![Alt text](Architecture.png) + Stores data in a internal table with length and height specified. Handles the storage of its data by writing to a text file. From d1e0651b81ec64f797cf3d889addd4ea12708d66 Mon Sep 17 00:00:00 2001 From: snowbanana12345 <50855780+snowbanana12345@users.noreply.github.com> Date: Wed, 28 Oct 2020 20:13:34 +0800 Subject: [PATCH 225/271] manually moved UML diaghrams and DG over to this branch --- UML_diaghrams/Architecture.puml | 19 ++++++ UML_diaghrams/FoodSaveLoadManager_load.puml | 24 ++++++++ UML_diaghrams/FoodSaveLoadManager_save.puml | 24 ++++++++ UML_diaghrams/UML diagram.puml | 15 +++++ .../Architecture.png | Bin 0 -> 43003 bytes .../FoodSaveLoadManager_load.png | Bin 0 -> 77795 bytes .../FoodSaveLoadManager_save.png | Bin 0 -> 75922 bytes docs/Zhong_Ming_developer_Guide/zm_DG.md | 55 ++++++++++++++++++ 8 files changed, 137 insertions(+) create mode 100644 UML_diaghrams/Architecture.puml create mode 100644 UML_diaghrams/FoodSaveLoadManager_load.puml create mode 100644 UML_diaghrams/FoodSaveLoadManager_save.puml create mode 100644 UML_diaghrams/UML diagram.puml create mode 100644 docs/Zhong_Ming_developer_Guide/Architecture.png create mode 100644 docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_load.png create mode 100644 docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png create mode 100644 docs/Zhong_Ming_developer_Guide/zm_DG.md diff --git a/UML_diaghrams/Architecture.puml b/UML_diaghrams/Architecture.puml new file mode 100644 index 0000000000..d4ec941ef8 --- /dev/null +++ b/UML_diaghrams/Architecture.puml @@ -0,0 +1,19 @@ +@startuml +object Saver +object Loader +object FoodSaveLoadManager +object PersonSaveLoadManager +object Command +object File + +File <-up-> Saver +File <-up-> Loader + +Saver <-up-> FoodSaveLoadManager +Saver <-up-> PersonSaveLoadManager +Loader <-up-> FoodSaveLoadManager +Loader <-up-> PersonSaveLoadManager + +FoodSaveLoadManager <-up-> Command +PersonSaveLoadManager <-up-> Command +@enduml diff --git a/UML_diaghrams/FoodSaveLoadManager_load.puml b/UML_diaghrams/FoodSaveLoadManager_load.puml new file mode 100644 index 0000000000..51669578f2 --- /dev/null +++ b/UML_diaghrams/FoodSaveLoadManager_load.puml @@ -0,0 +1,24 @@ +@startuml + +-> FoodSaveLoadManager : load() +activate FoodSaveLoadManager + +FoodSaveLoadManager -> Loader : static load() + +activate Loader +Loader -> FileLoader : load() + +activate FileLoader +loop all lines + activate Scanner + FileLoader -> Scanner : readline() + Scanner --> FileLoader : line data + destroy Scanner +end +FileLoader --> Loader : FileLoader +deactivate FileLoader + +Loader --> FoodSaveLoadManager : FileLoader +deactivate Loader +deactivate FoodSaveLoadManager +@enduml \ No newline at end of file diff --git a/UML_diaghrams/FoodSaveLoadManager_save.puml b/UML_diaghrams/FoodSaveLoadManager_save.puml new file mode 100644 index 0000000000..ea1c8a4805 --- /dev/null +++ b/UML_diaghrams/FoodSaveLoadManager_save.puml @@ -0,0 +1,24 @@ +@startuml +-> FoodSaveLoadManager : save +activate FoodSaveLoadManager + + +loop all food items + loop every entry in a food object + activate Saver + FoodSaveLoadManager -> Saver : add() + end +end + +FoodSaveLoadManager -> Saver : save() +deactivate Saver + +activate FileWriter +loop all entries in Saver table + Saver -> FileWriter : write() +end +destroy FileWriter + +deactivate FoodSaveLoadManager + +@enduml \ No newline at end of file diff --git a/UML_diaghrams/UML diagram.puml b/UML_diaghrams/UML diagram.puml new file mode 100644 index 0000000000..c82d8be9d3 --- /dev/null +++ b/UML_diaghrams/UML diagram.puml @@ -0,0 +1,15 @@ + +@startuml +-> FoodSaveLoadManager : save + +loop all food items + loop every entry in a food object + FoodSaveLoadManager -> Saver : add() + end +end + +FoodSaveLoadManager -> Saver : save() +loop all entries in Saver table + Saver -> FileWriter : write() +end +@enduml \ No newline at end of file diff --git a/docs/Zhong_Ming_developer_Guide/Architecture.png b/docs/Zhong_Ming_developer_Guide/Architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..1ca758c26adedd91685225c66df5578ba73afbcc GIT binary patch literal 43003 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%0Agux07_eCdzyRD<{cnP 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 literal 0 HcmV?d00001 diff --git a/docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png b/docs/Zhong_Ming_developer_Guide/FoodSaveLoadManager_save.png new file mode 100644 index 0000000000000000000000000000000000000000..61891d2a8d921406abaf721cc2d7ec66c4a22801 GIT binary patch literal 75922 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