From 3364f087a46f8cc28157c64e65b71ffec566c758 Mon Sep 17 00:00:00 2001 From: jaredoong <88092096+jaredoong@users.noreply.github.com> Date: Fri, 3 Mar 2023 10:22:46 +0800 Subject: [PATCH 001/252] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2873e189e1..4bf4c09733 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ bin/ /text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT + + From 67ff5b2a0cc0e825e8685d8ce647d7f23c6e07a8 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 3 Mar 2023 10:51:56 +0800 Subject: [PATCH 002/252] Update name --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..00246cceb2 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:----------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) From 728380a0d4a1b2145670070ad88571a976fd316a Mon Sep 17 00:00:00 2001 From: notbingsu Date: Fri, 3 Mar 2023 10:53:04 +0800 Subject: [PATCH 003/252] Lu Bingyuan name change --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..0054b85b85 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:-----------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [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) From bef23b92a2491c832ac7bb1af03555874290f03b Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 3 Mar 2023 10:53:40 +0800 Subject: [PATCH 004/252] edit AboutUs.md --- docs/AboutUs.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..a12c5ef01c 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: +Display | Name | Github Profile | Portfolio +--------|:--------:|:--------------:|:---------: ![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | 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) | Nita | [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) From 6b65ee296317aa69219fed1af7b5b3562c10a2d4 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 3 Mar 2023 10:53:45 +0800 Subject: [PATCH 005/252] Added my name --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..b0c224a3e1 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:------------------:|:------------------------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/TopGun2001) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) From 682819abe1a1c6e4d73a248e9f58a328f8f755ff Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 3 Mar 2023 10:55:54 +0800 Subject: [PATCH 006/252] add name to about us --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..6fc978767c 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:-------------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [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) From 6f352a9de6ae0caf6a0477888564b318c092fc12 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 3 Mar 2023 11:39:23 +0800 Subject: [PATCH 007/252] Edit names in AboutUs.md --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..3bdcb09d79 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:----------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) From ae1d05a80e9bea229113005ad0f9242ceb7602d2 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 3 Mar 2023 12:46:18 +0800 Subject: [PATCH 008/252] Fix merge conflicts in AboutUs.md --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 00246cceb2..0054b85b85 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:----------:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:-----------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [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) From 4d1ff2ab048bdb206ce261ced00525993f17d0e1 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 3 Mar 2023 14:26:15 +0800 Subject: [PATCH 009/252] Add github profile --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 615ca24973..326ee4fedb 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:-----------:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [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) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:-----------:|:--------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [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) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](docs/team/johndoe.md) From 2e479a74b8da1b415ca4c27425aae4c31be17683 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 3 Mar 2023 14:35:26 +0800 Subject: [PATCH 010/252] Add github profile --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 615ca24973..326ee4fedb 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:-----------:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [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) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:-----------:|:--------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [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) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](docs/team/johndoe.md) From 13fbbfbfa9a02c39e9f0355fa74cc7062d9bc627 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 6 Mar 2023 16:20:52 +0800 Subject: [PATCH 011/252] Edit package and class names Package name: seedu.duke Package name should follow name of program instead to prevent confusion as the program scales up. Let's, * change package name to seedu.meal360 * change class name to Meal360 * edit application and shadowJar of build.gradle --- build.gradle | 4 ++-- src/main/java/seedu/duke/Duke.java | 21 ------------------- src/main/java/seedu/meal360/Meal360.java | 21 +++++++++++++++++++ .../Meal360Test.java} | 4 ++-- text-ui-test/EXPECTED.TXT | 9 ++++---- 5 files changed, 29 insertions(+), 30 deletions(-) delete mode 100644 src/main/java/seedu/duke/Duke.java create mode 100644 src/main/java/seedu/meal360/Meal360.java rename src/test/java/seedu/{duke/DukeTest.java => meal360/Meal360Test.java} (80%) diff --git a/build.gradle b/build.gradle index d5e548e85f..4338bec0a3 100644 --- a/build.gradle +++ b/build.gradle @@ -29,11 +29,11 @@ test { } application { - mainClass = "seedu.duke.Duke" + mainClass = "seedu.meal360.Meal360" } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "meal360" archiveClassifier = null } 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/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java new file mode 100644 index 0000000000..02a09db4ff --- /dev/null +++ b/src/main/java/seedu/meal360/Meal360.java @@ -0,0 +1,21 @@ +package seedu.meal360; + +import java.util.Scanner; + +public class Meal360 { + /** + * Main entry-point for the java.duke.Meal360 application. + */ + public static void main(String[] args) { + String logo = " __ __ _ ____ __ __\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/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/meal360/Meal360Test.java similarity index 80% rename from src/test/java/seedu/duke/DukeTest.java rename to src/test/java/seedu/meal360/Meal360Test.java index 2dda5fd651..85fbe967e0 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,10 +1,10 @@ -package seedu.duke; +package seedu.meal360; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; -class DukeTest { +class Meal360Test { @Test public void sampleTest() { assertTrue(true); diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 892cb6cae7..4924c2d98c 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,9 +1,8 @@ Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| + __ __ _ ____ __ __ +| \/ |___ __ _| |__ / / / / \ +| |\/| / -_) _` | ||_ \/ _ \ () | +|_| |_\___\__,_|_|___/\___/\__/ What is your name? Hello James Gosling From ffa3e1b096947ae5bb09268351617db6de6751a8 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 9 Mar 2023 15:40:25 +0800 Subject: [PATCH 012/252] Add base template with basic classes --- src/main/java/seedu/meal360/Database.java | 16 ++++++++ src/main/java/seedu/meal360/Meal360.java | 42 +++++++++++++++++---- src/main/java/seedu/meal360/Parser.java | 35 +++++++++++++++++ src/main/java/seedu/meal360/Recipe.java | 21 +++++++++++ src/main/java/seedu/meal360/RecipeList.java | 22 +++++++++++ src/main/java/seedu/meal360/Ui.java | 42 +++++++++++++++++++++ 6 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 src/main/java/seedu/meal360/Database.java create mode 100644 src/main/java/seedu/meal360/Parser.java create mode 100644 src/main/java/seedu/meal360/Recipe.java create mode 100644 src/main/java/seedu/meal360/RecipeList.java create mode 100644 src/main/java/seedu/meal360/Ui.java diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java new file mode 100644 index 0000000000..a0c46c09a8 --- /dev/null +++ b/src/main/java/seedu/meal360/Database.java @@ -0,0 +1,16 @@ +package seedu.meal360; + +public class Database { + public void createDatabase() { + // create database + } + + public String loadDatabase() { + // load database + return "database loaded"; + } + + public void saveDatabase(String recipes) { + // save database + } +} diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 02a09db4ff..59de12c0d0 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -6,16 +6,42 @@ public class Meal360 { /** * Main entry-point for the java.duke.Meal360 application. */ + + private static Boolean canExit = false; + private static final Ui ui = new Ui(); + private static final Parser parser = new Parser(); + private static final Database database = new Database(); + private static final RecipeList recipeList = new RecipeList(); + + public static void startApp() { + ui.printWelcomeMessage(); + Scanner userInput = new Scanner(System.in); + ui.printMessage("Hello " + userInput.nextLine()); + } + + public static void receiveInput(String input) { + ui.printMessage(input); + if (input.equalsIgnoreCase("bye")) { + canExit = true; + return; + } + } + + public static void exitApp() { + ui.printGoodbyeMessage(); + } + public static void main(String[] args) { - String logo = " __ __ _ ____ __ __\n" + - "| \\/ |___ __ _| |__ / / / / \\\n" + - "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + - "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + startApp(); + + String line; + Scanner userInput = new Scanner(System.in); - System.out.println("Hello from\n" + logo); - System.out.println("What is your name?"); + do { + line = userInput.nextLine(); + receiveInput(line); + } while (!canExit); - Scanner in = new Scanner(System.in); - System.out.println("Hello " + in.nextLine()); + exitApp(); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java new file mode 100644 index 0000000000..e005b39591 --- /dev/null +++ b/src/main/java/seedu/meal360/Parser.java @@ -0,0 +1,35 @@ +package seedu.meal360; + +public class Parser { + public String[] parseCommand(String command) { + return command.split(" "); + } + + public Recipe parseAddRecipe(String[] input) { + return new Recipe("test", null); + } + + public Recipe parseEditRecipe(String[] input) { + return new Recipe("test", null); + } + + public String parseDeleteRecipe(String[] input) { + return "test"; + } + + public String parsePrepareRecipe(String[] input) { + return "test"; + } + + public void parseListRecipe(String[] input) { + // list recipe + } + + public RecipeList parseLoadDatabase(String input) { + return new RecipeList(); + } + + public String parseSaveDatabase(String input) { + return "test"; + } +} diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java new file mode 100644 index 0000000000..5ab8e3cf4c --- /dev/null +++ b/src/main/java/seedu/meal360/Recipe.java @@ -0,0 +1,21 @@ +package seedu.meal360; + +import java.util.HashMap; + +public class Recipe { + private String name; + private HashMap ingredients; + + public Recipe(String name, HashMap ingredients) { + this.name = name; + this.ingredients = ingredients; + } + + public String getName() { + return name; + } + + public HashMap getIngredients() { + return ingredients; + } +} diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java new file mode 100644 index 0000000000..6deb56c9b2 --- /dev/null +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -0,0 +1,22 @@ +package seedu.meal360; + +import java.util.ArrayList; +import java.util.HashMap; + +public class RecipeList extends ArrayList { + public void addRecipe(Recipe recipe) { + + } + + public void editRecipe(String name, HashMap ingredients) { + + } + + public void deleteRecipe(String name) { + + } + + public void listRecipes() { + + } +} diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java new file mode 100644 index 0000000000..ef990cd9f5 --- /dev/null +++ b/src/main/java/seedu/meal360/Ui.java @@ -0,0 +1,42 @@ +package seedu.meal360; + +public class Ui { + private static final int BOXWIDTH = 100; + private static final String SEPARATORCHAR = "-"; + + public void printSeparator() { + String separatorLine = SEPARATORCHAR.repeat(BOXWIDTH); + System.out.println(separatorLine); + } + + public void printWelcomeMessage() { + printSeparator(); + String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + + System.out.println("Hello from\n" + logo); + System.out.println("What is your name?"); + printSeparator(); + } + + public void printGoodbyeMessage() { + printSeparator(); + System.out.println("Bye. Hope to see you again soon!"); + printSeparator(); + } + + public String formatMessage(String message) { + return String.format("| %-97s|", message); + } + + public void printMessage(String message) { + String outputMessage = formatMessage(message); + printSeparator(); + System.out.println(outputMessage); + printSeparator(); + } + + public void printRecipe(Recipe recipe) { + printMessage(recipe.getName()); + } +} From 79d13b8f537273118d547303f0ed6723d71d037e Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 9 Mar 2023 16:05:30 +0800 Subject: [PATCH 013/252] Reformat code --- src/main/java/seedu/meal360/Database.java | 1 + src/main/java/seedu/meal360/Parser.java | 1 + src/main/java/seedu/meal360/Recipe.java | 1 + src/main/java/seedu/meal360/Ui.java | 1 + 4 files changed, 4 insertions(+) diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index a0c46c09a8..6fc39a1bea 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -1,6 +1,7 @@ package seedu.meal360; public class Database { + public void createDatabase() { // create database } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index e005b39591..370be3c2d1 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,6 +1,7 @@ package seedu.meal360; public class Parser { + public String[] parseCommand(String command) { return command.split(" "); } diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 5ab8e3cf4c..a29ba10f00 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -3,6 +3,7 @@ import java.util.HashMap; public class Recipe { + private String name; private HashMap ingredients; diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index ef990cd9f5..ae907924d9 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,6 +1,7 @@ package seedu.meal360; public class Ui { + private static final int BOXWIDTH = 100; private static final String SEPARATORCHAR = "-"; From 246f7f64b489970117c6b1db2c6889adc8dcde55 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 9 Mar 2023 16:05:55 +0800 Subject: [PATCH 014/252] Fix error in reading user input --- src/main/java/seedu/meal360/Meal360.java | 4 +--- text-ui-test/EXPECTED.TXT | 12 +++++++++++- text-ui-test/input.txt | 3 ++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 59de12c0d0..8a9156f786 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -3,6 +3,7 @@ import java.util.Scanner; public class Meal360 { + /** * Main entry-point for the java.duke.Meal360 application. */ @@ -15,15 +16,12 @@ public class Meal360 { public static void startApp() { ui.printWelcomeMessage(); - Scanner userInput = new Scanner(System.in); - ui.printMessage("Hello " + userInput.nextLine()); } public static void receiveInput(String input) { ui.printMessage(input); if (input.equalsIgnoreCase("bye")) { canExit = true; - return; } } diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 4924c2d98c..c6e59b4484 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,3 +1,4 @@ +---------------------------------------------------------------------------------------------------- Hello from __ __ _ ____ __ __ | \/ |___ __ _| |__ / / / / \ @@ -5,4 +6,13 @@ Hello from |_| |_\___\__,_|_|___/\___/\__/ What is your name? -Hello James Gosling +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| James | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| bye | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +Bye. Hope to see you again soon! +---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index f6ec2e9f95..7ca2c08799 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1 +1,2 @@ -James Gosling \ No newline at end of file +James +bye From 773c491c94f261c47a9419285f9e8ca86954bfa9 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 9 Mar 2023 21:49:47 +0800 Subject: [PATCH 015/252] add delete functionality & testing for that --- src/main/java/seedu/meal360/Meal360.java | 7 ++++++ src/main/java/seedu/meal360/Parser.java | 21 +++++++++++++++-- src/main/java/seedu/meal360/RecipeList.java | 6 +++-- src/test/java/seedu/meal360/Meal360Test.java | 24 ++++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 8a9156f786..a25db0367b 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -20,8 +20,15 @@ public static void startApp() { public static void receiveInput(String input) { ui.printMessage(input); + String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; + // delete a recipe in list + } else if (command[0].equals("delete")) { + Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + ui.printMessage("Noted. I've removed this recipe:"); + ui.printMessage(deletedRecipe.toString()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 370be3c2d1..86de5c5d9d 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -14,8 +14,25 @@ public Recipe parseEditRecipe(String[] input) { return new Recipe("test", null); } - public String parseDeleteRecipe(String[] input) { - return "test"; + public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { + // user inputted recipe name + if (input[1].contains("/r")) { + // skip over /r in recipe name + String recipeName = input[1].substring(2); + int recipeIndex = 1; + for (Recipe recipe : recipeList) { + // find index of recipe we want to delete + if (recipe.getName().equals(recipeName)) { + break; + } + recipeIndex++; + } + return recipeList.deleteRecipe(recipeIndex); + // user inputted index of recipe in list + } else { + int recipeIndex = Integer.parseInt(input[1]); + return recipeList.deleteRecipe(recipeIndex); + } } public String parsePrepareRecipe(String[] input) { diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 6deb56c9b2..9e1d856806 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -12,8 +12,10 @@ public void editRecipe(String name, HashMap ingredients) { } - public void deleteRecipe(String name) { - + public Recipe deleteRecipe(int recipeNum) { + Recipe recipeToDelete = super.get(recipeNum); + super.remove(recipeToDelete); + return recipeToDelete; } public void listRecipes() { diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 85fbe967e0..c893e45079 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,12 +1,36 @@ package seedu.meal360; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import org.junit.jupiter.api.Test; +import java.util.HashMap; + class Meal360Test { @Test public void sampleTest() { assertTrue(true); } + + @Test + public void testDeleteRecipe() { + RecipeList recipeList = new RecipeList(); + // add new recipe to list + HashMap ingredients = new HashMap<>(); + Recipe newRecipe = new Recipe("", ingredients); + recipeList.addRecipe(newRecipe); + try { + int oldRecipeListSize = recipeList.size(); + // delete recipe + recipeList.deleteRecipe(recipeList.indexOf(newRecipe)); + int newRecipeListSize = recipeList.size(); + // check if recipe list size is 1 less than before + assertEquals(oldRecipeListSize - 1, newRecipeListSize); + fail(); // the test should not reach this line + } catch (Exception e) { + assertEquals("Recipe was not deleted", e.getMessage()); + } + } } From 3bad3ac61629889ba06b0ba7d72d2b698e27b727 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 9 Mar 2023 21:56:59 +0800 Subject: [PATCH 016/252] edit name in AboutUS.md --- docs/AboutUs.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index ab13ff8ace..1421f25773 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,8 +1,8 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:-----------:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Nita | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:------------------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) From 10507c4335b7fdabc937f64e572d26c6810c811a Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 9 Mar 2023 23:20:11 +0800 Subject: [PATCH 017/252] add list recipe & edit ui printMessage --- src/main/java/seedu/meal360/Meal360.java | 3 +++ src/main/java/seedu/meal360/Parser.java | 4 ++-- src/main/java/seedu/meal360/Recipe.java | 4 ++++ src/main/java/seedu/meal360/RecipeList.java | 17 ++++++++++++++++- src/main/java/seedu/meal360/Ui.java | 2 -- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 8a9156f786..5505d64f8d 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -20,8 +20,11 @@ public static void startApp() { public static void receiveInput(String input) { ui.printMessage(input); + String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; + } else if (command[0].equals("list")) { + parser.parseListRecipe(recipeList); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 370be3c2d1..8feb832135 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -22,8 +22,8 @@ public String parsePrepareRecipe(String[] input) { return "test"; } - public void parseListRecipe(String[] input) { - // list recipe + public void parseListRecipe(RecipeList recipeList) { + recipeList.listRecipes(); } public RecipeList parseLoadDatabase(String input) { diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index a29ba10f00..67b48045af 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -19,4 +19,8 @@ public String getName() { public HashMap getIngredients() { return ingredients; } + + public int getNumOfIngredients() { + return ingredients.size(); + } } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 6deb56c9b2..c98120fc4b 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -4,6 +4,7 @@ import java.util.HashMap; public class RecipeList extends ArrayList { + private static final Ui ui = new Ui(); public void addRecipe(Recipe recipe) { } @@ -16,7 +17,21 @@ public void deleteRecipe(String name) { } + // list recipe's name and ingredients public void listRecipes() { - + ui.printSeparator(); + int numberOfRecipes = this.size(); + int order = 0; + if (numberOfRecipes > 0) { + ui.printMessage("These are the recipes you have (" + numberOfRecipes + " recipes) :"); + for (Recipe recipe : this) { + order = order + 1; + ui.printMessage(order + ". " + recipe.getName() + " (" + + recipe.getNumOfIngredients() + " ingredients"); + } + } else { + ui.printMessage("There is nothing in the list. Please add a recipe."); + } + ui.printSeparator(); } } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index ae907924d9..b8558fba3f 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -32,9 +32,7 @@ public String formatMessage(String message) { public void printMessage(String message) { String outputMessage = formatMessage(message); - printSeparator(); System.out.println(outputMessage); - printSeparator(); } public void printRecipe(Recipe recipe) { From d6046c3087bee4d6e2d9c8d356bf99bff44cf573 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 9 Mar 2023 23:26:16 +0800 Subject: [PATCH 018/252] Add ability to view recipe No functionality, only able to echo user input and exit program if user input is "bye". Function to view recipes added to allow user to see any previously entered recipes. Let's add the ability to view any previously added recipes. --- src/main/java/seedu/meal360/Meal360.java | 12 ++++++++++++ src/main/java/seedu/meal360/Parser.java | 5 +++++ src/main/java/seedu/meal360/RecipeList.java | 3 ++- src/main/java/seedu/meal360/Ui.java | 9 ++++++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 8a9156f786..fb22aaedcf 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -1,5 +1,6 @@ package seedu.meal360; +import java.util.HashMap; import java.util.Scanner; public class Meal360 { @@ -16,13 +17,24 @@ public class Meal360 { public static void startApp() { ui.printWelcomeMessage(); + // Dummy recipe for testing purposes + HashMap testIngredients = new HashMap<>(); + testIngredients.put("test ingredient", 100); + Recipe testR = new Recipe("test recipe name", testIngredients); + recipeList.addRecipe(testR); + } public static void receiveInput(String input) { ui.printMessage(input); + String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; + } else if (command[0].equals("view")) { + Recipe recipe = parser.parseViewRecipe(command, recipeList); + ui.printRecipe(recipe); } + } public static void exitApp() { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 370be3c2d1..6ebbf4d72c 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -26,6 +26,11 @@ public void parseListRecipe(String[] input) { // list recipe } + public Recipe parseViewRecipe(String[] command, RecipeList recipes) { + int recipeIndex = Integer.parseInt(command[1]) - 1; + return recipes.get(recipeIndex); + } + public RecipeList parseLoadDatabase(String input) { return new RecipeList(); } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 6deb56c9b2..dab366e4b9 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -4,8 +4,9 @@ import java.util.HashMap; public class RecipeList extends ArrayList { - public void addRecipe(Recipe recipe) { + public void addRecipe(Recipe recipe) { + super.add(recipe); } public void editRecipe(String name, HashMap ingredients) { diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index ae907924d9..771c7dad61 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -38,6 +38,13 @@ public void printMessage(String message) { } public void printRecipe(Recipe recipe) { - printMessage(recipe.getName()); + printSeparator(); + System.out.println(formatMessage("Name of recipe: " + recipe.getName())); + for (String ingredient : recipe.getIngredients().keySet()) { + String outputMessage = String.format("%s(%d)", ingredient, + recipe.getIngredients().get(ingredient)); + System.out.println(formatMessage(outputMessage)); + } + printSeparator(); } } From 9e50574d3d0191c1d6fed375bf2ecc96f69ce20e Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 9 Mar 2023 23:33:44 +0800 Subject: [PATCH 019/252] Add JUnit test for viewing recipe --- src/test/java/seedu/meal360/Meal360Test.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 85fbe967e0..edaf0e67bd 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -2,11 +2,27 @@ import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.HashMap; import org.junit.jupiter.api.Test; class Meal360Test { + @Test public void sampleTest() { assertTrue(true); } + + @Test + public void testViewRecipe() { + RecipeList recipes = new RecipeList(); + HashMap testIngredients = new HashMap<>(); + testIngredients.put("test ingredient", 100); + Recipe testR = new Recipe("test recipe name", testIngredients); + recipes.addRecipe(testR); + + Parser parser = new Parser(); + Recipe recipe = parser.parseViewRecipe(new String[]{"view", "1"}, recipes); + assertTrue(recipe.getName().equals("test recipe name")); + assertTrue(recipe.getIngredients().get("test ingredient") == 100); + } } From 6b430ca31e043ca7ada3b3ead7b48c452865517f Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 9 Mar 2023 23:58:54 +0800 Subject: [PATCH 020/252] update I/O test --- src/main/java/seedu/meal360/Meal360.java | 1 - text-ui-test/EXPECTED.TXT | 5 +---- text-ui-test/input.txt | 1 + 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 5505d64f8d..6dc1808971 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -19,7 +19,6 @@ public static void startApp() { } public static void receiveInput(String input) { - ui.printMessage(input); String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index c6e59b4484..0c962944aa 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -8,10 +8,7 @@ Hello from What is your name? ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| James | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| bye | +| There is nothing in the list. Please add a recipe. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- Bye. Hope to see you again soon! diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 7ca2c08799..0fa478432d 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,2 +1,3 @@ James +list bye From 3276bce259f273ec394f93ceefc0486be18a3d19 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 10 Mar 2023 00:18:22 +0800 Subject: [PATCH 021/252] change EXPECTED.TXT --- src/main/java/seedu/meal360/RecipeList.java | 2 +- text-ui-test/EXPECTED.TXT | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index c98120fc4b..eb2d0ffaba 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -27,7 +27,7 @@ public void listRecipes() { for (Recipe recipe : this) { order = order + 1; ui.printMessage(order + ". " + recipe.getName() + " (" - + recipe.getNumOfIngredients() + " ingredients"); + + recipe.getNumOfIngredients() + " ingredients)"); } } else { ui.printMessage("There is nothing in the list. Please add a recipe."); diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 0c962944aa..ef547bb62a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -8,7 +8,8 @@ Hello from What is your name? ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| There is nothing in the list. Please add a recipe. | +| These are the recipes you have (1 recipes) : | +| 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- Bye. Hope to see you again soon! From 5954795f6ab40a6228bc6f5ab839c9756f78ea00 Mon Sep 17 00:00:00 2001 From: JuneNita <88151966+JuneNita@users.noreply.github.com> Date: Fri, 10 Mar 2023 00:20:21 +0800 Subject: [PATCH 022/252] update EXPECTED.TXT --- text-ui-test/EXPECTED.TXT | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 0c962944aa..00dbd4dca6 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -8,7 +8,8 @@ Hello from What is your name? ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| There is nothing in the list. Please add a recipe. | +| These are the recipes you have (1 recipes) : | +| 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- Bye. Hope to see you again soon! From 3260ce3b21d8d9a5f8b59c62e2b20d1a3ab9e200 Mon Sep 17 00:00:00 2001 From: JuneNita <88151966+JuneNita@users.noreply.github.com> Date: Fri, 10 Mar 2023 00:22:56 +0800 Subject: [PATCH 023/252] add the missing ')' line 31 --- src/main/java/seedu/meal360/RecipeList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index d52aeffd75..d3e8e62006 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -28,7 +28,7 @@ public void listRecipes() { for (Recipe recipe : this) { order = order + 1; ui.printMessage(order + ". " + recipe.getName() + " (" - + recipe.getNumOfIngredients() + " ingredients"); + + recipe.getNumOfIngredients() + " ingredients)"); } } else { ui.printMessage("There is nothing in the list. Please add a recipe."); From b0dd47dd4e1249701f23a2b8f0554a6071d14ff8 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 10 Mar 2023 00:23:21 +0800 Subject: [PATCH 024/252] delete duplicate import --- src/test/java/seedu/meal360/Meal360Test.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 0ee47515fa..69b8d96871 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -7,7 +7,6 @@ import java.util.HashMap; import org.junit.jupiter.api.Test; -import java.util.HashMap; class Meal360Test { From 443bbd837f036b291cd43f5d22821beb0d2a2ae1 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 10 Mar 2023 00:56:46 +0800 Subject: [PATCH 025/252] fix style issues --- src/test/java/seedu/meal360/Meal360Test.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 3a9167e7ab..581f65a427 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,8 +1,6 @@ package seedu.meal360; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; import java.util.HashMap; import org.junit.jupiter.api.Test; From 69782609e20eea5a7c8082b92ca9a2460ea1e36e Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 10 Mar 2023 01:39:23 +0800 Subject: [PATCH 026/252] fix typos --- src/main/java/seedu/meal360/Parser.java | 2 +- src/test/java/seedu/meal360/Meal360Test.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 57808b7e71..ce6c977cc5 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -16,7 +16,7 @@ public Recipe parseEditRecipe(String[] input) { public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name - if (input[1].contains("/r")) { + if (input[1].contains("r/")) { // skip over /r in recipe name String recipeName = input[1].substring(2); int recipeIndex = 1; diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 581f65a427..1464aa94ed 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -13,6 +13,7 @@ public void sampleTest() { assertTrue(true); } + @Test public void testViewRecipe() { RecipeList recipes = new RecipeList(); HashMap testIngredients = new HashMap<>(); From c29dc134cd8be9e2be3e9b12288edf44ab26ff57 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 10 Mar 2023 10:06:59 +0800 Subject: [PATCH 027/252] added create fn --- build.gradle | 4 +- docs/AboutUs.md | 15 ++-- src/main/java/seedu/duke/Duke.java | 21 ------ src/main/java/seedu/meal360/Database.java | 17 +++++ src/main/java/seedu/meal360/Meal360.java | 67 +++++++++++++++++ src/main/java/seedu/meal360/Parser.java | 77 ++++++++++++++++++++ src/main/java/seedu/meal360/Recipe.java | 26 +++++++ src/main/java/seedu/meal360/RecipeList.java | 40 ++++++++++ src/main/java/seedu/meal360/Ui.java | 48 ++++++++++++ src/test/java/seedu/duke/DukeTest.java | 12 --- src/test/java/seedu/meal360/Meal360Test.java | 47 ++++++++++++ text-ui-test/EXPECTED.TXT | 19 +++-- text-ui-test/input.txt | 4 +- 13 files changed, 347 insertions(+), 50 deletions(-) delete mode 100644 src/main/java/seedu/duke/Duke.java create mode 100644 src/main/java/seedu/meal360/Database.java create mode 100644 src/main/java/seedu/meal360/Meal360.java create mode 100644 src/main/java/seedu/meal360/Parser.java create mode 100644 src/main/java/seedu/meal360/Recipe.java create mode 100644 src/main/java/seedu/meal360/RecipeList.java create mode 100644 src/main/java/seedu/meal360/Ui.java delete mode 100644 src/test/java/seedu/duke/DukeTest.java create mode 100644 src/test/java/seedu/meal360/Meal360Test.java diff --git a/build.gradle b/build.gradle index d5e548e85f..4338bec0a3 100644 --- a/build.gradle +++ b/build.gradle @@ -29,11 +29,11 @@ test { } application { - mainClass = "seedu.duke.Duke" + mainClass = "seedu.meal360.Meal360" } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "meal360" archiveClassifier = null } diff --git a/docs/AboutUs.md b/docs/AboutUs.md index b0c224a3e1..1421f25773 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,8 @@ # About us - -Display | Name | Github Profile | Portfolio ---------|:------------------:|:------------------------------------------------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/TopGun2001) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:------------------:|:--------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) 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/meal360/Database.java b/src/main/java/seedu/meal360/Database.java new file mode 100644 index 0000000000..6fc39a1bea --- /dev/null +++ b/src/main/java/seedu/meal360/Database.java @@ -0,0 +1,17 @@ +package seedu.meal360; + +public class Database { + + public void createDatabase() { + // create database + } + + public String loadDatabase() { + // load database + return "database loaded"; + } + + public void saveDatabase(String recipes) { + // save database + } +} diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java new file mode 100644 index 0000000000..085d81a1b3 --- /dev/null +++ b/src/main/java/seedu/meal360/Meal360.java @@ -0,0 +1,67 @@ +package seedu.meal360; + +import java.util.HashMap; +import java.util.Scanner; + +public class Meal360 { + + /** + * Main entry-point for the java.duke.Meal360 application. + */ + + private static Boolean canExit = false; + private static final Ui ui = new Ui(); + private static final Parser parser = new Parser(); + private static final Database database = new Database(); + private static final RecipeList recipeList = new RecipeList(); + + public static void startApp() { + ui.printWelcomeMessage(); + // Dummy recipe for testing purposes + HashMap testIngredients = new HashMap<>(); + testIngredients.put("test ingredient", 100); + Recipe testR = new Recipe("test recipe name", testIngredients); + recipeList.addRecipe(testR); + + } + + public static void receiveInput(String input) { + String[] command = input.trim().split(" "); + if (input.equalsIgnoreCase("bye")) { + canExit = true; + // delete a recipe in list + } else if (command[0].equals("delete")) { + Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + ui.printMessage("Noted. I've removed this recipe:"); + ui.printMessage(deletedRecipe.toString()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } else if (command[0].equals("view")) { + Recipe recipe = parser.parseViewRecipe(command, recipeList); + ui.printRecipe(recipe); + } else if (command[0].equals("list")) { + parser.parseListRecipe(recipeList); + } else if (command[0].equals("add")){ + Recipe newRecipe = parser.parseAddRecipe(command, recipeList); + ui.printMessage("I've added this new recipe:" + newRecipe.getName()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } + } + + public static void exitApp() { + ui.printGoodbyeMessage(); + } + + public static void main(String[] args) { + startApp(); + + String line; + Scanner userInput = new Scanner(System.in); + + do { + line = userInput.nextLine(); + receiveInput(line); + } while (!canExit); + + exitApp(); + } +} diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java new file mode 100644 index 0000000000..32da8a04bc --- /dev/null +++ b/src/main/java/seedu/meal360/Parser.java @@ -0,0 +1,77 @@ +package seedu.meal360; + +import java.util.HashMap; +import java.util.Scanner; + + +public class Parser { + + public String[] parseCommand(String command) { + return command.split(" "); + } + + public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { + String recipeName = input[1].substring(2); + System.out.println("Please Enter The Ingredients & Quantity: "); + HashMap ingredients = new HashMap<>(); + Scanner userInput = new Scanner(System.in); + while(true){ + String line = userInput.nextLine(); + if(line.equals("done")){ + break; + } + String[] command = line.trim().split(" "); + ingredients.put(command[0], Integer.parseInt(command[1])); + } + Recipe newRecipe = new Recipe(recipeName, ingredients); + recipeList.addRecipe(newRecipe); + recipeList.add(newRecipe); + return newRecipe; + } + + public Recipe parseEditRecipe(String[] input) { + return new Recipe("test", null); + } + + public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { + // user inputted recipe name + if (input[1].contains("r/")) { + // skip over /r in recipe name + String recipeName = input[1].substring(2); + int recipeIndex = 1; + for (Recipe recipe : recipeList) { + // find index of recipe we want to delete + if (recipe.getName().equals(recipeName)) { + break; + } + recipeIndex++; + } + return recipeList.deleteRecipe(recipeIndex); + // user inputted index of recipe in list + } else { + int recipeIndex = Integer.parseInt(input[1]); + return recipeList.deleteRecipe(recipeIndex); + } + } + + public String parsePrepareRecipe(String[] input) { + return "test"; + } + + public void parseListRecipe(RecipeList recipeList) { + recipeList.listRecipes(); + } + + public Recipe parseViewRecipe(String[] command, RecipeList recipes) { + int recipeIndex = Integer.parseInt(command[1]) - 1; + return recipes.get(recipeIndex); + } + + public RecipeList parseLoadDatabase(String input) { + return new RecipeList(); + } + + public String parseSaveDatabase(String input) { + return "test"; + } +} diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java new file mode 100644 index 0000000000..67b48045af --- /dev/null +++ b/src/main/java/seedu/meal360/Recipe.java @@ -0,0 +1,26 @@ +package seedu.meal360; + +import java.util.HashMap; + +public class Recipe { + + private String name; + private HashMap ingredients; + + public Recipe(String name, HashMap ingredients) { + this.name = name; + this.ingredients = ingredients; + } + + public String getName() { + return name; + } + + public HashMap getIngredients() { + return ingredients; + } + + public int getNumOfIngredients() { + return ingredients.size(); + } +} diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java new file mode 100644 index 0000000000..b5a8058003 --- /dev/null +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -0,0 +1,40 @@ +package seedu.meal360; + +import java.util.ArrayList; +import java.util.HashMap; + +public class RecipeList extends ArrayList { + private static final Ui ui = new Ui(); + + public void addRecipe(Recipe recipe) { + super.add(recipe); + } + + public void editRecipe(String name, HashMap ingredients) { + + } + + public Recipe deleteRecipe(int recipeNum) { + Recipe recipeToDelete = super.get(recipeNum); + super.remove(recipeToDelete); + return recipeToDelete; + } + + // list recipe's name and ingredients + public void listRecipes() { + ui.printSeparator(); + int numberOfRecipes = this.size(); + int order = 0; + if (numberOfRecipes > 0) { + ui.printMessage("These are the recipes you have (" + numberOfRecipes + " recipes) :"); + for (Recipe recipe : this) { + order = order + 1; + ui.printMessage(order + ". " + recipe.getName() + " (" + + recipe.getNumOfIngredients() + " ingredients)"); + } + } else { + ui.printMessage("There is nothing in the list. Please add a recipe."); + } + ui.printSeparator(); + } +} diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java new file mode 100644 index 0000000000..01afe8a28c --- /dev/null +++ b/src/main/java/seedu/meal360/Ui.java @@ -0,0 +1,48 @@ +package seedu.meal360; + +public class Ui { + + private static final int BOXWIDTH = 100; + private static final String SEPARATORCHAR = "-"; + + public void printSeparator() { + String separatorLine = SEPARATORCHAR.repeat(BOXWIDTH); + System.out.println(separatorLine); + } + + public void printWelcomeMessage() { + printSeparator(); + String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + + System.out.println("Hello from\n" + logo); + System.out.println("What is your name?"); + printSeparator(); + } + + public void printGoodbyeMessage() { + printSeparator(); + System.out.println("Bye. Hope to see you again soon!"); + printSeparator(); + } + + public String formatMessage(String message) { + return String.format("| %-97s|", message); + } + + public void printMessage(String message) { + String outputMessage = formatMessage(message); + System.out.println(outputMessage); + } + + public void printRecipe(Recipe recipe) { + printSeparator(); + System.out.println(formatMessage("Name of recipe: " + recipe.getName())); + for (String ingredient : recipe.getIngredients().keySet()) { + String outputMessage = String.format("%s(%d)", ingredient, + recipe.getIngredients().get(ingredient)); + System.out.println(formatMessage(outputMessage)); + } + printSeparator(); + } +} diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java deleted file mode 100644 index 2dda5fd651..0000000000 --- a/src/test/java/seedu/duke/DukeTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package seedu.duke; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - -class DukeTest { - @Test - public void sampleTest() { - assertTrue(true); - } -} diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java new file mode 100644 index 0000000000..1464aa94ed --- /dev/null +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -0,0 +1,47 @@ +package seedu.meal360; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashMap; +import org.junit.jupiter.api.Test; + + +class Meal360Test { + + @Test + public void sampleTest() { + assertTrue(true); + } + + @Test + public void testViewRecipe() { + RecipeList recipes = new RecipeList(); + HashMap testIngredients = new HashMap<>(); + testIngredients.put("test ingredient", 100); + Recipe testR = new Recipe("test recipe name", testIngredients); + recipes.addRecipe(testR); + + Parser parser = new Parser(); + Recipe recipe = parser.parseViewRecipe(new String[]{"view", "1"}, recipes); + assertTrue(recipe.getName().equals("test recipe name")); + assertTrue(recipe.getIngredients().get("test ingredient") == 100); + + } + + @Test + public void testDeleteRecipe() { + RecipeList recipes = new RecipeList(); + HashMap testIngredients = new HashMap<>(); + testIngredients.put("test ingredient", 100); + // create a fake recipe + Recipe testR = new Recipe("test recipe name", testIngredients); + recipes.addRecipe(testR); + + int oldRecipeListSize = recipes.size(); + // delete recipe + recipes.deleteRecipe(recipes.indexOf(testR)); + int newRecipeListSize = recipes.size(); + // check if recipe list size is 1 less than before + assertTrue((oldRecipeListSize - 1) == newRecipeListSize); + } +} diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 892cb6cae7..00dbd4dca6 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,9 +1,16 @@ +---------------------------------------------------------------------------------------------------- Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| + __ __ _ ____ __ __ +| \/ |___ __ _| |__ / / / / \ +| |\/| / -_) _` | ||_ \/ _ \ () | +|_| |_\___\__,_|_|___/\___/\__/ What is your name? -Hello James Gosling +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| These are the recipes you have (1 recipes) : | +| 1. test recipe name (1 ingredients) | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +Bye. Hope to see you again soon! +---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index f6ec2e9f95..0fa478432d 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1 +1,3 @@ -James Gosling \ No newline at end of file +James +list +bye From 499804e4b98b6e769c6b3786b5ffeb653d78f209 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 10 Mar 2023 10:37:11 +0800 Subject: [PATCH 028/252] done --- src/main/java/seedu/meal360/Meal360.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 085d81a1b3..a1153241f4 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -53,7 +53,6 @@ public static void exitApp() { public static void main(String[] args) { startApp(); - String line; Scanner userInput = new Scanner(System.in); From 24ec3fdc6af833f668020a2e69d26edc2719dee3 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 10 Mar 2023 10:43:16 +0800 Subject: [PATCH 029/252] fixed bug --- src/main/java/seedu/meal360/Parser.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 0546ccf235..8a72dd3334 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -15,9 +15,9 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { System.out.println("Please Enter The Ingredients & Quantity: "); HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); - while(true){ + while (true) { String line = userInput.nextLine(); - if(line.equals("done")){ + if (line.equals("done")) { break; } String[] command = line.trim().split(" "); @@ -27,6 +27,7 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { recipeList.addRecipe(newRecipe); recipeList.add(newRecipe); return newRecipe; + } public Recipe parseAddRecipe(String[] input) { return new Recipe("test", null); } From 77477d4fe69515c2c6eecb3bb4632bd0316ad29b Mon Sep 17 00:00:00 2001 From: notbingsu Date: Fri, 10 Mar 2023 11:08:51 +0800 Subject: [PATCH 030/252] nothng --- text-ui-test/runtest.bat | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 25ac7a2989..a208a60b5d 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -1,6 +1,6 @@ @echo off -setlocal enableextensions -pushd %~dp0 +set local enable extensions +push d %~dp0 cd .. call gradlew clean shadowJar @@ -9,10 +9,10 @@ cd build\libs for /f "tokens=*" %%a in ( 'dir /b *.jar' ) do ( - set jarloc=%%a + set jar loc=%%a ) -java -jar %jarloc% < ..\..\text-ui-test\input.txt > ..\..\text-ui-test\ACTUAL.TXT +java -jar %jar loc% < ..\..\text-ui-test\input.txt > ..\..\text-ui-test\ACTUAL.TXT cd ..\..\text-ui-test From 081f3894c6e9ee35f46fa4c108322ce402245c80 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Fri, 10 Mar 2023 15:17:09 +0800 Subject: [PATCH 031/252] edit recipe method --- src/main/java/seedu/meal360/Meal360.java | 8 ++++-- src/main/java/seedu/meal360/Parser.java | 31 ++++++++++++++++++--- src/main/java/seedu/meal360/Recipe.java | 3 +- src/main/java/seedu/meal360/RecipeList.java | 13 +++++++-- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index a1153241f4..74fe3a55c0 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -29,7 +29,7 @@ public static void receiveInput(String input) { String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; - // delete a recipe in list + // delete a recipe in list } else if (command[0].equals("delete")) { Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); ui.printMessage("Noted. I've removed this recipe:"); @@ -40,10 +40,14 @@ public static void receiveInput(String input) { ui.printRecipe(recipe); } else if (command[0].equals("list")) { parser.parseListRecipe(recipeList); - } else if (command[0].equals("add")){ + } else if (command[0].equals("add")) { Recipe newRecipe = parser.parseAddRecipe(command, recipeList); ui.printMessage("I've added this new recipe:" + newRecipe.getName()); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } else if (command[0].equals("edit")) { + Recipe newrecipe = parser.parseEditRecipe(command, recipeList); + // ui print message + ui.printMessage("I've edited this recipe:" + newrecipe.getName()); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 8a72dd3334..0d4acba6e9 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,9 +1,9 @@ package seedu.meal360; +import java.text.BreakIterator; import java.util.HashMap; import java.util.Scanner; - public class Parser { public String[] parseCommand(String command) { @@ -23,17 +23,40 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" "); ingredients.put(command[0], Integer.parseInt(command[1])); } + userInput.close(); Recipe newRecipe = new Recipe(recipeName, ingredients); recipeList.addRecipe(newRecipe); recipeList.add(newRecipe); return newRecipe; } + public Recipe parseAddRecipe(String[] input) { return new Recipe("test", null); } - public Recipe parseEditRecipe(String[] input) { - return new Recipe("test", null); + public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { + String recipeName = input[1].substring(2); + Recipe recipeToEdit; + if (recipeList.findByName(recipeName) == null) { + // ui recipe not found + return null; + } else { + recipeToEdit = recipeList.findByName(recipeName); + } + System.out.println("Please Enter New Ingredients & Quantity: "); + HashMap ingredients = new HashMap<>(); + Scanner userInput = new Scanner(System.in); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + break; + } + String[] command = line.trim().split(" "); + ingredients.put(command[0], Integer.parseInt(command[1])); + } + userInput.close(); + recipeList.editRecipe(recipeToEdit, ingredients); + return recipeToEdit; } public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { @@ -50,7 +73,7 @@ public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { recipeIndex++; } return recipeList.deleteRecipe(recipeIndex); - // user inputted index of recipe in list + // user inputted index of recipe in list } else { int recipeIndex = Integer.parseInt(input[1]); return recipeList.deleteRecipe(recipeIndex); diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 67b48045af..281c3c61fb 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -5,7 +5,8 @@ public class Recipe { private String name; - private HashMap ingredients; + // changed ingredients to public to edit via editRecipe + public HashMap ingredients; public Recipe(String name, HashMap ingredients) { this.name = name; diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index b5a8058003..b0d9a6e244 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -6,12 +6,21 @@ public class RecipeList extends ArrayList { private static final Ui ui = new Ui(); + public Recipe findByName(String name) { + for (Recipe recipe : this) { + if (recipe.getName().equalsIgnoreCase(name)) { + return recipe; + } + } + return null; + } + public void addRecipe(Recipe recipe) { super.add(recipe); } - public void editRecipe(String name, HashMap ingredients) { - + public void editRecipe(Recipe recipe, HashMap ingredients) { + recipe.ingredients = ingredients; } public Recipe deleteRecipe(int recipeNum) { From 96e8cd54c1fa8364a3730df05352021c3b493403 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Fri, 10 Mar 2023 15:40:34 +0800 Subject: [PATCH 032/252] reformat --- src/main/java/seedu/meal360/Parser.java | 1 - src/main/java/seedu/meal360/Recipe.java | 2 +- src/main/java/seedu/meal360/RecipeList.java | 3 +-- src/main/java/seedu/meal360/Ui.java | 6 ++---- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 0d4acba6e9..ff441f3478 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,6 +1,5 @@ package seedu.meal360; -import java.text.BreakIterator; import java.util.HashMap; import java.util.Scanner; diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 281c3c61fb..f94e04da19 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -4,9 +4,9 @@ public class Recipe { - private String name; // changed ingredients to public to edit via editRecipe public HashMap ingredients; + private String name; public Recipe(String name, HashMap ingredients) { this.name = name; diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index b0d9a6e244..8531aa4e7b 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -38,8 +38,7 @@ public void listRecipes() { ui.printMessage("These are the recipes you have (" + numberOfRecipes + " recipes) :"); for (Recipe recipe : this) { order = order + 1; - ui.printMessage(order + ". " + recipe.getName() + " (" - + recipe.getNumOfIngredients() + " ingredients)"); + ui.printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); } } else { ui.printMessage("There is nothing in the list. Please add a recipe."); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 01afe8a28c..4996342294 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -12,8 +12,7 @@ public void printSeparator() { public void printWelcomeMessage() { printSeparator(); - String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" - + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; System.out.println("Hello from\n" + logo); System.out.println("What is your name?"); @@ -39,8 +38,7 @@ public void printRecipe(Recipe recipe) { printSeparator(); System.out.println(formatMessage("Name of recipe: " + recipe.getName())); for (String ingredient : recipe.getIngredients().keySet()) { - String outputMessage = String.format("%s(%d)", ingredient, - recipe.getIngredients().get(ingredient)); + String outputMessage = String.format("%s(%d)", ingredient, recipe.getIngredients().get(ingredient)); System.out.println(formatMessage(outputMessage)); } printSeparator(); From 7c7db5bc142f5bac6ce82c21733d5c1f8db2fca9 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Fri, 10 Mar 2023 15:49:57 +0800 Subject: [PATCH 033/252] reformatted --- src/main/java/seedu/meal360/RecipeList.java | 5 ++++- src/main/java/seedu/meal360/Ui.java | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 8531aa4e7b..3bc76ef3b8 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -38,7 +38,10 @@ public void listRecipes() { ui.printMessage("These are the recipes you have (" + numberOfRecipes + " recipes) :"); for (Recipe recipe : this) { order = order + 1; - ui.printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); + ui.printMessage(order + ". " + + recipe.getName() + + " (" + recipe.getNumOfIngredients() + + " ingredients)"); } } else { ui.printMessage("There is nothing in the list. Please add a recipe."); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 4996342294..565f689c1c 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -12,7 +12,10 @@ public void printSeparator() { public void printWelcomeMessage() { printSeparator(); - String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + String logo = " __ __ _ ____ __ __\n" + + "| \\/ |___ __ _| |__ / / / / \\\n" + + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; System.out.println("Hello from\n" + logo); System.out.println("What is your name?"); From ac0c01353751447eefc4e0a575b338adcdf033fd Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sat, 11 Mar 2023 16:20:07 +0800 Subject: [PATCH 034/252] new changes --- src/main/java/seedu/meal360/Parser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index ff441f3478..d596fe38f4 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -25,7 +25,6 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { userInput.close(); Recipe newRecipe = new Recipe(recipeName, ingredients); recipeList.addRecipe(newRecipe); - recipeList.add(newRecipe); return newRecipe; } From 39d7225e7eaa11263bf81822bc4d882825f06d1a Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sat, 11 Mar 2023 17:09:16 +0800 Subject: [PATCH 035/252] Updated the parseAddRecipe method --- src/main/java/seedu/meal360/Parser.java | 28 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index d596fe38f4..2da60eaadc 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -10,20 +10,31 @@ public String[] parseCommand(String command) { } public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { - String recipeName = input[1].substring(2); - System.out.println("Please Enter The Ingredients & Quantity: "); + + StringBuilder recipeName = new StringBuilder(input[2]); + for(int i = 3; i < input.length; i++){ + assert false; + recipeName.append(" ").append(input[i]); + } HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); + System.out.println("Please Enter The Ingredients & Quantity: "); while (true) { String line = userInput.nextLine(); if (line.equals("done")) { break; + } else { + String[] command = line.trim().split(" "); + StringBuilder iName = new StringBuilder(command[0]); + for(int i=1; i < command.length-1; i++){ + assert false; + iName.append(" ").append(command[i]); + } + ingredients.put(iName.toString(), Integer.parseInt(command[command.length-1])); } - String[] command = line.trim().split(" "); - ingredients.put(command[0], Integer.parseInt(command[1])); } - userInput.close(); - Recipe newRecipe = new Recipe(recipeName, ingredients); + assert false; + Recipe newRecipe = new Recipe(recipeName.toString(), ingredients); recipeList.addRecipe(newRecipe); return newRecipe; } @@ -35,6 +46,8 @@ public Recipe parseAddRecipe(String[] input) { public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String recipeName = input[1].substring(2); Recipe recipeToEdit; + HashMap ingredients = new HashMap<>(); + Scanner userInput = new Scanner(System.in); if (recipeList.findByName(recipeName) == null) { // ui recipe not found return null; @@ -42,8 +55,6 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { recipeToEdit = recipeList.findByName(recipeName); } System.out.println("Please Enter New Ingredients & Quantity: "); - HashMap ingredients = new HashMap<>(); - Scanner userInput = new Scanner(System.in); while (true) { String line = userInput.nextLine(); if (line.equals("done")) { @@ -52,7 +63,6 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" "); ingredients.put(command[0], Integer.parseInt(command[1])); } - userInput.close(); recipeList.editRecipe(recipeToEdit, ingredients); return recipeToEdit; } From ccfc469f0901b3a57129cf0d8b17081a2b210f3e Mon Sep 17 00:00:00 2001 From: jaredoong <88092096+jaredoong@users.noreply.github.com> Date: Sun, 12 Mar 2023 12:13:19 +0800 Subject: [PATCH 036/252] Update Parser.java Remove assert false statements --- src/main/java/seedu/meal360/Parser.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 2da60eaadc..bb34705cfa 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -13,7 +13,6 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { StringBuilder recipeName = new StringBuilder(input[2]); for(int i = 3; i < input.length; i++){ - assert false; recipeName.append(" ").append(input[i]); } HashMap ingredients = new HashMap<>(); @@ -27,13 +26,11 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" "); StringBuilder iName = new StringBuilder(command[0]); for(int i=1; i < command.length-1; i++){ - assert false; iName.append(" ").append(command[i]); } ingredients.put(iName.toString(), Integer.parseInt(command[command.length-1])); } } - assert false; Recipe newRecipe = new Recipe(recipeName.toString(), ingredients); recipeList.addRecipe(newRecipe); return newRecipe; From 13863a734c7c7081a58a3fcf6e97347730a6ba9a Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 12 Mar 2023 19:20:50 +0800 Subject: [PATCH 037/252] Added help tab --- src/main/java/seedu/meal360/Meal360.java | 2 ++ src/main/java/seedu/meal360/Parser.java | 18 ++++++++++++++++++ src/main/java/seedu/meal360/Ui.java | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 74fe3a55c0..dbf04fb1be 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -48,6 +48,8 @@ public static void receiveInput(String input) { Recipe newrecipe = parser.parseEditRecipe(command, recipeList); // ui print message ui.printMessage("I've edited this recipe:" + newrecipe.getName()); + } else if (command[0].equals("help")){ + parser.parseHelpUser(); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index bb34705cfa..f443b960af 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,10 +1,14 @@ package seedu.meal360; +import com.sun.security.jgss.GSSUtil; + import java.util.HashMap; import java.util.Scanner; public class Parser { + public static final Ui ui = new Ui(); + public String[] parseCommand(String command) { return command.split(" "); } @@ -85,6 +89,20 @@ public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { } } + public void parseHelpUser(){ + ui.printSeparator(); + System.out.println("These are the operations you can do. Please follow the proper input" + + " formats while typing."); + ui.printSeparator(); + System.out.println("1. Add Recipe: add /r {recipe name}"); + System.out.println("2. View Recipe: view {index number} or view /r {recipe name}"); + System.out.println("3. Edit Recipe: edit {index number} or view /r {recipe name}"); + System.out.println("4. Delete Recipe: delete {index number} or view /r {recipe name}"); + System.out.println("5. List All Recipes: list"); + System.out.println("6. Exit: bye"); + ui.printSeparator(); + } + public String parsePrepareRecipe(String[] input) { return "test"; } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 565f689c1c..76211a96af 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,5 +1,7 @@ package seedu.meal360; +import java.util.Scanner; + public class Ui { private static final int BOXWIDTH = 100; @@ -11,6 +13,7 @@ public void printSeparator() { } public void printWelcomeMessage() { + Scanner takeName = new Scanner(System.in); printSeparator(); String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + @@ -19,6 +22,9 @@ public void printWelcomeMessage() { System.out.println("Hello from\n" + logo); System.out.println("What is your name?"); + String userName = takeName.nextLine(); + printSeparator(); + System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); printSeparator(); } From 59ccf2826a1d47bff38632aed14620b15a606156 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 12 Mar 2023 19:24:37 +0800 Subject: [PATCH 038/252] changed public to private --- src/main/java/seedu/meal360/Parser.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index f443b960af..61499775ae 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,13 +1,11 @@ package seedu.meal360; -import com.sun.security.jgss.GSSUtil; - import java.util.HashMap; import java.util.Scanner; public class Parser { - public static final Ui ui = new Ui(); + private static final Ui ui = new Ui(); public String[] parseCommand(String command) { return command.split(" "); From efe79ad8a5ff7a9d5bb8d3bff058333b842516ee Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 12 Mar 2023 19:49:26 +0800 Subject: [PATCH 039/252] . --- src/main/java/seedu/meal360/Ui.java | 1 + text-ui-test/EXPECTED.TXT | 10 +++++++++- text-ui-test/input.txt | 3 ++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 76211a96af..79f51f7553 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -26,6 +26,7 @@ public void printWelcomeMessage() { printSeparator(); System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); printSeparator(); + takeName.close(); } public void printGoodbyeMessage() { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 00dbd4dca6..59e8ea5a60 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,4 +1,3 @@ ----------------------------------------------------------------------------------------------------- Hello from __ __ _ ____ __ __ | \/ |___ __ _| |__ / / / / \ @@ -6,11 +5,20 @@ Hello from |_| |_\___\__,_|_|___/\___/\__/ What is your name? +spiderman +---------------------------------------------------------------------------------------------------- +Hello spiderman! Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes) : | | 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- +view 1 +---------------------------------------------------------------------------------------------------- +| Name of recipe: test recipe name | +| test ingredient(100) | +---------------------------------------------------------------------------------------------------- +bye ---------------------------------------------------------------------------------------------------- Bye. Hope to see you again soon! ---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 0fa478432d..02cf30f37a 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,3 +1,4 @@ -James +spiderman list +view 1 bye From c8aef66832d52275f12a519c7234c3d71a4607b5 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 12 Mar 2023 19:56:03 +0800 Subject: [PATCH 040/252] . --- src/main/java/seedu/meal360/Ui.java | 10 +++++----- text-ui-test/EXPECTED.TXT | 11 +++-------- text-ui-test/input.txt | 1 - 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 79f51f7553..760cfc7293 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -13,7 +13,7 @@ public void printSeparator() { } public void printWelcomeMessage() { - Scanner takeName = new Scanner(System.in); + //Scanner takeName = new Scanner(System.in); printSeparator(); String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + @@ -22,11 +22,11 @@ public void printWelcomeMessage() { System.out.println("Hello from\n" + logo); System.out.println("What is your name?"); - String userName = takeName.nextLine(); + //String userName = takeName.nextLine(); printSeparator(); - System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); - printSeparator(); - takeName.close(); + ///System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); + //printSeparator(); + //takeName.close(); } public void printGoodbyeMessage() { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 59e8ea5a60..bc0a996f1a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,3 +1,4 @@ +---------------------------------------------------------------------------------------------------- Hello from __ __ _ ____ __ __ | \/ |___ __ _| |__ / / / / \ @@ -5,19 +6,13 @@ Hello from |_| |_\___\__,_|_|___/\___/\__/ What is your name? -spiderman ----------------------------------------------------------------------------------------------------- -Hello spiderman! Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- +spiderman +list ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes) : | | 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- -view 1 ----------------------------------------------------------------------------------------------------- -| Name of recipe: test recipe name | -| test ingredient(100) | ----------------------------------------------------------------------------------------------------- bye ---------------------------------------------------------------------------------------------------- Bye. Hope to see you again soon! diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 02cf30f37a..5fa2483e12 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,4 +1,3 @@ spiderman list -view 1 bye From 34c7c8bc569d3f98c66a62377aa27ebc1cd8c7ee Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 12 Mar 2023 19:58:44 +0800 Subject: [PATCH 041/252] . --- src/main/java/seedu/meal360/Ui.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 760cfc7293..276070073a 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,7 +1,4 @@ package seedu.meal360; - -import java.util.Scanner; - public class Ui { private static final int BOXWIDTH = 100; From f626b025c6e02743db2e25611b7bfd5621a30fce Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 12 Mar 2023 20:11:23 +0800 Subject: [PATCH 042/252] Last change --- src/main/java/seedu/meal360/Ui.java | 4 ++-- text-ui-test/EXPECTED.TXT | 5 +---- text-ui-test/input.txt | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 276070073a..dbaa5febb2 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,4 +1,5 @@ package seedu.meal360; + public class Ui { private static final int BOXWIDTH = 100; @@ -21,9 +22,8 @@ public void printWelcomeMessage() { System.out.println("What is your name?"); //String userName = takeName.nextLine(); printSeparator(); - ///System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); + //System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); //printSeparator(); - //takeName.close(); } public void printGoodbyeMessage() { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index bc0a996f1a..faf18f13f7 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -7,13 +7,10 @@ Hello from What is your name? ---------------------------------------------------------------------------------------------------- -spiderman -list ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes) : | | 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- -bye ---------------------------------------------------------------------------------------------------- Bye. Hope to see you again soon! ----------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 5fa2483e12..00d8f46bd1 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,3 +1,3 @@ -spiderman +James list -bye +bye \ No newline at end of file From ff04cee2181964098abd7a73c60aeba8a5d65cce Mon Sep 17 00:00:00 2001 From: jaredoong <88092096+jaredoong@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:59:54 +0800 Subject: [PATCH 043/252] Update EXPECTED.TXT Add newline according to error message --- 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 faf18f13f7..00dbd4dca6 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -13,4 +13,4 @@ What is your name? ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- Bye. Hope to see you again soon! ----------------------------------------------------------------------------------------------------- \ No newline at end of file +---------------------------------------------------------------------------------------------------- From 9cdef58c3d779d60306d8e157d34c0e90847fbf3 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 12 Mar 2023 22:10:56 +0800 Subject: [PATCH 044/252] Added change but fails ./runtest --- src/main/java/seedu/meal360/Ui.java | 10 ++++++---- text-ui-test/EXPECTED.TXT | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index dbaa5febb2..781f102bb5 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,5 +1,7 @@ package seedu.meal360; +import java.util.Scanner; + public class Ui { private static final int BOXWIDTH = 100; @@ -11,7 +13,6 @@ public void printSeparator() { } public void printWelcomeMessage() { - //Scanner takeName = new Scanner(System.in); printSeparator(); String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + @@ -19,11 +20,12 @@ public void printWelcomeMessage() { "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; System.out.println("Hello from\n" + logo); + String userName; + Scanner takeName = new Scanner(System.in); System.out.println("What is your name?"); - //String userName = takeName.nextLine(); + userName = takeName.nextLine(); + System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); printSeparator(); - //System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); - //printSeparator(); } public void printGoodbyeMessage() { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 00dbd4dca6..4f914748d9 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -7,6 +7,7 @@ Hello from What is your name? ---------------------------------------------------------------------------------------------------- +Hello James! Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes) : | | 1. test recipe name (1 ingredients) | From f16e1ee15b94b3c30b38943e5f461b26e6fd88a2 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 13 Mar 2023 01:32:29 +0800 Subject: [PATCH 045/252] Add exception handling to view function View function is unable to take in any command that is entirely accurate. Let's update view function to handle the following errors: * insufficient arguments * second argument is not a number * second argument is a number that is out of range --- src/main/java/seedu/meal360/Meal360.java | 35 +++++++++++++++++--- src/main/java/seedu/meal360/Parser.java | 5 +-- src/main/java/seedu/meal360/Ui.java | 8 ++--- src/test/java/seedu/meal360/Meal360Test.java | 25 ++++++++++++++ text-ui-test/input.txt | 1 + text-ui-test/runtest.bat | 8 ++--- 6 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 74fe3a55c0..ce2b240b51 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -22,7 +22,6 @@ public static void startApp() { testIngredients.put("test ingredient", 100); Recipe testR = new Recipe("test recipe name", testIngredients); recipeList.addRecipe(testR); - } public static void receiveInput(String input) { @@ -36,18 +35,44 @@ public static void receiveInput(String input) { ui.printMessage(deletedRecipe.toString()); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } else if (command[0].equals("view")) { - Recipe recipe = parser.parseViewRecipe(command, recipeList); - ui.printRecipe(recipe); + ui.printSeparator(); + try { + Recipe recipe = parser.parseViewRecipe(command, recipeList); + ui.printRecipe(recipe); + } catch (NumberFormatException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is not a number.", + command[1]); + ui.printMessage(errorMessage); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You did not enter a recipe number."); + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", + command[1]); + ui.printMessage(errorMessage); + } + ui.printSeparator(); } else if (command[0].equals("list")) { parser.parseListRecipe(recipeList); } else if (command[0].equals("add")) { + ui.printSeparator(); Recipe newRecipe = parser.parseAddRecipe(command, recipeList); ui.printMessage("I've added this new recipe:" + newRecipe.getName()); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + ui.printSeparator(); } else if (command[0].equals("edit")) { - Recipe newrecipe = parser.parseEditRecipe(command, recipeList); + ui.printSeparator(); + Recipe newRecipe = parser.parseEditRecipe(command, recipeList); // ui print message - ui.printMessage("I've edited this recipe:" + newrecipe.getName()); + ui.printMessage("I've edited this recipe:" + newRecipe.getName()); + ui.printSeparator(); + } else { + ui.printSeparator(); + ui.printMessage("I'm sorry, but I don't know what that means :-("); + ui.printSeparator(); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index bb34705cfa..a0d4685bd6 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -36,10 +36,6 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { return newRecipe; } - public Recipe parseAddRecipe(String[] input) { - return new Recipe("test", null); - } - public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String recipeName = input[1].substring(2); Recipe recipeToEdit; @@ -94,6 +90,7 @@ public void parseListRecipe(RecipeList recipeList) { } public Recipe parseViewRecipe(String[] command, RecipeList recipes) { + assert command[0].equals("view"); int recipeIndex = Integer.parseInt(command[1]) - 1; return recipes.get(recipeIndex); } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 565f689c1c..4c3ae21051 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -16,15 +16,13 @@ public void printWelcomeMessage() { "| \\/ |___ __ _| |__ / / / / \\\n" + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; - - System.out.println("Hello from\n" + logo); - System.out.println("What is your name?"); + System.out.println("Welcome to Meal360, your ultimate Recipe Manager!\n" + logo); printSeparator(); } public void printGoodbyeMessage() { printSeparator(); - System.out.println("Bye. Hope to see you again soon!"); + System.out.println(formatMessage("Bye. Hope to see you again soon!")); printSeparator(); } @@ -38,12 +36,10 @@ public void printMessage(String message) { } public void printRecipe(Recipe recipe) { - printSeparator(); System.out.println(formatMessage("Name of recipe: " + recipe.getName())); for (String ingredient : recipe.getIngredients().keySet()) { String outputMessage = String.format("%s(%d)", ingredient, recipe.getIngredients().get(ingredient)); System.out.println(formatMessage(outputMessage)); } - printSeparator(); } } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 1464aa94ed..6ea4bc3a38 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -26,6 +26,31 @@ public void testViewRecipe() { assertTrue(recipe.getName().equals("test recipe name")); assertTrue(recipe.getIngredients().get("test ingredient") == 100); + // Testing exceptions + try { + parser.parseViewRecipe(new String[]{"view"}, recipes); + } catch (ArrayIndexOutOfBoundsException e) { + assertTrue(true); + } + + try { + parser.parseViewRecipe(new String[]{"view", "a"}, recipes); + } catch (NumberFormatException e) { + assertTrue(true); + } + + try { + parser.parseViewRecipe(new String[]{"view", "2"}, recipes); + } catch (IndexOutOfBoundsException e) { + assertTrue(true); + } + + try { + parser.parseViewRecipe(new String[]{"view", "0"}, recipes); + } catch (IndexOutOfBoundsException e) { + assertTrue(true); + } + } @Test diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 0fa478432d..b2b1bd8619 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,3 +1,4 @@ James + list bye diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index a208a60b5d..25ac7a2989 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -1,6 +1,6 @@ @echo off -set local enable extensions -push d %~dp0 +setlocal enableextensions +pushd %~dp0 cd .. call gradlew clean shadowJar @@ -9,10 +9,10 @@ cd build\libs for /f "tokens=*" %%a in ( 'dir /b *.jar' ) do ( - set jar loc=%%a + set jarloc=%%a ) -java -jar %jar loc% < ..\..\text-ui-test\input.txt > ..\..\text-ui-test\ACTUAL.TXT +java -jar %jarloc% < ..\..\text-ui-test\input.txt > ..\..\text-ui-test\ACTUAL.TXT cd ..\..\text-ui-test From 2fab50a95469758652b66c9dcef808afd8330b16 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 13 Mar 2023 02:08:02 +0800 Subject: [PATCH 046/252] Update build/gradle Enable assertions when using gradle --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 4338bec0a3..fc107018c5 100644 --- a/build.gradle +++ b/build.gradle @@ -43,4 +43,5 @@ checkstyle { run{ standardInput = System.in + enableAssertions = true } From ffb68dde022a27b08d2603989d63195fa75f4275 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 13 Mar 2023 02:12:59 +0800 Subject: [PATCH 047/252] Update build/gradle Enable assertions when using gradle --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 4338bec0a3..fc107018c5 100644 --- a/build.gradle +++ b/build.gradle @@ -43,4 +43,5 @@ checkstyle { run{ standardInput = System.in + enableAssertions = true } From 8260abe8468a3d79b33152661c15f811e0f8b48a Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Mon, 13 Mar 2023 20:58:53 +0800 Subject: [PATCH 048/252] new changes --- src/main/java/seedu/meal360/Ui.java | 6 ------ text-ui-test/EXPECTED.TXT | 1 - 2 files changed, 7 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 781f102bb5..565f689c1c 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,7 +1,5 @@ package seedu.meal360; -import java.util.Scanner; - public class Ui { private static final int BOXWIDTH = 100; @@ -20,11 +18,7 @@ public void printWelcomeMessage() { "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; System.out.println("Hello from\n" + logo); - String userName; - Scanner takeName = new Scanner(System.in); System.out.println("What is your name?"); - userName = takeName.nextLine(); - System.out.println("Hello " + userName + "!" + " Welcome to Meal360, your ultimate Recipe Manager!"); printSeparator(); } diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 4f914748d9..00dbd4dca6 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -7,7 +7,6 @@ Hello from What is your name? ---------------------------------------------------------------------------------------------------- -Hello James! Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes) : | | 1. test recipe name (1 ingredients) | From a0d8be912b53d1dd2990b9cb6b2eb40a32079b6f Mon Sep 17 00:00:00 2001 From: JuneNita Date: Mon, 13 Mar 2023 21:09:01 +0800 Subject: [PATCH 049/252] update lvl of abstraction of list command --- src/main/java/seedu/meal360/Meal360.java | 3 ++- src/main/java/seedu/meal360/Parser.java | 4 ++-- src/main/java/seedu/meal360/RecipeList.java | 15 --------------- src/main/java/seedu/meal360/Ui.java | 16 ++++++++++++++++ text-ui-test/EXPECTED.TXT | 2 +- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 1e848adb5b..0d285a4a75 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -33,7 +33,8 @@ public static void receiveInput(String input) { Recipe recipe = parser.parseViewRecipe(command, recipeList); ui.printRecipe(recipe); } else if (command[0].equals("list")) { - parser.parseListRecipe(recipeList); + RecipeList recipeListToPrint = parser.parseListRecipe(recipeList); + ui.listRecipe(recipeListToPrint); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index e47ca77fc7..df8a6fdff8 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -22,8 +22,8 @@ public String parsePrepareRecipe(String[] input) { return "test"; } - public void parseListRecipe(RecipeList recipeList) { - recipeList.listRecipes(); + public RecipeList parseListRecipe(RecipeList recipeList) { + return recipeList; } public Recipe parseViewRecipe(String[] command, RecipeList recipes) { diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index d3e8e62006..b08782498f 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -18,21 +18,6 @@ public void deleteRecipe(String name) { } - // list recipe's name and ingredients public void listRecipes() { - ui.printSeparator(); - int numberOfRecipes = this.size(); - int order = 0; - if (numberOfRecipes > 0) { - ui.printMessage("These are the recipes you have (" + numberOfRecipes + " recipes) :"); - for (Recipe recipe : this) { - order = order + 1; - ui.printMessage(order + ". " + recipe.getName() + " (" - + recipe.getNumOfIngredients() + " ingredients)"); - } - } else { - ui.printMessage("There is nothing in the list. Please add a recipe."); - } - ui.printSeparator(); } } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 01afe8a28c..31f325fe4c 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -45,4 +45,20 @@ public void printRecipe(Recipe recipe) { } printSeparator(); } + + public void listRecipe(RecipeList recipeListToPrint) { + printSeparator(); + int numberOfRecipes = recipeListToPrint.size(); + int order = 0; + if (numberOfRecipes > 0) { + printMessage("These are the recipes you have (" + numberOfRecipes + " recipes):"); + for (Recipe recipe : recipeListToPrint) { + order = order + 1; + printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); + } + } else { + printMessage("There is nothing in the list. Please add a recipe."); + } + printSeparator(); + } } diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 00dbd4dca6..c4d9a1094b 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -8,7 +8,7 @@ Hello from What is your name? ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes) : | +| These are the recipes you have (1 recipes): | | 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- From 0ad279de116a393bc537f0076c635f9584b6931c Mon Sep 17 00:00:00 2001 From: JuneNita Date: Mon, 13 Mar 2023 22:06:06 +0800 Subject: [PATCH 050/252] add testListRecipe --- src/test/java/seedu/meal360/Meal360Test.java | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index edaf0e67bd..a4dac9a17b 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -25,4 +25,27 @@ public void testViewRecipe() { assertTrue(recipe.getName().equals("test recipe name")); assertTrue(recipe.getIngredients().get("test ingredient") == 100); } + + @Test + public void testListRecipe() { + RecipeList recipes = new RecipeList(); + Parser parser = new Parser(); + + HashMap testIngredients = new HashMap<>(); + testIngredients.put("test ingredient1", 10); + testIngredients.put("test ingredient2", 20); + testIngredients.put("test ingredient3", 30); + Recipe testR = new Recipe("test recipe1", testIngredients); + recipes.addRecipe(testR); + + RecipeList recipeListToPrint = parser.parseListRecipe(recipes); + assertTrue(recipeListToPrint.size() == 1); + int order = 1; + for (Recipe recipe : recipes) { + if (order == 1) { + assertTrue(recipe.getNumOfIngredients() == 3); + } + order++; + } + } } From 69182d4c393b23b88c6c303292bce1cd39827547 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Mon, 13 Mar 2023 23:31:01 +0800 Subject: [PATCH 051/252] 'list' filter by name/ingredients --- src/main/java/seedu/meal360/Meal360.java | 2 +- src/main/java/seedu/meal360/Parser.java | 11 ++++- src/main/java/seedu/meal360/RecipeList.java | 13 +++++- src/main/java/seedu/meal360/Ui.java | 17 ++++---- src/test/java/seedu/meal360/Meal360Test.java | 42 +++++++++++++++----- 5 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 0d285a4a75..e8e276f978 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -33,7 +33,7 @@ public static void receiveInput(String input) { Recipe recipe = parser.parseViewRecipe(command, recipeList); ui.printRecipe(recipe); } else if (command[0].equals("list")) { - RecipeList recipeListToPrint = parser.parseListRecipe(recipeList); + RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); ui.listRecipe(recipeListToPrint); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index df8a6fdff8..af45f64575 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -22,8 +22,15 @@ public String parsePrepareRecipe(String[] input) { return "test"; } - public RecipeList parseListRecipe(RecipeList recipeList) { - return recipeList; + public RecipeList parseListRecipe(String[] input, RecipeList recipeList) { + RecipeList recipeListToPrint = new RecipeList(); + String filter; + if (input.length == 1) { + filter = null; + } else { + filter = input[1]; + } + return recipeList.listRecipes(filter); } public Recipe parseViewRecipe(String[] command, RecipeList recipes) { diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index b08782498f..af5858b9f6 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -4,7 +4,6 @@ import java.util.HashMap; public class RecipeList extends ArrayList { - private static final Ui ui = new Ui(); public void addRecipe(Recipe recipe) { super.add(recipe); @@ -18,6 +17,16 @@ public void deleteRecipe(String name) { } - public void listRecipes() { + public RecipeList listRecipes(String filter) { + RecipeList filteredRecipeList = new RecipeList(); + if (filter == null) { + return this; + } + for (Recipe recipe: this) { + if (recipe.getName().contains(filter) || recipe.getIngredients().containsKey(filter)) { + filteredRecipeList.addRecipe(recipe); + } + } + return filteredRecipeList; } } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 31f325fe4c..e009e7b492 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -50,14 +50,15 @@ public void listRecipe(RecipeList recipeListToPrint) { printSeparator(); int numberOfRecipes = recipeListToPrint.size(); int order = 0; - if (numberOfRecipes > 0) { - printMessage("These are the recipes you have (" + numberOfRecipes + " recipes):"); - for (Recipe recipe : recipeListToPrint) { - order = order + 1; - printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); - } - } else { - printMessage("There is nothing in the list. Please add a recipe."); + if (numberOfRecipes == 0) { + printMessage("There is nothing to list."); + printSeparator(); + return; + } + printMessage("These are the recipes you have (" + numberOfRecipes + " recipes):"); + for (Recipe recipe : recipeListToPrint) { + order = order + 1; + printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); } printSeparator(); } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index a4dac9a17b..fdf4b6155d 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,5 +1,6 @@ package seedu.meal360; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.HashMap; @@ -30,22 +31,43 @@ public void testViewRecipe() { public void testListRecipe() { RecipeList recipes = new RecipeList(); Parser parser = new Parser(); + String input; + String[] command; + RecipeList recipeListToPrint; - HashMap testIngredients = new HashMap<>(); - testIngredients.put("test ingredient1", 10); - testIngredients.put("test ingredient2", 20); - testIngredients.put("test ingredient3", 30); - Recipe testR = new Recipe("test recipe1", testIngredients); - recipes.addRecipe(testR); + HashMap testIngredients1 = new HashMap<>(); + testIngredients1.put("test ingredient1-1", 10); + testIngredients1.put("test ingredient1-2", 20); + testIngredients1.put("test ingredient1-3", 30); + Recipe testRecipe1 = new Recipe("test recipe1", testIngredients1); + recipes.addRecipe(testRecipe1); - RecipeList recipeListToPrint = parser.parseListRecipe(recipes); - assertTrue(recipeListToPrint.size() == 1); + HashMap testIngredients2 = new HashMap<>(); + testIngredients2.put("test ingredient2-1", 10); + testIngredients2.put("test ingredient2-2", 20); + Recipe testRecipe2 = new Recipe("test recipe2", testIngredients2); + recipes.addRecipe(testRecipe2); + + input = "list"; + command = input.split(" ",2); + recipeListToPrint = parser.parseListRecipe(command, recipes); + assertEquals(2, recipeListToPrint.size()); int order = 1; for (Recipe recipe : recipes) { - if (order == 1) { - assertTrue(recipe.getNumOfIngredients() == 3); + switch(order) { + case 1: assertEquals(3, recipe.getNumOfIngredients()); + break; + case 2: assertEquals(2, recipe.getNumOfIngredients()); + break; + default: assertTrue(false); } order++; } + + input = "list test ingredient2-1"; + command = input.split(" ",2); + recipeListToPrint = parser.parseListRecipe(command, recipes); + assertEquals(1, recipeListToPrint.size()); + assertEquals(2, recipeListToPrint.get(0).getNumOfIngredients()); } } From 326146fd8cc0213bc42db2787cbea6d7e0b1999c Mon Sep 17 00:00:00 2001 From: JuneNita Date: Mon, 13 Mar 2023 23:48:11 +0800 Subject: [PATCH 052/252] add 'list' to user guide --- docs/UserGuide.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..ac7ad6a09c 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -14,6 +14,7 @@ ## Features {Give detailed description of each feature} +* Listing relevant recipes ### Adding a todo: `todo` Adds a new item to the list of todo items. @@ -29,6 +30,21 @@ Example of usage: `todo n/Refactor the User Guide to remove passive voice d/13/04/2020` +### Listing recipes: `list` +List all recipes or filtered list recipes by the name or ingredients. + +Format: `list [NAME/INGREDIENTS]` + +* The `NAME/INGREDIENTS` is optional. +* To list all recipes, do not add `NAME/INGREDIENTS`. + + +Example of usage: + +`list` + +`list pizza` + ## FAQ **Q**: How do I transfer my data to another computer? @@ -40,3 +56,4 @@ Example of usage: {Give a 'cheat sheet' of commands here} * Add todo `todo n/TODO_NAME d/DEADLINE` +* List recipe `list [KEYWORD]` From 53ec20cb5e6dd189296ddabe9186979cc7c13a9d Mon Sep 17 00:00:00 2001 From: jaredoong Date: Tue, 14 Mar 2023 00:04:04 +0800 Subject: [PATCH 053/252] Add function to create weekly plan Includes function of adding recipes to weekly plan, deleting recipes from weekly plan, and viewing list of recipes and their respective count --- src/main/java/seedu/meal360/Meal360.java | 26 ++++++++++++++++ src/main/java/seedu/meal360/Parser.java | 33 ++++++++++++++++++--- src/main/java/seedu/meal360/Ui.java | 9 ++++++ src/main/java/seedu/meal360/WeeklyPlan.java | 18 +++++++++++ 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/main/java/seedu/meal360/WeeklyPlan.java diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index ce2b240b51..a55f75a784 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -14,6 +14,7 @@ public class Meal360 { private static final Parser parser = new Parser(); private static final Database database = new Database(); private static final RecipeList recipeList = new RecipeList(); + private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); public static void startApp() { ui.printWelcomeMessage(); @@ -69,6 +70,31 @@ public static void receiveInput(String input) { // ui print message ui.printMessage("I've edited this recipe:" + newRecipe.getName()); ui.printSeparator(); + } else if (command[0].equals("weekly")) { + try { + ui.printSeparator(); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); + + if (command[1].equals("/add")) { + ui.printMessage("I've added the recipe to your weekly plan!"); + weeklyPlan.addPlan(recipeMap); + } else if (command[1].equals("/delete")) { + ui.printMessage("I've deleted the recipe from your weekly plan!"); + weeklyPlan.deletePlan(recipeMap); + } + } catch (NumberFormatException e) { + String errorMessage = String.format( + "Please enter a valid number as the last argument."); + ui.printMessage(errorMessage); + } catch (IllegalArgumentException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("weeklyplan")) { + ui.printSeparator(); + ui.printMessage("Here is your weekly plan:"); + ui.printWeeklyPlan(weeklyPlan); + ui.printSeparator(); } else { ui.printSeparator(); ui.printMessage("I'm sorry, but I don't know what that means :-("); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index a0d4685bd6..9051a8c6c5 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -10,9 +10,8 @@ public String[] parseCommand(String command) { } public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { - StringBuilder recipeName = new StringBuilder(input[2]); - for(int i = 3; i < input.length; i++){ + for (int i = 3; i < input.length; i++) { recipeName.append(" ").append(input[i]); } HashMap ingredients = new HashMap<>(); @@ -25,10 +24,10 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { } else { String[] command = line.trim().split(" "); StringBuilder iName = new StringBuilder(command[0]); - for(int i=1; i < command.length-1; i++){ + for (int i = 1; i < command.length - 1; i++) { iName.append(" ").append(command[i]); } - ingredients.put(iName.toString(), Integer.parseInt(command[command.length-1])); + ingredients.put(iName.toString(), Integer.parseInt(command[command.length - 1])); } } Recipe newRecipe = new Recipe(recipeName.toString(), ingredients); @@ -95,6 +94,32 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { return recipes.get(recipeIndex); } + public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { + if (!command[1].equals("/add") && !command[1].equals("/delete")) { + throw new IllegalArgumentException( + "Please indicate if you would want to add or delete the recipe from your weekly " + + "plan."); + } + + int numDays = 0; + if (command[1].equals("/add")) { + numDays = Integer.parseInt(command[command.length - 1]); + } + + WeeklyPlan addToPlan = new WeeklyPlan(); + StringBuilder recipeName = new StringBuilder(command[2]); + for (int i = 3; i < command.length - 1; i++) { + recipeName.append(" ").append(command[i]); + } + + if (recipes.findByName(recipeName.toString()) != null) { + addToPlan.put(recipeName.toString(), numDays); + return addToPlan; + } else { + throw new IllegalArgumentException("Please indicate a valid recipe name."); + } + } + public RecipeList parseLoadDatabase(String input) { return new RecipeList(); } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 4c3ae21051..9fae720243 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,5 +1,7 @@ package seedu.meal360; +import java.util.HashMap; + public class Ui { private static final int BOXWIDTH = 100; @@ -42,4 +44,11 @@ public void printRecipe(Recipe recipe) { System.out.println(formatMessage(outputMessage)); } } + + public void printWeeklyPlan(HashMap weeklyPlan) { + weeklyPlan.forEach((recipe, count) -> { + String outputMessage = String.format("%s: %d times", recipe, count); + printMessage(outputMessage); + }); + } } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java new file mode 100644 index 0000000000..d6d1635e51 --- /dev/null +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -0,0 +1,18 @@ +package seedu.meal360; + +import java.util.HashMap; + +public class WeeklyPlan extends HashMap { + + public void addPlan(HashMap recipeMap) { + recipeMap.forEach((recipe, count) -> { + this.put(recipe, count); + }); + } + + public void deletePlan(HashMap recipeMap) { + recipeMap.forEach((recipe, count) -> { + this.remove(recipe); + }); + } +} From 2a105e45399ab275653ec5524a381eb2c326b7ce Mon Sep 17 00:00:00 2001 From: jaredoong Date: Tue, 14 Mar 2023 00:06:29 +0800 Subject: [PATCH 054/252] Update viewing of weekly plan Edit output message from program when weekly plan is empty --- src/main/java/seedu/meal360/Meal360.java | 1 - src/main/java/seedu/meal360/Ui.java | 16 +++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index a55f75a784..997d0fdf2a 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -92,7 +92,6 @@ public static void receiveInput(String input) { ui.printSeparator(); } else if (command[0].equals("weeklyplan")) { ui.printSeparator(); - ui.printMessage("Here is your weekly plan:"); ui.printWeeklyPlan(weeklyPlan); ui.printSeparator(); } else { diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 9fae720243..0a5ba61225 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -45,10 +45,16 @@ public void printRecipe(Recipe recipe) { } } - public void printWeeklyPlan(HashMap weeklyPlan) { - weeklyPlan.forEach((recipe, count) -> { - String outputMessage = String.format("%s: %d times", recipe, count); - printMessage(outputMessage); - }); + public void printWeeklyPlan(WeeklyPlan weeklyPlan) { + if (weeklyPlan.isEmpty()) { + printMessage("Your weekly plan is empty!"); + } else { + printMessage("Here is your weekly plan:"); + weeklyPlan.forEach((recipe, count) -> { + String outputMessage = String.format("%s: %d times", recipe, count); + printMessage(outputMessage); + }); + } + } } From b2bea036244436f1669ce184e90f6e42445277ed Mon Sep 17 00:00:00 2001 From: JuneNita Date: Tue, 14 Mar 2023 00:11:53 +0800 Subject: [PATCH 055/252] 'list' with multiple filter (&) --- src/main/java/seedu/meal360/Parser.java | 13 ++++++------- src/main/java/seedu/meal360/RecipeList.java | 16 +++++++++------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index af45f64575..54d5638ccc 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -22,15 +22,14 @@ public String parsePrepareRecipe(String[] input) { return "test"; } - public RecipeList parseListRecipe(String[] input, RecipeList recipeList) { - RecipeList recipeListToPrint = new RecipeList(); - String filter; - if (input.length == 1) { - filter = null; + public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { + String[] filters; + if (inputs.length == 1) { + filters = null; } else { - filter = input[1]; + filters = inputs[1].split("&"); } - return recipeList.listRecipes(filter); + return recipeList.listRecipes(filters); } public Recipe parseViewRecipe(String[] command, RecipeList recipes) { diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index af5858b9f6..4cae5f99f2 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -17,14 +17,16 @@ public void deleteRecipe(String name) { } - public RecipeList listRecipes(String filter) { - RecipeList filteredRecipeList = new RecipeList(); - if (filter == null) { - return this; + public RecipeList listRecipes(String[] filters) { + RecipeList filteredRecipeList = this; + if (filters == null) { + return filteredRecipeList; } - for (Recipe recipe: this) { - if (recipe.getName().contains(filter) || recipe.getIngredients().containsKey(filter)) { - filteredRecipeList.addRecipe(recipe); + for (String filter : filters) { + for (Recipe recipe: filteredRecipeList) { + if (!recipe.getName().contains(filter) && !recipe.getIngredients().containsKey(filter)) { + filteredRecipeList.remove(recipe); + } } } return filteredRecipeList; From e11008c0fcf4a77e8e1378ae5a5a32c86c8fb883 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Tue, 14 Mar 2023 00:45:25 +0800 Subject: [PATCH 056/252] update 'list' with & filter and testListRecipe --- src/main/java/seedu/meal360/RecipeList.java | 10 ++++---- src/test/java/seedu/meal360/Meal360Test.java | 25 +++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 4cae5f99f2..330b97911e 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -18,12 +18,14 @@ public void deleteRecipe(String name) { } public RecipeList listRecipes(String[] filters) { - RecipeList filteredRecipeList = this; + RecipeList filteredRecipeList = new RecipeList(); if (filters == null) { - return filteredRecipeList; + return this; } - for (String filter : filters) { - for (Recipe recipe: filteredRecipeList) { + for (Recipe recipe: this) { + filteredRecipeList.add(recipe); + for (String filter : filters) { + filter = filter.trim(); if (!recipe.getName().contains(filter) && !recipe.getIngredients().containsKey(filter)) { filteredRecipeList.remove(recipe); } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index fdf4b6155d..c0c4c6bad7 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,11 +1,11 @@ package seedu.meal360; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.util.HashMap; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + class Meal360Test { @Test @@ -52,22 +52,19 @@ public void testListRecipe() { command = input.split(" ",2); recipeListToPrint = parser.parseListRecipe(command, recipes); assertEquals(2, recipeListToPrint.size()); - int order = 1; - for (Recipe recipe : recipes) { - switch(order) { - case 1: assertEquals(3, recipe.getNumOfIngredients()); - break; - case 2: assertEquals(2, recipe.getNumOfIngredients()); - break; - default: assertTrue(false); - } - order++; - } + assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); + assertEquals(2, recipeListToPrint.get(1).getNumOfIngredients()); input = "list test ingredient2-1"; command = input.split(" ",2); recipeListToPrint = parser.parseListRecipe(command, recipes); assertEquals(1, recipeListToPrint.size()); assertEquals(2, recipeListToPrint.get(0).getNumOfIngredients()); + assertEquals("test recipe2", recipeListToPrint.get(0).getName()); + + input = "list test ingredient2-1 & test recipe1"; + command = input.split(" ",2); + recipeListToPrint = parser.parseListRecipe(command, recipes); + assertEquals(0, recipeListToPrint.size()); } } From 664e47fa8e29ab8684fac07f80ebfd0c8b68c293 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Tue, 14 Mar 2023 00:54:36 +0800 Subject: [PATCH 057/252] update 'list' --- docs/UserGuide.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index ac7ad6a09c..0d8d3b111f 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -33,17 +33,19 @@ Example of usage: ### Listing recipes: `list` List all recipes or filtered list recipes by the name or ingredients. -Format: `list [NAME/INGREDIENTS]` +Format: `list [KEYWORD & KEYWORD & ...]` -* The `NAME/INGREDIENTS` is optional. -* To list all recipes, do not add `NAME/INGREDIENTS`. +* The `KEYWORD` is optional. It can be a name of recipe or ingredients. +* To list all recipes, do not add `KEYWORD`. +* Use `&` to list all the recipe that contain all specified keywords. Example of usage: `list` - `list pizza` +`list milk & egg` + ## FAQ From ccdbf3c37c1e5bc5508f599ec6b810199bc38854 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Tue, 14 Mar 2023 01:24:00 +0800 Subject: [PATCH 058/252] Update JUnit test Include JUnit test for weekly plan functionality --- src/main/java/seedu/meal360/Parser.java | 3 + src/main/java/seedu/meal360/Ui.java | 13 +- src/main/java/seedu/meal360/WeeklyPlan.java | 4 +- src/test/java/seedu/meal360/Meal360Test.java | 159 +++++++++++++++++-- 4 files changed, 156 insertions(+), 23 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 9051a8c6c5..9001403e6e 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -104,6 +104,9 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { int numDays = 0; if (command[1].equals("/add")) { numDays = Integer.parseInt(command[command.length - 1]); + if (numDays < 1) { + throw new NumberFormatException(); + } } WeeklyPlan addToPlan = new WeeklyPlan(); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 0a5ba61225..1a2adb9683 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,7 +1,5 @@ package seedu.meal360; -import java.util.HashMap; - public class Ui { private static final int BOXWIDTH = 100; @@ -14,10 +12,8 @@ public void printSeparator() { public void printWelcomeMessage() { printSeparator(); - String logo = " __ __ _ ____ __ __\n" + - "| \\/ |___ __ _| |__ / / / / \\\n" + - "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + - "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; System.out.println("Welcome to Meal360, your ultimate Recipe Manager!\n" + logo); printSeparator(); } @@ -40,7 +36,8 @@ public void printMessage(String message) { public void printRecipe(Recipe recipe) { System.out.println(formatMessage("Name of recipe: " + recipe.getName())); for (String ingredient : recipe.getIngredients().keySet()) { - String outputMessage = String.format("%s(%d)", ingredient, recipe.getIngredients().get(ingredient)); + String outputMessage = String.format("%s(%d)", ingredient, + recipe.getIngredients().get(ingredient)); System.out.println(formatMessage(outputMessage)); } } @@ -51,7 +48,7 @@ public void printWeeklyPlan(WeeklyPlan weeklyPlan) { } else { printMessage("Here is your weekly plan:"); weeklyPlan.forEach((recipe, count) -> { - String outputMessage = String.format("%s: %d times", recipe, count); + String outputMessage = String.format("%s x%d", recipe, count); printMessage(outputMessage); }); } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index d6d1635e51..f64835ae62 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -4,13 +4,13 @@ public class WeeklyPlan extends HashMap { - public void addPlan(HashMap recipeMap) { + public void addPlan(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { this.put(recipe, count); }); } - public void deletePlan(HashMap recipeMap) { + public void deletePlan(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { this.remove(recipe); }); diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 6ea4bc3a38..d594ba6ca0 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,30 +1,72 @@ package seedu.meal360; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.HashMap; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class Meal360Test { - @Test - public void sampleTest() { - assertTrue(true); + private static final RecipeList recipes = new RecipeList(); + private static final Parser parser = new Parser(); + private static final Ui ui = new Ui(); + + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + + @BeforeEach + public void setUpStreams() { + System.setOut(new PrintStream(outContent)); + } + + @AfterEach + public void restoreStreams() { + System.setOut(originalOut); + } + + @BeforeAll + public static void setUp() { + // Adding of recipes + HashMap burgerIngredients = new HashMap<>(); + burgerIngredients.put("buns", 2); + burgerIngredients.put("meat patty", 1); + burgerIngredients.put("lettuce", 3); + Recipe burger = new Recipe("burger", burgerIngredients); + + HashMap pizzaIngredients = new HashMap<>(); + pizzaIngredients.put("dough", 1); + pizzaIngredients.put("tomato sauce", 1); + pizzaIngredients.put("cheese", 1); + pizzaIngredients.put("pepperoni", 1); + Recipe pizza = new Recipe("pizza", pizzaIngredients); + + HashMap saladIngredients = new HashMap<>(); + saladIngredients.put("lettuce", 1); + saladIngredients.put("tomato", 1); + saladIngredients.put("cucumber", 1); + Recipe salad = new Recipe("salad", saladIngredients); + + recipes.addRecipe(burger); + recipes.addRecipe(pizza); + recipes.addRecipe(salad); } @Test public void testViewRecipe() { - RecipeList recipes = new RecipeList(); - HashMap testIngredients = new HashMap<>(); - testIngredients.put("test ingredient", 100); - Recipe testR = new Recipe("test recipe name", testIngredients); - recipes.addRecipe(testR); - Parser parser = new Parser(); Recipe recipe = parser.parseViewRecipe(new String[]{"view", "1"}, recipes); - assertTrue(recipe.getName().equals("test recipe name")); - assertTrue(recipe.getIngredients().get("test ingredient") == 100); + assertEquals("burger", recipe.getName()); + assertEquals(2, (int) recipe.getIngredients().get("buns")); + assertEquals(1, (int) recipe.getIngredients().get("meat patty")); + assertEquals(3, (int) recipe.getIngredients().get("lettuce")); // Testing exceptions try { @@ -40,7 +82,7 @@ public void testViewRecipe() { } try { - parser.parseViewRecipe(new String[]{"view", "2"}, recipes); + parser.parseViewRecipe(new String[]{"view", "5"}, recipes); } catch (IndexOutOfBoundsException e) { assertTrue(true); } @@ -55,7 +97,6 @@ public void testViewRecipe() { @Test public void testDeleteRecipe() { - RecipeList recipes = new RecipeList(); HashMap testIngredients = new HashMap<>(); testIngredients.put("test ingredient", 100); // create a fake recipe @@ -69,4 +110,96 @@ public void testDeleteRecipe() { // check if recipe list size is 1 less than before assertTrue((oldRecipeListSize - 1) == newRecipeListSize); } + + @Test + public void testAddWeeklyPlan() { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + WeeklyPlan recipeMap; + + // Testing add recipe to weekly plan + recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "1"}, recipes); + weeklyPlan.addPlan(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(1, (int) weeklyPlan.get("burger")); + assertFalse(weeklyPlan.containsKey("pizza")); + + recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/add", "pizza", "3"}, recipes); + weeklyPlan.addPlan(recipeMap); + assertTrue(weeklyPlan.containsKey("pizza")); + assertEquals(3, (int) weeklyPlan.get("pizza")); + + // Testing exceptions + try { + parser.parseWeeklyPlan(new String[]{"weekly", "burger", "1"}, recipes); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + try { + parser.parseWeeklyPlan(new String[]{"weekly", "burger"}, recipes); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + try { + parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger"}, recipes); + } catch (NumberFormatException e) { + assertTrue(true); + } + + try { + parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "a"}, recipes); + } catch (NumberFormatException e) { + assertTrue(true); + } + + try { + parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "0"}, recipes); + } catch (NumberFormatException e) { + assertTrue(true); + } + + try { + parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "-9"}, recipes); + } catch (NumberFormatException e) { + assertTrue(true); + } + } + + @Test + public void testDeleteWeeklyPlan() { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + weeklyPlan.put("salad", 1); + weeklyPlan.put("pizza", 3); + + // Testing delete recipe from weekly plan + int oldWeeklyPlanSize = weeklyPlan.size(); + WeeklyPlan toDelete = new WeeklyPlan(); + toDelete.put("burger", 0); + weeklyPlan.deletePlan(toDelete); + int newWeeklyPlanSize = weeklyPlan.size(); + assertEquals(oldWeeklyPlanSize, newWeeklyPlanSize); + + toDelete.put("salad", 0); + weeklyPlan.deletePlan(toDelete); + newWeeklyPlanSize = weeklyPlan.size(); + assertEquals(oldWeeklyPlanSize - 1, newWeeklyPlanSize); + } + + @Test + public void testViewEmptyWeeklyPlan() { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + ui.printWeeklyPlan(weeklyPlan); + assertEquals(ui.formatMessage("Your weekly plan is empty!"), outContent.toString().trim()); + } + + @Test + public void testViewNonEmptyWeeklyPlan() { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + weeklyPlan.put("salad", 1); + ui.printWeeklyPlan(weeklyPlan); + assertEquals( + ui.formatMessage("Here is your weekly plan:") + System.lineSeparator() + ui.formatMessage( + "salad x1"), outContent.toString().trim()); + } } From 95fd20436b1d7b612eb9b0efa9c2b710e6e6932f Mon Sep 17 00:00:00 2001 From: jaredoong Date: Tue, 14 Mar 2023 02:35:00 +0800 Subject: [PATCH 059/252] Update runtest.bat Include new functions as test input --- text-ui-test/EXPECTED.TXT | 42 +++++++++++++++++++++++++++++++++++---- text-ui-test/input.txt | 13 ++++++++++-- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 00dbd4dca6..4dd511cc0d 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,16 +1,50 @@ ---------------------------------------------------------------------------------------------------- -Hello from +Welcome to Meal360, your ultimate Recipe Manager! __ __ _ ____ __ __ | \/ |___ __ _| |__ / / / / \ | |\/| / -_) _` | ||_ \/ _ \ () | |_| |_\___\__,_|_|___/\___/\__/ -What is your name? ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes) : | +| These are the recipes you have (1 recipes): | | 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -Bye. Hope to see you again soon! +| Please enter a valid recipe number. You did not enter a recipe number. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Name of recipe: test recipe name | +| test ingredient(100) | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please enter a valid recipe number. You entered -2, which is out of bounds. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please enter a valid recipe number. You entered abc, which is not a number. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Insufficient number of arguments provided. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please indicate if you would want to add or delete the recipe from your weekly plan. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please indicate a valid recipe name. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| I've added the recipe to your weekly plan! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your weekly plan: | +| test recipe name x1 | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| I've deleted the recipe from your weekly plan! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Your weekly plan is empty! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Bye. Hope to see you again soon! | ---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index b2b1bd8619..6617787d55 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,4 +1,13 @@ -James - list +view +view 1 +view -2 +view abc +weekly +weekly random name +weekly /add random name 1 +weekly /add test recipe name 1 +weeklyplan +weekly /delete test recipe name +weeklyplan bye From 06564ccb05b92b6573c567083fd8daef6af95d82 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Tue, 14 Mar 2023 12:02:44 +0800 Subject: [PATCH 060/252] Update user guide Minor edits to variable name too --- docs/UserGuide.md | 101 +++++++++++++++++------- src/main/java/seedu/meal360/Parser.java | 6 +- 2 files changed, 77 insertions(+), 30 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 0d8d3b111f..c5dcffc970 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,35 +2,27 @@ ## Introduction -{Give a product intro} +Meal360 is a desktop app for managing your recipes, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI apps. + +___ ## Quick Start -{Give steps to get started quickly} +1. Ensure that you have Java 11 or above installed. +2. Down the latest version of `Duke` from [here](http://link.to/duke). -1. Ensure that you have Java 11 or above installed. -1. Down the latest version of `Duke` from [here](http://link.to/duke). +___ -## Features +## Features -{Give detailed description of each feature} +* View recipes * Listing relevant recipes - -### 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` +* Add recipes to weekly plan +* Remove recipes from weekly plan +* View weekly plan ### Listing recipes: `list` + List all recipes or filtered list recipes by the name or ingredients. Format: `list [KEYWORD & KEYWORD & ...]` @@ -39,23 +31,78 @@ Format: `list [KEYWORD & KEYWORD & ...]` * To list all recipes, do not add `KEYWORD`. * Use `&` to list all the recipe that contain all specified keywords. - Example of usage: `list` `list pizza` `list milk & egg` +### Viewing recipes: `view` + +Views the list of ingredients and their quantities for a recipe. + +Format: `view INDEX` + +* Views the recipe at the specified `INDEX`. +* The index refers to the index number shown in the displayed person list. +* The index **must be a positive integer** 1,2,3, ... + +Example of usage: + +`view 1` + +### Adding to this week's plan: `weekly /add` + +Adds an existing recipe to this week's plan. + +Format: `weekly /add RECIPE NAME QUANTITY` + +* Adds the specified `RECIPE NAME` to this week's plan`[QUANTITY]` number of times. +* The recipe name refers to the name of the recipe shown in the displayed recipe list. +* The quantity **must be a positive + integer** 1,2,3, ... + +Example of usage: + +* `weekly /add pizza 2` adds pizza to this week's plan twice. +* `weekly /add burger 1` adds burger to this week's plan once. + +### Deleting from this week's plan: `weekly /delete` + +Deletes an existing recipe from this week's plan. + +Format: `weekly /delete RECIPE NAME` + +* Deletes the specified `RECIPE NAME` to this week's plan. +* The recipe name refers to the name of the recipe shown in the displayed recipe list. + +Example of usage: + +* `weekly /remove pizza` removes pizza from this week's plan. + +### View this week's plan: `weeklyplan` + +View this week's plan. + +Format: `weeklyplan` + +### Exit the program: `bye` + +Exits the program. + +Format: `bye` ## FAQ -**Q**: How do I transfer my data to another computer? +**Q**: How do I transfer my data to another computer? **A**: {your answer here} ## Command Summary - -{Give a 'cheat sheet' of commands here} - -* Add todo `todo n/TODO_NAME d/DEADLINE` -* List recipe `list [KEYWORD]` +| Action | Format, Examples | +|--------|---------------------------------------| +|List recipe | `list [KEYWORD]`
e.g `list pizza` | +|View recipe | `view INDEX`
e.g `view 1` | +|Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | +|Delete from weekly plan | `weekly /delete RECIPE NAME`
e.g `weekly /delete pizza` | +|View weekly plan | `weeklyplan` | diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 78844b227f..4813a208f8 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -108,15 +108,15 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { } int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; - WeeklyPlan addToPlan = new WeeklyPlan(); + WeeklyPlan thisWeekPlan = new WeeklyPlan(); StringBuilder recipeName = new StringBuilder(command[2]); for (int i = 3; i < nameLastIndex; i++) { recipeName.append(" ").append(command[i]); } if (recipes.findByName(recipeName.toString().trim()) != null) { - addToPlan.put(recipeName.toString(), numDays); - return addToPlan; + thisWeekPlan.put(recipeName.toString(), numDays); + return thisWeekPlan; } else { throw new IllegalArgumentException("Please indicate a valid recipe name."); } From 4913f207a2b2b2f865b260c95f4a7e278036c2cb Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Tue, 14 Mar 2023 17:58:02 +0800 Subject: [PATCH 061/252] fix delete functionality & add exceptions --- src/main/java/seedu/meal360/Meal360.java | 22 +++++++++++++++++----- src/main/java/seedu/meal360/Parser.java | 11 ++++++----- src/main/java/seedu/meal360/Recipe.java | 1 + 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index beba2520f6..50cb64595b 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -29,12 +29,24 @@ public static void receiveInput(String input) { String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; - // delete a recipe in list } else if (command[0].equals("delete")) { - Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); - ui.printMessage("Noted. I've removed this recipe:"); - ui.printMessage(deletedRecipe.toString()); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + ui.printSeparator(); + try { + Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + ui.printMessage("Noted. I've removed this recipe:"); + ui.printMessage(deletedRecipe.getName()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number or name. You did not enter a recipe number or name."); + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number or mame. You entered %s, " + "which is in ivalid.", + command[1]); + ui.printMessage(errorMessage); + } + ui.printSeparator(); } else if (command[0].equals("view")) { ui.printSeparator(); try { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 4813a208f8..60f5ded148 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -59,20 +59,21 @@ public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name if (input[1].contains("r/")) { // skip over /r in recipe name - String recipeName = input[1].substring(2); - int recipeIndex = 1; + String recipeToDelete = input[1].substring(2); + int recipeIndex = 0; for (Recipe recipe : recipeList) { // find index of recipe we want to delete - if (recipe.getName().equals(recipeName)) { + if (recipe.getName().equals(recipeToDelete)) { break; } recipeIndex++; } return recipeList.deleteRecipe(recipeIndex); - // user inputted index of recipe in list + // user inputted index of recipe in list } else { int recipeIndex = Integer.parseInt(input[1]); - return recipeList.deleteRecipe(recipeIndex); + // need to subtract 1 since list is 1-based + return recipeList.deleteRecipe(recipeIndex - 1); } } diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index f94e04da19..fdf2aba36d 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -24,4 +24,5 @@ public HashMap getIngredients() { public int getNumOfIngredients() { return ingredients.size(); } + } From 2b04ad6e161f0736683c49c4409d660a1065091d Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Tue, 14 Mar 2023 18:56:40 +0800 Subject: [PATCH 062/252] wip: adding to delete functionality --- src/main/java/seedu/meal360/Meal360.java | 4 +-- src/main/java/seedu/meal360/Parser.java | 40 +++++++++++++++++------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 50cb64595b..9c9ce2a73e 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -32,9 +32,9 @@ public static void receiveInput(String input) { } else if (command[0].equals("delete")) { ui.printSeparator(); try { - Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + String deletedRecipe = parser.parseDeleteRecipe(command, recipeList); ui.printMessage("Noted. I've removed this recipe:"); - ui.printMessage(deletedRecipe.getName()); + ui.printMessage(deletedRecipe); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format( diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 60f5ded148..53610980b2 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -55,25 +55,43 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { return recipeToEdit; } - public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { + public String parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name if (input[1].contains("r/")) { // skip over /r in recipe name String recipeToDelete = input[1].substring(2); - int recipeIndex = 0; - for (Recipe recipe : recipeList) { - // find index of recipe we want to delete - if (recipe.getName().equals(recipeToDelete)) { - break; + if (recipeToDelete.equals("all")) { + String allRecipes = ""; + for (int i = 0; i < recipeList.size(); i++) { + allRecipes += recipeList.deleteRecipe(i).getName() + " "; } - recipeIndex++; + return allRecipes; + } else { + int recipeIndex = 0; + for (Recipe recipe : recipeList) { + // find index of recipe we want to delete + if (recipe.getName().equals(recipeToDelete)) { + break; + } + recipeIndex++; + } + return recipeList.deleteRecipe(recipeIndex).getName(); } - return recipeList.deleteRecipe(recipeIndex); // user inputted index of recipe in list } else { - int recipeIndex = Integer.parseInt(input[1]); - // need to subtract 1 since list is 1-based - return recipeList.deleteRecipe(recipeIndex - 1); + // deleting a range of recipes + if (input[1].contains("-")) { + int startIndex = Integer.parseInt(input[1].charAt(0) + ""); + int endIndex = Integer.parseInt(input[1].charAt(2) + ""); + for (int i = startIndex; i <= endIndex; i++) { + recipeList.deleteRecipe(i); + } + return input[1]; + } else { + int recipeIndex = Integer.parseInt(input[1]); + // need to subtract 1 since list is 1-based + return recipeList.deleteRecipe(recipeIndex - 1).getName(); + } } } From 5861ea8b3e24630ff65461a30318a3566aeb4e68 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Tue, 14 Mar 2023 19:26:14 +0800 Subject: [PATCH 063/252] edited the parseEditRecipe function --- src/main/java/seedu/meal360/Meal360.java | 1 + src/main/java/seedu/meal360/Parser.java | 91 +++++++++++++++++++----- src/main/java/seedu/meal360/Ui.java | 4 +- 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index beba2520f6..33fbb8fe31 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -68,6 +68,7 @@ public static void receiveInput(String input) { } else if (command[0].equals("edit")) { ui.printSeparator(); Recipe newRecipe = parser.parseEditRecipe(command, recipeList); + ui.printSeparator(); ui.printMessage("I've edited this recipe:" + newRecipe.getName()); ui.printSeparator(); } else if (command[0].equals("weekly")) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 4813a208f8..393c4aeab7 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -5,53 +5,96 @@ public class Parser { - public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { - StringBuilder recipeName = new StringBuilder(input[2]); - for (int i = 3; i < input.length; i++) { - recipeName.append(" ").append(input[i]); + Ui ui = new Ui(); + + public String combineWords(String[] input, int startIndex){ + StringBuilder word = new StringBuilder(input[startIndex]); + for(int i = startIndex+1; i< input.length; i++) { + word.append(" ").append(input[i]); } + + return word.toString(); + } + + public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { + String recipeName = combineWords(input, 2); HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); System.out.println("Please Enter The Ingredients & Quantity: "); while (true) { String line = userInput.nextLine(); if (line.equals("done")) { + ui.printSeparator(); break; } else { String[] command = line.trim().split(" "); - StringBuilder iName = new StringBuilder(command[0]); - for (int i = 1; i < command.length - 1; i++) { - iName.append(" ").append(command[i]); - } - ingredients.put(iName.toString(), Integer.parseInt(command[command.length - 1])); + String iName = combineWords(command, 0); + ingredients.put(iName, Integer.parseInt(command[command.length - 1])); } } - Recipe newRecipe = new Recipe(recipeName.toString(), ingredients); + Recipe newRecipe = new Recipe(recipeName, ingredients); recipeList.addRecipe(newRecipe); return newRecipe; } public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { - String recipeName = input[1].substring(2); + String recipeName = combineWords(input, 2); Recipe recipeToEdit; HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); if (recipeList.findByName(recipeName) == null) { - // ui recipe not found return null; } else { recipeToEdit = recipeList.findByName(recipeName); } - System.out.println("Please Enter New Ingredients & Quantity: "); - while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - break; + System.out.println("Do you want to edit recipe fully or partially?"); + System.out.println("Press 1 for full edit | Press 2 for partial edit"); + + Scanner getInput = new Scanner(System.in); + int index = getInput.nextInt(); + if(index == 1){ + System.out.println("Please Enter New Ingredients & Quantity: "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + break; + } + String[] command = line.trim().split(" "); + ingredients.put(command[0], Integer.parseInt(command[1])); + recipeList.editRecipe(recipeToEdit, ingredients); + } + } else if(index == 2){ + System.out.println("These are the ingredients for the recipe:"); + ui.printSeparator(); + Recipe recipe = parseViewRecipe(recipeName, recipeList); + ui.printRecipe(recipe); + ui.printSeparator(); + System.out.println("Which ingredient do you want to change?"); + int ingredientIndex = getInput.nextInt(); + ingredientIndex -= 1; + int count = 0; + String ingredientToRemove = null; + for (String ingredient : recipeToEdit.getIngredients().keySet()) { + if(ingredientIndex == count){ + ingredientToRemove = ingredient; + System.out.println("Ingredient to be changed:"); + ui.printSeparator(); + String toPrint = String.format("%s(%d)", ingredient, recipeToEdit.getIngredients().get(ingredient)); + System.out.println(ui.formatMessage(toPrint)); + ui.printSeparator(); + break; + } + count++; } + System.out.println("Please enter the new ingredient:"); + String line = userInput.nextLine(); String[] command = line.trim().split(" "); - ingredients.put(command[0], Integer.parseInt(command[1])); + String newIngredientName = combineWords(command, 0); + recipeToEdit.getIngredients().remove(ingredientToRemove); + recipeToEdit.getIngredients().put(newIngredientName, Integer.parseInt(command[command.length-1])); + recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); } - recipeList.editRecipe(recipeToEdit, ingredients); + return recipeToEdit; } @@ -91,6 +134,16 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { int recipeIndex = Integer.parseInt(command[1]) - 1; return recipes.get(recipeIndex); } + public Recipe parseViewRecipe(String recipeName, RecipeList recipes){ + int recipeIndex = 1; + for (Recipe recipe : recipes) { + if (recipe.getName().equals(recipeName)) { + break; + } + recipeIndex++; + } + return recipes.get(recipeIndex-1); + } public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { if (!command[1].equals("/add") && !command[1].equals("/delete")) { diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index a5e41499b2..66ed88c9a4 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -35,10 +35,12 @@ public void printMessage(String message) { public void printRecipe(Recipe recipe) { System.out.println(formatMessage("Name of recipe: " + recipe.getName())); + int index = 1; for (String ingredient : recipe.getIngredients().keySet()) { String outputMessage = String.format("%s(%d)", ingredient, recipe.getIngredients().get(ingredient)); - System.out.println(formatMessage(outputMessage)); + System.out.println(formatMessage(index + ". " + outputMessage)); + index++; } } From 4943d04ebc26a6b435d3a710cba8e9828cc5cabc Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Wed, 15 Mar 2023 15:43:11 +0800 Subject: [PATCH 064/252] be able to delete all recipes --- src/main/java/seedu/meal360/Parser.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 53610980b2..cd4e7bf2a1 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -62,9 +62,12 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { String recipeToDelete = input[1].substring(2); if (recipeToDelete.equals("all")) { String allRecipes = ""; - for (int i = 0; i < recipeList.size(); i++) { - allRecipes += recipeList.deleteRecipe(i).getName() + " "; + System.out.println("recipeList size: " + recipeList.size()); + int index = 0; + while (recipeList.size() != 0) { + allRecipes += recipeList.deleteRecipe(index).getName() + ", "; } + allRecipes = allRecipes.substring(0, allRecipes.length() - 2); return allRecipes; } else { int recipeIndex = 0; From 8d56a3192653d622caaeecb5c1854ebbd79e68e2 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Wed, 15 Mar 2023 17:00:28 +0800 Subject: [PATCH 065/252] wip: deleting a range of recipes --- src/main/java/seedu/meal360/Meal360.java | 2 +- src/main/java/seedu/meal360/Parser.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 9c9ce2a73e..1a923ae12c 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -42,7 +42,7 @@ public static void receiveInput(String input) { ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( - "Please enter a valid recipe number or mame. You entered %s, " + "which is in ivalid.", + "Please enter a valid recipe number or name. You entered %s, " + "which is in invalid.", command[1]); ui.printMessage(errorMessage); } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index cd4e7bf2a1..c06674c5ee 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -83,13 +83,18 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted index of recipe in list } else { // deleting a range of recipes - if (input[1].contains("-")) { + if (input[1].length() >= 3) { + String rangeRecipes = ""; int startIndex = Integer.parseInt(input[1].charAt(0) + ""); int endIndex = Integer.parseInt(input[1].charAt(2) + ""); - for (int i = startIndex; i <= endIndex; i++) { - recipeList.deleteRecipe(i); + int newSize = recipeList.size() - ((endIndex - startIndex) + 1); + // endIndex -= 4; + while (recipeList.size() != newSize) { + rangeRecipes += recipeList.deleteRecipe(endIndex).getName() + ", "; + endIndex--; } - return input[1]; + rangeRecipes = rangeRecipes.substring(0, rangeRecipes.length() - 2); + return rangeRecipes; } else { int recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based From 7a48dfa0f1feb33148fd68a4366432f95a66c79a Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 16 Mar 2023 15:28:38 +0800 Subject: [PATCH 066/252] updated delete functionality to delete all/range of recipes & updated user guide --- docs/UserGuide.md | 17 +++++++++++++++++ src/main/java/seedu/meal360/Parser.java | 6 +++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index c5dcffc970..a405a8f93a 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -51,6 +51,23 @@ Example of usage: `view 1` +### Deleting recipes: `delete` + +Deletes one, a range, or all recipes currently in list. + +Format: `delete INDEX/RANGE` or `delete r/NAME` + +* Deletes the recipe(s) specified by the user either through the recipe index or name. +* The index refers to the index number shown in the displayed person list. +* The name refers to the recipe name in the list. + +Example of usage: + +`delete 1` +`delete 1-3` +`delete r/pizza` +`delete r/all` + ### Adding to this week's plan: `weekly /add` Adds an existing recipe to this week's plan. diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index c06674c5ee..d18fe0e7e9 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -87,11 +87,11 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { String rangeRecipes = ""; int startIndex = Integer.parseInt(input[1].charAt(0) + ""); int endIndex = Integer.parseInt(input[1].charAt(2) + ""); + startIndex -= 1; + endIndex -= 1; int newSize = recipeList.size() - ((endIndex - startIndex) + 1); - // endIndex -= 4; while (recipeList.size() != newSize) { - rangeRecipes += recipeList.deleteRecipe(endIndex).getName() + ", "; - endIndex--; + rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; } rangeRecipes = rangeRecipes.substring(0, rangeRecipes.length() - 2); return rangeRecipes; From b98fa8cd25571d8d4b838dabe864a5962b3a2cce Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 16 Mar 2023 02:38:29 -0500 Subject: [PATCH 067/252] Revert "fix delete functionality & add exceptions" --- docs/UserGuide.md | 17 -------- src/main/java/seedu/meal360/Meal360.java | 22 +++------- src/main/java/seedu/meal360/Parser.java | 51 ++++++------------------ src/main/java/seedu/meal360/Recipe.java | 1 - 4 files changed, 17 insertions(+), 74 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index a405a8f93a..c5dcffc970 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -51,23 +51,6 @@ Example of usage: `view 1` -### Deleting recipes: `delete` - -Deletes one, a range, or all recipes currently in list. - -Format: `delete INDEX/RANGE` or `delete r/NAME` - -* Deletes the recipe(s) specified by the user either through the recipe index or name. -* The index refers to the index number shown in the displayed person list. -* The name refers to the recipe name in the list. - -Example of usage: - -`delete 1` -`delete 1-3` -`delete r/pizza` -`delete r/all` - ### Adding to this week's plan: `weekly /add` Adds an existing recipe to this week's plan. diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 1a923ae12c..beba2520f6 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -29,24 +29,12 @@ public static void receiveInput(String input) { String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; + // delete a recipe in list } else if (command[0].equals("delete")) { - ui.printSeparator(); - try { - String deletedRecipe = parser.parseDeleteRecipe(command, recipeList); - ui.printMessage("Noted. I've removed this recipe:"); - ui.printMessage(deletedRecipe); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number or name. You did not enter a recipe number or name."); - ui.printMessage(errorMessage); - } catch (IndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number or name. You entered %s, " + "which is in invalid.", - command[1]); - ui.printMessage(errorMessage); - } - ui.printSeparator(); + Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + ui.printMessage("Noted. I've removed this recipe:"); + ui.printMessage(deletedRecipe.toString()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } else if (command[0].equals("view")) { ui.printSeparator(); try { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index d18fe0e7e9..4813a208f8 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -55,51 +55,24 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { return recipeToEdit; } - public String parseDeleteRecipe(String[] input, RecipeList recipeList) { + public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name if (input[1].contains("r/")) { // skip over /r in recipe name - String recipeToDelete = input[1].substring(2); - if (recipeToDelete.equals("all")) { - String allRecipes = ""; - System.out.println("recipeList size: " + recipeList.size()); - int index = 0; - while (recipeList.size() != 0) { - allRecipes += recipeList.deleteRecipe(index).getName() + ", "; + String recipeName = input[1].substring(2); + int recipeIndex = 1; + for (Recipe recipe : recipeList) { + // find index of recipe we want to delete + if (recipe.getName().equals(recipeName)) { + break; } - allRecipes = allRecipes.substring(0, allRecipes.length() - 2); - return allRecipes; - } else { - int recipeIndex = 0; - for (Recipe recipe : recipeList) { - // find index of recipe we want to delete - if (recipe.getName().equals(recipeToDelete)) { - break; - } - recipeIndex++; - } - return recipeList.deleteRecipe(recipeIndex).getName(); + recipeIndex++; } - // user inputted index of recipe in list + return recipeList.deleteRecipe(recipeIndex); + // user inputted index of recipe in list } else { - // deleting a range of recipes - if (input[1].length() >= 3) { - String rangeRecipes = ""; - int startIndex = Integer.parseInt(input[1].charAt(0) + ""); - int endIndex = Integer.parseInt(input[1].charAt(2) + ""); - startIndex -= 1; - endIndex -= 1; - int newSize = recipeList.size() - ((endIndex - startIndex) + 1); - while (recipeList.size() != newSize) { - rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; - } - rangeRecipes = rangeRecipes.substring(0, rangeRecipes.length() - 2); - return rangeRecipes; - } else { - int recipeIndex = Integer.parseInt(input[1]); - // need to subtract 1 since list is 1-based - return recipeList.deleteRecipe(recipeIndex - 1).getName(); - } + int recipeIndex = Integer.parseInt(input[1]); + return recipeList.deleteRecipe(recipeIndex); } } diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index fdf2aba36d..f94e04da19 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -24,5 +24,4 @@ public HashMap getIngredients() { public int getNumOfIngredients() { return ingredients.size(); } - } From ab6074a88adf7098ffeb9cd58755f0a95039c07c Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 16 Mar 2023 15:59:09 +0800 Subject: [PATCH 068/252] able to delete a single, all, or range of recipes & user guide updated --- docs/UserGuide.md | 18 +++++++++ src/main/java/seedu/meal360/Meal360.java | 24 ++++++++--- src/main/java/seedu/meal360/Parser.java | 51 ++++++++++++++++++------ 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index c5dcffc970..afa38088dd 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -51,6 +51,24 @@ Example of usage: `view 1` +### Deleting recipes: `delete` + +Deletes one, a range, or all recipes currently in list. + +Format: `delete INDEX/RANGE` or `delete r/NAME` + +* Deletes the recipe(s) specified by the user either through the recipe index or name. +* The index refers to the index number shown in the displayed person list. +* The name refers to the recipe name in the list. + +Example of usage: + +`delete 1` +`delete 1-3` +`delete r/pizza` +`delete r/all` + + ### Adding to this week's plan: `weekly /add` Adds an existing recipe to this week's plan. diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index beba2520f6..0487677f76 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -29,12 +29,24 @@ public static void receiveInput(String input) { String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { canExit = true; - // delete a recipe in list } else if (command[0].equals("delete")) { - Recipe deletedRecipe = parser.parseDeleteRecipe(command, recipeList); - ui.printMessage("Noted. I've removed this recipe:"); - ui.printMessage(deletedRecipe.toString()); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + ui.printSeparator(); + try { + String deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + ui.printMessage("Noted. I've removed this recipe:"); + ui.printMessage(deletedRecipe); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number or name. You did not enter a recipe number or name."); + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number or name. You entered %s, " + "which is in invalid.", + command[1]); + ui.printMessage(errorMessage); + } + ui.printSeparator(); } else if (command[0].equals("view")) { ui.printSeparator(); try { @@ -123,4 +135,4 @@ public static void main(String[] args) { exitApp(); } -} +} \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 4813a208f8..fbe3c33d50 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -55,24 +55,51 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { return recipeToEdit; } - public Recipe parseDeleteRecipe(String[] input, RecipeList recipeList) { + public String parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name if (input[1].contains("r/")) { // skip over /r in recipe name - String recipeName = input[1].substring(2); - int recipeIndex = 1; - for (Recipe recipe : recipeList) { - // find index of recipe we want to delete - if (recipe.getName().equals(recipeName)) { - break; + String recipeToDelete = input[1].substring(2); + if (recipeToDelete.equals("all")) { + String allRecipes = ""; + System.out.println("recipeList size: " + recipeList.size()); + int index = 0; + while (recipeList.size() != 0) { + allRecipes += recipeList.deleteRecipe(index).getName() + ", "; } - recipeIndex++; + allRecipes = allRecipes.substring(0, allRecipes.length() - 2); + return allRecipes; + } else { + int recipeIndex = 0; + for (Recipe recipe : recipeList) { + // find index of recipe we want to delete + if (recipe.getName().equals(recipeToDelete)) { + break; + } + recipeIndex++; + } + return recipeList.deleteRecipe(recipeIndex).getName(); } - return recipeList.deleteRecipe(recipeIndex); // user inputted index of recipe in list } else { - int recipeIndex = Integer.parseInt(input[1]); - return recipeList.deleteRecipe(recipeIndex); + // deleting a range of recipes + if (input[1].length() >= 3) { + String rangeRecipes = ""; + int startIndex = Integer.parseInt(input[1].charAt(0) + ""); + int endIndex = Integer.parseInt(input[1].charAt(2) + ""); + startIndex -= 1; + endIndex -= 1; + int newSize = recipeList.size() - ((endIndex - startIndex) + 1); + while (recipeList.size() != newSize) { + rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; + } + rangeRecipes = rangeRecipes.substring(0, rangeRecipes.length() - 2); + return rangeRecipes; + } else { + int recipeIndex = Integer.parseInt(input[1]); + // need to subtract 1 since list is 1-based + return recipeList.deleteRecipe(recipeIndex - 1).getName(); + } } } @@ -129,4 +156,4 @@ public RecipeList parseLoadDatabase(String input) { public String parseSaveDatabase(String input) { return "test"; } -} +} \ No newline at end of file From 230c10c40f1a00ff192ce4636ceee4aef7404677 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 16 Mar 2023 16:07:55 +0800 Subject: [PATCH 069/252] add newline to end of the file --- src/main/java/seedu/meal360/Meal360.java | 2 +- src/main/java/seedu/meal360/Parser.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 0487677f76..1a923ae12c 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -135,4 +135,4 @@ public static void main(String[] args) { exitApp(); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index fbe3c33d50..c9b6a0ed50 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -156,4 +156,4 @@ public RecipeList parseLoadDatabase(String input) { public String parseSaveDatabase(String input) { return "test"; } -} \ No newline at end of file +} From 150e709ac1be304fd267b19d636cbaeea2105447 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Thu, 16 Mar 2023 16:21:11 +0800 Subject: [PATCH 070/252] Added try & catch for add and edit methods --- src/main/java/seedu/meal360/Meal360.java | 33 +++++++++++++++++++----- src/main/java/seedu/meal360/Parser.java | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 33fbb8fe31..ee33e35506 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -61,15 +61,36 @@ public static void receiveInput(String input) { ui.listRecipe(recipeListToPrint); } else if (command[0].equals("add")) { ui.printSeparator(); - Recipe newRecipe = parser.parseAddRecipe(command, recipeList); - ui.printMessage("I've added this new recipe:" + newRecipe.getName()); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + try{ + Recipe newRecipe = parser.parseAddRecipe(command, recipeList); + ui.printMessage("I've added this new recipe:" + newRecipe.getName()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } catch(ArrayIndexOutOfBoundsException e) { + String errorMessage = String.format("Please enter a valid recipe name."); + ui.printMessage(errorMessage); + } ui.printSeparator(); } else if (command[0].equals("edit")) { ui.printSeparator(); - Recipe newRecipe = parser.parseEditRecipe(command, recipeList); - ui.printSeparator(); - ui.printMessage("I've edited this recipe:" + newRecipe.getName()); + try{ + Recipe newRecipe = parser.parseEditRecipe(command, recipeList); + ui.printSeparator(); + ui.printMessage("I've edited this recipe:" + newRecipe.getName()); + } catch (NumberFormatException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is not a number.", + command[1]); + ui.printMessage(errorMessage); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe name."); + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", + command[1]); + ui.printMessage(errorMessage); + } ui.printSeparator(); } else if (command[0].equals("weekly")) { try { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 393c4aeab7..7c7282fa93 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -9,7 +9,7 @@ public class Parser { public String combineWords(String[] input, int startIndex){ StringBuilder word = new StringBuilder(input[startIndex]); - for(int i = startIndex+1; i< input.length; i++) { + for(int i = startIndex+1; i< input.length-1; i++) { word.append(" ").append(input[i]); } From 49eb82c300f45384d1af43e1f963757612487f18 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 16 Mar 2023 20:37:28 +0800 Subject: [PATCH 071/252] fix get filter --- src/main/java/seedu/meal360/Parser.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 54d5638ccc..d0fbb10e46 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -27,7 +27,11 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { if (inputs.length == 1) { filters = null; } else { - filters = inputs[1].split("&"); + StringBuilder filterString = new StringBuilder(inputs[1]); + for (int i = 2; i < inputs.length; i++) { + filterString.append(" ").append(inputs[i]); + } + filters = filterString.toString().split("&"); } return recipeList.listRecipes(filters); } From 75fb104d9a92d33169914ed31a25b46ddfb71360 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 16 Mar 2023 20:54:04 +0800 Subject: [PATCH 072/252] update list test --- src/test/java/seedu/meal360/Meal360Test.java | 48 ++++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index f1c73c9ca2..482a96c788 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -205,42 +205,30 @@ public void testViewNonEmptyWeeklyPlan() { @Test public void testListRecipe() { - RecipeList recipes = new RecipeList(); - Parser parser = new Parser(); - String input; - String[] command; RecipeList recipeListToPrint; + String[] inputs; - HashMap testIngredients1 = new HashMap<>(); - testIngredients1.put("test ingredient1-1", 10); - testIngredients1.put("test ingredient1-2", 20); - testIngredients1.put("test ingredient1-3", 30); - Recipe testRecipe1 = new Recipe("test recipe1", testIngredients1); - recipes.addRecipe(testRecipe1); - - HashMap testIngredients2 = new HashMap<>(); - testIngredients2.put("test ingredient2-1", 10); - testIngredients2.put("test ingredient2-2", 20); - Recipe testRecipe2 = new Recipe("test recipe2", testIngredients2); - recipes.addRecipe(testRecipe2); - - input = "list"; - command = input.split(" ",2); - recipeListToPrint = parser.parseListRecipe(command, recipes); - assertEquals(2, recipeListToPrint.size()); + inputs = new String[] {"list"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(3, recipeListToPrint.size()); assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); - assertEquals(2, recipeListToPrint.get(1).getNumOfIngredients()); + assertEquals(4, recipeListToPrint.get(1).getNumOfIngredients()); + assertEquals(3, recipeListToPrint.get(2).getNumOfIngredients()); + + inputs = new String[] {"list", "tomato", "sauce"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(1, recipeListToPrint.size()); + assertEquals(4, recipeListToPrint.get(0).getNumOfIngredients()); + assertEquals("pizza", recipeListToPrint.get(0).getName()); - input = "list test ingredient2-1"; - command = input.split(" ",2); - recipeListToPrint = parser.parseListRecipe(command, recipes); + inputs = new String[] {"list", "salad", "&", "tomato"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(1, recipeListToPrint.size()); - assertEquals(2, recipeListToPrint.get(0).getNumOfIngredients()); - assertEquals("test recipe2", recipeListToPrint.get(0).getName()); + assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); + assertEquals("salad", recipeListToPrint.get(0).getName()); - input = "list test ingredient2-1 & test recipe1"; - command = input.split(" ",2); - recipeListToPrint = parser.parseListRecipe(command, recipes); + inputs = new String[] {"list", "salad", "&", "pizza"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(0, recipeListToPrint.size()); } } From b7406b7de98543d5ef2be30beac41a8791152b7b Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Thu, 16 Mar 2023 22:20:10 +0800 Subject: [PATCH 073/252] New commit --- 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 4dd511cc0d..15c52f07bf 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -15,7 +15,7 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Name of recipe: test recipe name | -| test ingredient(100) | +| 1. test ingredient(100) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You entered -2, which is out of bounds. | From e557583c41a713592e4e30c8ab80d99e38083bdb Mon Sep 17 00:00:00 2001 From: Abijith Ram <88262428+TopGun2001@users.noreply.github.com> Date: Thu, 16 Mar 2023 22:29:55 +0800 Subject: [PATCH 074/252] Update UserGuide.md --- docs/UserGuide.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index afa38088dd..17735c92ce 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -21,6 +21,35 @@ ___ * Remove recipes from weekly plan * View weekly plan +### Adding recipes: `add` + +Add new recipes to your list. + +Format: `add /r [recipe_name]` + +* `recipe_name` is basically a string. +* Type the recipe name after typing `/r `. + +Example of usage: + +`add /r chicken rice` +`add /r noodles` + +### Editing recipes: `edit` + +Edit recipes in your list either partially or fully. + +Format: `edit /r [recipe_name]` + +* `recipe_name` is basically a string. +* Type the recipe name after typing `/r `. + + +Example of usage: + +`edit /r chicken rice` +`edit /r noodles` + ### Listing recipes: `list` List all recipes or filtered list recipes by the name or ingredients. @@ -119,6 +148,8 @@ Format: `bye` ## Command Summary | Action | Format, Examples | |--------|---------------------------------------| +|Add recipe | `add /r [recipe_name]`
e.g `add /r chicken rice` | +|Edit recipe | `edit /r [recipe_name]`
e.g `edit /r chicken rice` | |List recipe | `list [KEYWORD]`
e.g `list pizza` | |View recipe | `view INDEX`
e.g `view 1` | |Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | From 303efe5ad83e95ab7f350e9719da78bcbc5f01cc Mon Sep 17 00:00:00 2001 From: Abijith Ram <88262428+TopGun2001@users.noreply.github.com> Date: Thu, 16 Mar 2023 22:38:53 +0800 Subject: [PATCH 075/252] Update Meal360.java --- src/main/java/seedu/meal360/Meal360.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index ee33e35506..b4f045df61 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -73,9 +73,9 @@ public static void receiveInput(String input) { } else if (command[0].equals("edit")) { ui.printSeparator(); try{ - Recipe newRecipe = parser.parseEditRecipe(command, recipeList); + Recipe recipeToEdit = parser.parseEditRecipe(command, recipeList); ui.printSeparator(); - ui.printMessage("I've edited this recipe:" + newRecipe.getName()); + ui.printMessage("I've edited this recipe:" + recipeToEdit.getName()); } catch (NumberFormatException e) { String errorMessage = String.format( "Please enter a valid recipe number. You entered %s, " + "which is not a number.", From 2be9aa6cb5b6adeb6082101826f184e783c3d10c Mon Sep 17 00:00:00 2001 From: Abijith Ram <88262428+TopGun2001@users.noreply.github.com> Date: Thu, 16 Mar 2023 22:39:51 +0800 Subject: [PATCH 076/252] Update Parser.java --- src/main/java/seedu/meal360/Parser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 7c7282fa93..0824141d54 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -28,8 +28,8 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { break; } else { String[] command = line.trim().split(" "); - String iName = combineWords(command, 0); - ingredients.put(iName, Integer.parseInt(command[command.length - 1])); + String ingredientName = combineWords(command, 0); + ingredients.put(ingredientName, Integer.parseInt(command[command.length - 1])); } } Recipe newRecipe = new Recipe(recipeName, ingredients); From c622667fd722cce6ba50dfd01652ce2b2684bdec Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 17 Mar 2023 10:09:06 +0800 Subject: [PATCH 077/252] ... --- src/main/java/seedu/meal360/Meal360.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index ee33e35506..a14d4fa1c1 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -134,6 +134,7 @@ public static void exitApp() { } public static void main(String[] args) { + startApp(); String line; Scanner userInput = new Scanner(System.in); From 11032919847dfe484fc24c72c6a140824cc8ea46 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Fri, 17 Mar 2023 16:32:18 +0800 Subject: [PATCH 078/252] added 3rd recipe edit option: add additional ingredients --- src/main/java/seedu/meal360/Meal360.java | 6 ++-- src/main/java/seedu/meal360/Parser.java | 38 ++++++++++++++++----- src/main/java/seedu/meal360/RecipeList.java | 2 +- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 489ec06e54..7a6a4d8110 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -73,18 +73,18 @@ public static void receiveInput(String input) { ui.listRecipe(recipeListToPrint); } else if (command[0].equals("add")) { ui.printSeparator(); - try{ + try { Recipe newRecipe = parser.parseAddRecipe(command, recipeList); ui.printMessage("I've added this new recipe:" + newRecipe.getName()); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); - } catch(ArrayIndexOutOfBoundsException e) { + } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format("Please enter a valid recipe name."); ui.printMessage(errorMessage); } ui.printSeparator(); } else if (command[0].equals("edit")) { ui.printSeparator(); - try{ + try { Recipe recipeToEdit = parser.parseEditRecipe(command, recipeList); ui.printSeparator(); ui.printMessage("I've edited this recipe:" + recipeToEdit.getName()); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 03162a93d8..008112817b 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -7,9 +7,9 @@ public class Parser { Ui ui = new Ui(); - public String combineWords(String[] input, int startIndex){ + public String combineWords(String[] input, int startIndex) { StringBuilder word = new StringBuilder(input[startIndex]); - for(int i = startIndex+1; i< input.length-1; i++) { + for (int i = startIndex + 1; i < input.length - 1; i++) { word.append(" ").append(input[i]); } @@ -48,11 +48,11 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { recipeToEdit = recipeList.findByName(recipeName); } System.out.println("Do you want to edit recipe fully or partially?"); - System.out.println("Press 1 for full edit | Press 2 for partial edit"); + System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); Scanner getInput = new Scanner(System.in); int index = getInput.nextInt(); - if(index == 1){ + if (index == 1) { System.out.println("Please Enter New Ingredients & Quantity: "); while (true) { String line = userInput.nextLine(); @@ -63,7 +63,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { ingredients.put(command[0], Integer.parseInt(command[1])); recipeList.editRecipe(recipeToEdit, ingredients); } - } else if(index == 2){ + } else if (index == 2) { System.out.println("These are the ingredients for the recipe:"); ui.printSeparator(); Recipe recipe = parseViewRecipe(recipeName, recipeList); @@ -75,7 +75,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { int count = 0; String ingredientToRemove = null; for (String ingredient : recipeToEdit.getIngredients().keySet()) { - if(ingredientIndex == count){ + if (ingredientIndex == count) { ingredientToRemove = ingredient; System.out.println("Ingredient to be changed:"); ui.printSeparator(); @@ -91,7 +91,26 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" "); String newIngredientName = combineWords(command, 0); recipeToEdit.getIngredients().remove(ingredientToRemove); - recipeToEdit.getIngredients().put(newIngredientName, Integer.parseInt(command[command.length-1])); + recipeToEdit.getIngredients().put(newIngredientName, Integer.parseInt(command[command.length - 1])); + recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); + } else if (index == 3) { + System.out.println("These are the current ingredients:"); + ui.printSeparator(); + Recipe recipe = parseViewRecipe(recipeName, recipeList); + ui.printRecipe(recipe); + ui.printSeparator(); + System.out.println("Please Enter Additional Ingredients & Quantity (Enter done when complete): "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + break; + } else { + String[] command = line.trim().split(" "); + String ingredientName = combineWords(command, 0); + recipeToEdit.getIngredients().put(ingredientName, Integer.parseInt(command[command.length - 1])); + } + } recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); } @@ -165,7 +184,8 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { int recipeIndex = Integer.parseInt(command[1]) - 1; return recipes.get(recipeIndex); } - public Recipe parseViewRecipe(String recipeName, RecipeList recipes){ + + public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { int recipeIndex = 1; for (Recipe recipe : recipes) { if (recipe.getName().equals(recipeName)) { @@ -173,7 +193,7 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes){ } recipeIndex++; } - return recipes.get(recipeIndex-1); + return recipes.get(recipeIndex - 1); } public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index a081c8bdb6..784a5ecb86 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -33,7 +33,7 @@ public RecipeList listRecipes(String[] filters) { if (filters == null) { return this; } - for (Recipe recipe: this) { + for (Recipe recipe : this) { filteredRecipeList.add(recipe); for (String filter : filters) { filter = filter.trim(); From 150b8a558d08ae7b584711766c5815c64f8a278f Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sun, 19 Mar 2023 15:07:16 +0800 Subject: [PATCH 079/252] Add local database Program loads a single dummy test recipe, and is unable to save any changes made to the recipes by the user. Low number of default recipes can make it difficult for a user to test the different functionalities of the program. Let's: * add a local database * create a more substantial default database * load from local database upon startup * save to local database upon exiting --- META-INF/MANIFEST.MF | 3 + build.gradle | 1 + database/recipesDatabase.json | 1 + src/main/java/seedu/meal360/Database.java | 204 +++++++++++++++++++++- src/main/java/seedu/meal360/Meal360.java | 51 ++++-- src/main/java/seedu/meal360/Ui.java | 4 - 6 files changed, 238 insertions(+), 26 deletions(-) create mode 100644 META-INF/MANIFEST.MF create mode 100644 database/recipesDatabase.json diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..d54b3b8812 --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: seedu.meal360.Meal360 + diff --git a/build.gradle b/build.gradle index fc107018c5..801228db39 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,7 @@ repositories { } dependencies { + implementation 'com.google.code.gson:gson:2.10.1' 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/database/recipesDatabase.json b/database/recipesDatabase.json new file mode 100644 index 0000000000..0beacc58a3 --- /dev/null +++ b/database/recipesDatabase.json @@ -0,0 +1 @@ +[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index 6fc39a1bea..b78151cb8b 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -1,17 +1,207 @@ package seedu.meal360; +import com.google.gson.Gson; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; + public class Database { - public void createDatabase() { - // create database + private static final Ui ui = new Ui(); + private static final String recipesDatabaseFilepath = "./database/recipesDatabase.json"; + + public RecipeList loadDatabase() throws IOException { + RecipeList database; + Gson gson = new Gson(); + + // Check if the JSON file exists + File file = new File(recipesDatabaseFilepath); + if (!file.exists()) { + try { + // Create the parent directory if it does not exist + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + ui.printMessage("Database directory does not exist, creating one now..."); + parentDir.mkdirs(); + } + ui.printMessage("Database file does not exist, creating one now..."); + file.createNewFile(); + } catch (IOException e) { + throw new IOException("Error creating database file."); + } + + // Return a default recipe list if database file does not exist + return defaultRecipeList(); + } + + // Read the JSON data from the file if it already exists + try { + // Read the JSON data from the file + BufferedReader reader = new BufferedReader(new FileReader(recipesDatabaseFilepath)); + database = gson.fromJson(reader, RecipeList.class); + reader.close(); + } catch (FileNotFoundException e) { + throw new FileNotFoundException("Unable to find database file."); + } catch (IOException e) { + throw new IOException("Error reading from database file."); + } + + // Ensure non empty recipeList is returned + if (database == null) { + ui.printMessage("Database file is empty, loading default database"); + return defaultRecipeList(); + } else { + return database; + } } - public String loadDatabase() { - // load database - return "database loaded"; + public void saveDatabase(RecipeList recipeList) throws IOException { + Gson gson = new Gson(); + // Write the data object to the JSON file + FileWriter writer; + try { + writer = new FileWriter(recipesDatabaseFilepath); + gson.toJson(recipeList, writer); + writer.close(); + } catch (IOException e) { + throw new IOException("Error writing to database file. File not saved."); + } } - public void saveDatabase(String recipes) { - // save database + private RecipeList defaultRecipeList() { + RecipeList defaultRecipeList = new RecipeList(); + defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap() { + { + put("Chicken", 1); + put("Rice", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap() { + { + put("Ripe mixed-colour cherry tomatoes ", 250); + put("Flat-leaf parsley", 15); + put("Garlic cloves", 2); + put("Plain flour", 2); + put("Eggs", 2); + put("Breadcrumbs", 100); + put("Vegetable oil", 2); + put("Feta cheese", 30); + } + })); + + defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap() { + { + put("Chicken breast fillets", 2); + put("Mushrooms", 250); + put("Onion", 1); + put("Plain flour", 2); + put("Butter", 2); + put("Milk", 2); + put("Puff pastry", 1); + } + })); + + defaultRecipeList.add(new Recipe("Seafood paella", new HashMap() { + { + put("Prawns", 500); + put("Mussels", 500); + put("Chorizo", 100); + put("Onion", 1); + put("Garlic cloves", 2); + put("Rice", 1); + put("Cherry tomatoes", 250); + put("Vegetable oil", 2); + put("Chicken stock", 1); + put("Saffron", 1); + } + })); + + defaultRecipeList.add(new Recipe("Avocado toast", new HashMap() { + { + put("Avocado", 1); + put("Bread", 2); + put("Lemon", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap() { + { + put("Italian sausage", 1); + put("Onion", 1); + put("Garlic cloves", 2); + put("Carrot", 1); + put("Celery", 1); + put("Dried oregano", 1); + put("Dried basil", 1); + put("Dried thyme", 1); + put("Dried parsley", 1); + put("Dried rosemary", 1); + put("Chicken stock", 1); + put("Orzo", 1); + put("Parmesan cheese", 1); + } + })); + + defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap() { + { + put("Chicken breast fillets", 2); + put("Mushrooms", 250); + put("Onion", 1); + put("Garlic cloves", 2); + put("Plain flour", 2); + put("Butter", 2); + put("Milk", 2); + put("Pasta", 1); + } + })); + + defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap() { + { + put("Pasta", 1); + put("Hummus", 1); + put("Garlic cloves", 2); + put("Lemon", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap() { + { + put("Ground beef", 1); + put("Potato", 1); + put("Onion", 1); + put("Garlic cloves", 2); + put("Tomato paste", 1); + put("Tomato sauce", 1); + put("Beef stock", 1); + put("Cheddar cheese", 1); + } + })); + + defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap() { + { + put("Chicken breast fillets", 2); + put("Macaroni", 1); + put("Butter", 2); + put("Flour", 2); + put("Milk", 2); + put("Cheddar cheese", 1); + put("Blue cheese", 1); + put("Hot sauce", 1); + } + })); + + return defaultRecipeList; } } + diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 489ec06e54..3ff2d5adcc 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -1,6 +1,5 @@ package seedu.meal360; -import java.util.HashMap; import java.util.Scanner; public class Meal360 { @@ -13,16 +12,25 @@ public class Meal360 { private static final Ui ui = new Ui(); private static final Parser parser = new Parser(); private static final Database database = new Database(); - private static final RecipeList recipeList = new RecipeList(); + private static RecipeList recipeList; private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); public static void startApp() { + ui.printSeparator(); ui.printWelcomeMessage(); - // Dummy recipe for testing purposes - HashMap testIngredients = new HashMap<>(); - testIngredients.put("test ingredient", 100); - Recipe testR = new Recipe("test recipe name", testIngredients); - recipeList.addRecipe(testR); + ui.printSeparator(); + + // Load database + ui.printMessage("Loading database..."); + try { + recipeList = database.loadDatabase(); + ui.printMessage("Database loaded successfully."); + } catch (Exception e) { + ui.printMessage(String.valueOf(e)); + ui.printMessage("Overwriting database with new default database..."); + } + + ui.printSeparator(); } public static void receiveInput(String input) { @@ -38,12 +46,13 @@ public static void receiveInput(String input) { ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format( - "Please enter a valid recipe number or name. You did not enter a recipe number or name."); + "Please enter a valid recipe number or name. You did not enter a recipe number or " + + "name."); ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( - "Please enter a valid recipe number or name. You entered %s, " + "which is in invalid.", - command[1]); + "Please enter a valid recipe number or name. You entered %s, " + + "which is in invalid.", command[1]); ui.printMessage(errorMessage); } ui.printSeparator(); @@ -73,18 +82,18 @@ public static void receiveInput(String input) { ui.listRecipe(recipeListToPrint); } else if (command[0].equals("add")) { ui.printSeparator(); - try{ + try { Recipe newRecipe = parser.parseAddRecipe(command, recipeList); ui.printMessage("I've added this new recipe:" + newRecipe.getName()); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); - } catch(ArrayIndexOutOfBoundsException e) { + } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format("Please enter a valid recipe name."); ui.printMessage(errorMessage); } ui.printSeparator(); } else if (command[0].equals("edit")) { ui.printSeparator(); - try{ + try { Recipe recipeToEdit = parser.parseEditRecipe(command, recipeList); ui.printSeparator(); ui.printMessage("I've edited this recipe:" + recipeToEdit.getName()); @@ -94,8 +103,7 @@ public static void receiveInput(String input) { command[1]); ui.printMessage(errorMessage); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe name."); + String errorMessage = String.format("Please enter a valid recipe name."); ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( @@ -142,11 +150,24 @@ public static void receiveInput(String input) { } public static void exitApp() { + ui.printSeparator(); + + // Save database + ui.printMessage("Saving database..."); + try { + database.saveDatabase(recipeList); + ui.printMessage("Database saved successfully."); + } catch (Exception e) { + ui.printMessage(String.valueOf(e)); + } + ui.printGoodbyeMessage(); + ui.printSeparator(); } public static void main(String[] args) { startApp(); + String line; Scanner userInput = new Scanner(System.in); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 66ed88c9a4..5134619ac1 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -11,17 +11,13 @@ public void printSeparator() { } public void printWelcomeMessage() { - printSeparator(); String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; System.out.println("Welcome to Meal360, your ultimate Recipe Manager!\n" + logo); - printSeparator(); } public void printGoodbyeMessage() { - printSeparator(); System.out.println(formatMessage("Bye. Hope to see you again soon!")); - printSeparator(); } public String formatMessage(String message) { From b32a86cc7cc1777d06f7dee9190c7e34bbf8f732 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sun, 19 Mar 2023 15:20:41 +0800 Subject: [PATCH 080/252] Update EXPECTED.TXT Include testing of local database --- text-ui-test/EXPECTED.TXT | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 15c52f07bf..fb3b8db008 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -6,16 +6,33 @@ Welcome to Meal360, your ultimate Recipe Manager! |_| |_\___\__,_|_|___/\___/\__/ ---------------------------------------------------------------------------------------------------- +| Loading database... | +| Database directory does not exist, creating one now... | +| Database file does not exist, creating one now... | +| Database loaded successfully. | ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes): | -| 1. test recipe name (1 ingredients) | +---------------------------------------------------------------------------------------------------- +| These are the recipes you have (10 recipes): | +| 1. Chicken Rice (4 ingredients) | +| 2. Tomato fritters (8 ingredients) | +| 3. Chicken and mushroom pie (7 ingredients) | +| 4. Seafood paella (10 ingredients) | +| 5. Avocado toast (5 ingredients) | +| 6. Italian sausage orzo soup (13 ingredients) | +| 7. Chicken and mushroom pasta (8 ingredients) | +| 8. Creamy Hummus Pasta (6 ingredients) | +| 9. Ground beef and potato casserole (8 ingredients) | +| 10. Buffalo Chicken Mac 'n' Cheese (8 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You did not enter a recipe number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Name of recipe: test recipe name | -| 1. test ingredient(100) | +| Name of recipe: Chicken Rice | +| 1. Salt(1) | +| 2. Pepper(1) | +| 3. Chicken(1) | +| 4. Rice(1) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You entered -2, which is out of bounds. | @@ -33,18 +50,19 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| I've added the recipe to your weekly plan! | +| Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Here is your weekly plan: | -| test recipe name x1 | +| Your weekly plan is empty! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| I've deleted the recipe from your weekly plan! | +| Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Your weekly plan is empty! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- +| Saving database... | +| Database saved successfully. | | Bye. Hope to see you again soon! | ---------------------------------------------------------------------------------------------------- From 3702fc85f88cc430782e0004e3789f5c290b57fa Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sun, 19 Mar 2023 18:36:05 +0800 Subject: [PATCH 081/252] Update build.gradle Fix building of jar file using gradle --- build.gradle | 10 ++++++++++ src/main/java/seedu/meal360/Database.java | 14 +++++-------- src/main/java/seedu/meal360/Meal360.java | 5 +++-- src/main/resources/META-INF/MANIFEST.MF | 3 +++ .../main/resources}/recipesDatabase.json | 0 src/test/java/seedu/meal360/Meal360Test.java | 20 +++++++++++++++---- 6 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 src/main/resources/META-INF/MANIFEST.MF rename {database => src/main/resources}/recipesDatabase.json (100%) diff --git a/build.gradle b/build.gradle index 801228db39..fae2e74093 100644 --- a/build.gradle +++ b/build.gradle @@ -46,3 +46,13 @@ run{ standardInput = System.in enableAssertions = true } + +jar { + manifest { + attributes "Main-Class": "seedu.meal360.Meal360" + } + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index b78151cb8b..3d9bac52b4 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -12,7 +12,7 @@ public class Database { private static final Ui ui = new Ui(); - private static final String recipesDatabaseFilepath = "./database/recipesDatabase.json"; + private static final String recipesDatabaseFilepath = "./src/main/resources/recipesDatabase.json"; public RecipeList loadDatabase() throws IOException { RecipeList database; @@ -63,16 +63,12 @@ public void saveDatabase(RecipeList recipeList) throws IOException { Gson gson = new Gson(); // Write the data object to the JSON file FileWriter writer; - try { - writer = new FileWriter(recipesDatabaseFilepath); - gson.toJson(recipeList, writer); - writer.close(); - } catch (IOException e) { - throw new IOException("Error writing to database file. File not saved."); - } + writer = new FileWriter(recipesDatabaseFilepath); + gson.toJson(recipeList, writer); + writer.close(); } - private RecipeList defaultRecipeList() { + public RecipeList defaultRecipeList() { RecipeList defaultRecipeList = new RecipeList(); defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap() { { diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 3ff2d5adcc..56a7d16c94 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -26,8 +26,9 @@ public static void startApp() { recipeList = database.loadDatabase(); ui.printMessage("Database loaded successfully."); } catch (Exception e) { - ui.printMessage(String.valueOf(e)); + ui.printMessage("Error loading database, loading default database instead."); ui.printMessage("Overwriting database with new default database..."); + recipeList = database.defaultRecipeList(); } ui.printSeparator(); @@ -158,7 +159,7 @@ public static void exitApp() { database.saveDatabase(recipeList); ui.printMessage("Database saved successfully."); } catch (Exception e) { - ui.printMessage(String.valueOf(e)); + ui.printMessage("Error saving database."); } ui.printGoodbyeMessage(); diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..d54b3b8812 --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: seedu.meal360.Meal360 + diff --git a/database/recipesDatabase.json b/src/main/resources/recipesDatabase.json similarity index 100% rename from database/recipesDatabase.json rename to src/main/resources/recipesDatabase.json diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 482a96c788..43cdf5a8d9 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,5 +1,6 @@ package seedu.meal360; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -8,17 +9,18 @@ import java.io.PrintStream; import java.util.HashMap; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class Meal360Test { - private static final RecipeList recipes = new RecipeList(); + private static RecipeList recipes = new RecipeList(); private static final Parser parser = new Parser(); private static final Ui ui = new Ui(); + private static final Database database = new Database(); + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; @@ -32,8 +34,8 @@ public void restoreStreams() { System.setOut(originalOut); } - @BeforeAll - public static void setUp() { + @BeforeEach + public void setUpRecipes() { // Adding of recipes HashMap burgerIngredients = new HashMap<>(); burgerIngredients.put("buns", 2); @@ -59,6 +61,11 @@ public static void setUp() { recipes.addRecipe(salad); } + @AfterEach + public void tearDownRecipes() { + recipes = new RecipeList(); + } + @Test public void testViewRecipe() { Parser parser = new Parser(); @@ -231,4 +238,9 @@ public void testListRecipe() { recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(0, recipeListToPrint.size()); } + + @Test + public void testLoadDatabase() { + assertDoesNotThrow(() -> database.loadDatabase()); + } } From 5d72e2366aac9484b68125f8f42c4c7eb540416c Mon Sep 17 00:00:00 2001 From: notbingsu Date: Wed, 22 Mar 2023 20:17:14 +0800 Subject: [PATCH 082/252] parser to parse date in dd/mm/yyyy format to LocalDate Ingredient class with Ingredient name, count, expiry date, expiry status IngredientList class with methods findCount, findExpiryDate, add, edit, delete ingredient, list all ingredient, list all expired ingredients, clear all ingredients, clear all expired ingredients --- src/main/java/seedu/meal360/Ingredient.java | 27 +++++ .../java/seedu/meal360/IngredientList.java | 105 ++++++++++++++++++ src/main/java/seedu/meal360/Parser.java | 10 ++ 3 files changed, 142 insertions(+) create mode 100644 src/main/java/seedu/meal360/Ingredient.java create mode 100644 src/main/java/seedu/meal360/IngredientList.java diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java new file mode 100644 index 0000000000..69544086e2 --- /dev/null +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -0,0 +1,27 @@ +package seedu.meal360; + +import java.time.LocalDate; + +public class Ingredient { + public String ingredientName; + public Integer ingredientCount; + public LocalDate expiryDate; + public Boolean expired; + private static final Parser parser = new Parser(); + + public Ingredient(String ingredientName, Integer ingredientCount, String expiryDate) { + this.ingredientName = ingredientName; + this.ingredientCount = ingredientCount; + // parse expiry date using parseDate method + this.expiryDate = parser.parseDate(expiryDate); + this.updateExpired(); + } + + public void updateExpired() { + if (expiryDate.isBefore(LocalDate.now())) { + expired = true; + } else { + expired = false; + } + } +} diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java new file mode 100644 index 0000000000..a578c5bab0 --- /dev/null +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -0,0 +1,105 @@ +package seedu.meal360; + +import java.util.ArrayList; +import java.time.LocalDate; + +public class IngredientList extends ArrayList { + private static final Parser parser = new Parser(); + + // private exception for ingredient not found + private class IngredientNotFoundException extends Exception { + public IngredientNotFoundException() { + System.out.println("Ingredient not found"); + } + } + + // public method to find count of ingredient + public Integer findCount(String ingredientName) { + try { + for (Ingredient ingredient : this) { + if (ingredient.ingredientName.equalsIgnoreCase(ingredientName)) { + return ingredient.ingredientCount; + } + } + throw new IngredientNotFoundException(); + } catch (IngredientNotFoundException e) { + return null; + } + } + + // public method to find expiry date of ingredient + public LocalDate findExpiryDate(String ingredientName) { + try { + for (Ingredient ingredient : this) { + if (ingredient.ingredientName.equalsIgnoreCase(ingredientName)) { + return ingredient.expiryDate; + } + } + throw new IngredientNotFoundException(); + } catch (IngredientNotFoundException e) { + return null; + } + } + + public void addIngredient(Ingredient ingredient) { + super.add(ingredient); + } + + public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) { + ingredient.ingredientCount = ingredientCount; + ingredient.expiryDate = parser.parseDate(expiryDate); + } + + public void deleteIngredient(int ingredientNum) { + Ingredient ingredientToDelete = super.get(ingredientNum); + super.remove(ingredientToDelete); + } + + // private indexed list of ingredients, count and expiry date + private String listIngredients() { + String ingredientList = ""; + for (int i = 0; i < this.size(); i++) { + ingredientList += (i + 1) + ". " + this.get(i).ingredientName + " (" + + this.get(i).ingredientCount + " left, expires on " + + this.get(i).expiryDate + ")\n"; + } + return ingredientList; + } + + // public method to print ingredients in list + public void printIngredients() { + System.out.println(listIngredients()); + } + + // public method to print expired ingredients and expiry date + // if no expired ingredients, print "No expired ingredients" + public void printExpiredIngredients() { + String expiredIngredients = ""; + for (Ingredient ingredient : this) { + if (ingredient.expired) { + expiredIngredients += ingredient.ingredientName + " (expires on " + + ingredient.expiryDate + ")\n"; + } + } + if (expiredIngredients.equals("")) { + System.out.println("No expired ingredients"); + } else { + System.out.println(expiredIngredients); + } + } + + // public method to clear all ingredients + public void clearIngredients() { + this.clear(); + } + + // public method to clear expired ingredients + public void clearExpiredIngredients() { + for (int i = 0; i < this.size(); i++) { + if (this.get(i).expired) { + this.remove(i); + } + } + } + +} diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 008112817b..444f3bedec 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Scanner; +import java.time.LocalDate; public class Parser { @@ -226,6 +227,15 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { } } + // parser to read dd/mm/yyyy format as local date + public LocalDate parseDate(String input) { + String[] date = input.split("/"); + int day = Integer.parseInt(date[0]); + int month = Integer.parseInt(date[1]); + int year = Integer.parseInt(date[2]); + return LocalDate.of(year, month, day); + } + public RecipeList parseLoadDatabase(String input) { return new RecipeList(); } From 7e4c032076e4afee4a1ea6a570c5d4b2d6d4ab17 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Wed, 22 Mar 2023 20:30:42 +0800 Subject: [PATCH 083/252] updated coding standards --- src/main/java/seedu/meal360/Ingredient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java index 69544086e2..cab254a5c1 100644 --- a/src/main/java/seedu/meal360/Ingredient.java +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -3,11 +3,11 @@ import java.time.LocalDate; public class Ingredient { + private static final Parser parser = new Parser(); public String ingredientName; public Integer ingredientCount; public LocalDate expiryDate; public Boolean expired; - private static final Parser parser = new Parser(); public Ingredient(String ingredientName, Integer ingredientCount, String expiryDate) { this.ingredientName = ingredientName; From ca3872d5c40908b86e0b84f58cbcfcbeb18e8c72 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Wed, 22 Mar 2023 22:54:15 +0800 Subject: [PATCH 084/252] add recipe tags in recipeList --- src/main/java/seedu/meal360/Meal360.java | 24 ++++++++++- src/main/java/seedu/meal360/Parser.java | 44 +++++++++++++++++++-- src/main/java/seedu/meal360/RecipeList.java | 25 +++++++++++- src/main/java/seedu/meal360/Ui.java | 3 -- text-ui-test/EXPECTED.TXT | 13 ++++++ text-ui-test/input.txt | 4 ++ 6 files changed, 104 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 7a6a4d8110..28df8f8e5c 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -69,8 +69,15 @@ public static void receiveInput(String input) { } ui.printSeparator(); } else if (command[0].equals("list")) { - RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); - ui.listRecipe(recipeListToPrint); + try { + ui.printSeparator(); + RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); + ui.listRecipe(recipeListToPrint); + } catch (IllegalArgumentException e) { + String errorMessage = "Please enter the command in the valid format. Some arguments might be missing."; + ui.printMessage(errorMessage); + } + ui.printSeparator(); } else if (command[0].equals("add")) { ui.printSeparator(); try { @@ -104,6 +111,19 @@ public static void receiveInput(String input) { ui.printMessage(errorMessage); } ui.printSeparator(); + } else if (command[0].equals("tag")) { + try { + ui.printSeparator(); + String tag = parser.parseTagRecipe(command, recipeList); + ui.printMessage("You have added the recipe(s) to this \"" + tag + "\" tag."); + } catch (IllegalArgumentException e) { + String errorMessage = "Please enter the command in the correct format."; + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = "Sorry, I am unable to find the recipes you entered."; + ui.printMessage(errorMessage); + } + ui.printSeparator(); } else if (command[0].equals("weekly")) { try { ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 008112817b..ff6e5da318 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -165,18 +165,56 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } } + public String parseTagRecipe(String[] inputs, RecipeList recipeList) { + String tag; + if (inputs.length == 1) { + throw new IllegalArgumentException("Please indicate at least a tag and a recipe."); + } else { + StringBuilder commandString = new StringBuilder(inputs[1]); + for (int i = 2; i < inputs.length; i++) { + commandString.append(" ").append(inputs[i]); + } + String[] args = commandString.toString().trim().split("<<"); + if (commandString.indexOf("<<") == -1) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } else if (args.length < 2) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } + tag = args[0].trim(); + String[] recipesToTag = args[1].split(","); + for (String recipeName : recipesToTag) { + recipeName = recipeName.trim(); + Recipe recipe = recipeList.findByName(recipeName); + if (recipe == null) { + throw new IndexOutOfBoundsException("Unable to find the recipe."); + } + recipeList.addRecipeToTag(tag, recipe); + } + } + return tag; + } + public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { String[] filters; + boolean isTag = false; if (inputs.length == 1) { filters = null; } else { - StringBuilder filterString = new StringBuilder(inputs[1]); - for (int i = 2; i < inputs.length; i++) { + int firstArgsIndex = 1; + if (inputs[1].equals("/t")){ + if (inputs.length == 2) { + throw new IllegalArgumentException("argument is missing."); + } + firstArgsIndex = 2; + isTag = true; + } + StringBuilder filterString = new StringBuilder(inputs[firstArgsIndex]); + for (int i = firstArgsIndex + 1; i < inputs.length; i++) { filterString.append(" ").append(inputs[i]); } filters = filterString.toString().split("&"); } - return recipeList.listRecipes(filters); + return recipeList.listRecipes(filters, isTag); } public Recipe parseViewRecipe(String[] command, RecipeList recipes) { diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 784a5ecb86..7745f77e0b 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -4,6 +4,7 @@ import java.util.HashMap; public class RecipeList extends ArrayList { + private HashMap> tags = new HashMap>(); public Recipe findByName(String name) { for (Recipe recipe : this) { @@ -28,11 +29,33 @@ public Recipe deleteRecipe(int recipeNum) { return recipeToDelete; } - public RecipeList listRecipes(String[] filters) { + public void addRecipeToTag(String tag, Recipe recipe) { + if (tags.containsKey(tag)) { + tags.get(tag).add(recipe); + } else { + assert !tags.containsKey(tags); + ArrayList tagRecipes = new ArrayList(); + tagRecipes.add(recipe); + tags.put(tag, tagRecipes); + assert tags.size() > 0 : "tag's size is still 0."; + } + } + + public RecipeList listRecipes(String[] filters, boolean isTag) { RecipeList filteredRecipeList = new RecipeList(); if (filters == null) { return this; } + if (isTag) { + for (String filter : filters) { + filter = filter.trim(); + ArrayList tagRecipes = this.tags.get(filter); + if (tagRecipes != null) { + filteredRecipeList.addAll(this.tags.get(filter)); + } + } + return filteredRecipeList; + } for (Recipe recipe : this) { filteredRecipeList.add(recipe); for (String filter : filters) { diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 66ed88c9a4..8e84520acf 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -58,12 +58,10 @@ public void printWeeklyPlan(WeeklyPlan weeklyPlan) { } public void listRecipe(RecipeList recipeListToPrint) { - printSeparator(); int numberOfRecipes = recipeListToPrint.size(); int order = 0; if (numberOfRecipes == 0) { printMessage("There is nothing to list."); - printSeparator(); return; } printMessage("These are the recipes you have (" + numberOfRecipes + " recipes):"); @@ -72,7 +70,6 @@ public void listRecipe(RecipeList recipeListToPrint) { printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); } - printSeparator(); } public void printHelp() { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 15c52f07bf..49af9dd38f 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -11,6 +11,19 @@ Welcome to Meal360, your ultimate Recipe Manager! | 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- +| You have added the recipe(s) to this "tag#1" tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| These are the recipes you have (1 recipes): | +| 1. test recipe name (1 ingredients) | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please enter the command in the valid format. Some arguments might be missing. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You did not enter a recipe number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 6617787d55..c49b4762b7 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,4 +1,8 @@ list +tag tag#1 << test recipe name +list /t tag#1 +list /t +list apple view view 1 view -2 From bd046e81026a2fadc26f59576899ed71cb10746d Mon Sep 17 00:00:00 2001 From: jaredoong Date: Wed, 22 Mar 2023 23:09:22 +0800 Subject: [PATCH 085/252] Add functionality to weekly planner User can now add and delete multiple recipes from the plan at once --- src/main/java/seedu/meal360/Database.java | 2 +- src/main/java/seedu/meal360/Meal360.java | 19 +- src/main/java/seedu/meal360/Parser.java | 164 +++++++++++++++--- src/main/java/seedu/meal360/WeeklyPlan.java | 16 +- .../InvalidNegativeValueException.java | 8 + .../InvalidRecipeNameException.java | 8 + 6 files changed, 189 insertions(+), 28 deletions(-) create mode 100644 src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java create mode 100644 src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index 3d9bac52b4..05560f5900 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -18,7 +18,7 @@ public RecipeList loadDatabase() throws IOException { RecipeList database; Gson gson = new Gson(); - // Check if the JSON file exists + // Check if the JSON file exists and create one if it does not File file = new File(recipesDatabaseFilepath); if (!file.exists()) { try { diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 56a7d16c94..dd633b366e 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -1,6 +1,9 @@ package seedu.meal360; +import java.io.IOException; import java.util.Scanner; +import seedu.meal360.exceptions.InvalidNegativeValueException; +import seedu.meal360.exceptions.InvalidRecipeNameException; public class Meal360 { @@ -25,7 +28,7 @@ public static void startApp() { try { recipeList = database.loadDatabase(); ui.printMessage("Database loaded successfully."); - } catch (Exception e) { + } catch (IOException e) { ui.printMessage("Error loading database, loading default database instead."); ui.printMessage("Overwriting database with new default database..."); recipeList = database.defaultRecipeList(); @@ -119,11 +122,17 @@ public static void receiveInput(String input) { WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); if (command[1].equals("/add")) { + weeklyPlan.addPlans(recipeMap); ui.printMessage("I've added the recipe to your weekly plan!"); - weeklyPlan.addPlan(recipeMap); } else if (command[1].equals("/delete")) { + weeklyPlan.deletePlans(recipeMap); ui.printMessage("I've deleted the recipe from your weekly plan!"); - weeklyPlan.deletePlan(recipeMap); + } else if (command[1].equals("/multiadd")) { + weeklyPlan.addPlans(recipeMap); + ui.printMessage("I've added the recipes to your weekly plan!"); + } else if (command[1].equals("/multidelete")) { + weeklyPlan.deletePlans(recipeMap); + ui.printMessage("I've deleted the recipes from your weekly plan!"); } } catch (NumberFormatException e) { String errorMessage = String.format("Please enter a valid number as the last argument."); @@ -133,6 +142,10 @@ public static void receiveInput(String input) { } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format("Insufficient number of arguments provided."); ui.printMessage(errorMessage); + } catch (InvalidNegativeValueException e) { + ui.printMessage(e.getMessage()); + } catch (InvalidRecipeNameException e) { + ui.printMessage(e.getMessage()); } ui.printSeparator(); } else if (command[0].equals("weeklyplan")) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 03162a93d8..848fc2e01d 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,15 +1,19 @@ package seedu.meal360; +import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; +import seedu.meal360.exceptions.InvalidNegativeValueException; +import seedu.meal360.exceptions.InvalidRecipeNameException; public class Parser { Ui ui = new Ui(); - public String combineWords(String[] input, int startIndex){ + public String combineWords(String[] input, int startIndex) { StringBuilder word = new StringBuilder(input[startIndex]); - for(int i = startIndex+1; i< input.length-1; i++) { + for (int i = startIndex + 1; i < input.length - 1; i++) { word.append(" ").append(input[i]); } @@ -52,7 +56,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { Scanner getInput = new Scanner(System.in); int index = getInput.nextInt(); - if(index == 1){ + if (index == 1) { System.out.println("Please Enter New Ingredients & Quantity: "); while (true) { String line = userInput.nextLine(); @@ -63,7 +67,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { ingredients.put(command[0], Integer.parseInt(command[1])); recipeList.editRecipe(recipeToEdit, ingredients); } - } else if(index == 2){ + } else if (index == 2) { System.out.println("These are the ingredients for the recipe:"); ui.printSeparator(); Recipe recipe = parseViewRecipe(recipeName, recipeList); @@ -75,11 +79,12 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { int count = 0; String ingredientToRemove = null; for (String ingredient : recipeToEdit.getIngredients().keySet()) { - if(ingredientIndex == count){ + if (ingredientIndex == count) { ingredientToRemove = ingredient; System.out.println("Ingredient to be changed:"); ui.printSeparator(); - String toPrint = String.format("%s(%d)", ingredient, recipeToEdit.getIngredients().get(ingredient)); + String toPrint = String.format("%s(%d)", ingredient, + recipeToEdit.getIngredients().get(ingredient)); System.out.println(ui.formatMessage(toPrint)); ui.printSeparator(); break; @@ -91,7 +96,8 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" "); String newIngredientName = combineWords(command, 0); recipeToEdit.getIngredients().remove(ingredientToRemove); - recipeToEdit.getIngredients().put(newIngredientName, Integer.parseInt(command[command.length-1])); + recipeToEdit.getIngredients() + .put(newIngredientName, Integer.parseInt(command[command.length - 1])); recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); } @@ -165,7 +171,8 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { int recipeIndex = Integer.parseInt(command[1]) - 1; return recipes.get(recipeIndex); } - public Recipe parseViewRecipe(String recipeName, RecipeList recipes){ + + public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { int recipeIndex = 1; for (Recipe recipe : recipes) { if (recipe.getName().equals(recipeName)) { @@ -173,39 +180,156 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes){ } recipeIndex++; } - return recipes.get(recipeIndex-1); + return recipes.get(recipeIndex - 1); } - public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { - if (!command[1].equals("/add") && !command[1].equals("/delete")) { + public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidNegativeValueException, InvalidRecipeNameException { + WeeklyPlan updatedWeeklyPlan; + if (command[1].equals("/add")) { + updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); + } else if (command[1].equals("/delete")) { + updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); + } else if (command[1].equals("/multiadd")) { + updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); + } else if (command[1].equals("/multidelete")) { + try { + updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); + } catch (InvalidRecipeNameException error) { + throw error; + } + } else { throw new IllegalArgumentException( "Please indicate if you would want to add or delete the recipe from your weekly " + "plan."); } + return updatedWeeklyPlan; + } - int numDays = 0; - if (command[1].equals("/add")) { - numDays = Integer.parseInt(command[command.length - 1]); - if (numDays < 1) { - throw new NumberFormatException(); - } + public WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidNegativeValueException, InvalidRecipeNameException { + int numDays = Integer.parseInt(command[command.length - 1]); + if (numDays < 1) { + throw new InvalidNegativeValueException("Number of days needs to be at least 1."); } - int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; + int nameLastIndex = command.length - 1; WeeklyPlan thisWeekPlan = new WeeklyPlan(); StringBuilder recipeName = new StringBuilder(command[2]); for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i]); + recipeName.append(" ").append(command[i].toLowerCase().trim()); } if (recipes.findByName(recipeName.toString().trim()) != null) { thisWeekPlan.put(recipeName.toString(), numDays); return thisWeekPlan; } else { - throw new IllegalArgumentException("Please indicate a valid recipe name."); + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } + } + + public WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException { + int nameLastIndex = command.length; + WeeklyPlan thisWeekPlan = new WeeklyPlan(); + StringBuilder recipeName = new StringBuilder(command[2]); + for (int i = 3; i < nameLastIndex; i++) { + recipeName.append(" ").append(command[i].toLowerCase().trim()); + } + + if (recipes.findByName(recipeName.toString().trim()) != null) { + thisWeekPlan.put(recipeName.toString(), 0); + return thisWeekPlan; + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); } } + public WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) { + WeeklyPlan recipesToAdd = new WeeklyPlan(); + ArrayList quantities = new ArrayList<>(); + ArrayList recipeNames = new ArrayList<>(); + ArrayList startIndices = new ArrayList<>(); + ArrayList endIndices = new ArrayList<>(); + StringBuilder recipeName = new StringBuilder(); + + for (int i = 0; i < command.length; i++) { + if (command[i].equals("/r")) { + startIndices.add(i); + } else if (command[i].equals("/q")) { + endIndices.add(i); + quantities.add(Integer.parseInt(command[i + 1])); + } + } + + // Checks that command is entered in the correct + if (startIndices.size() != endIndices.size()) { + throw new IllegalArgumentException("Please ensure the number of recipes and quantities match."); + } + + // Building the recipe names + for (int i = 0; i < startIndices.size(); i++) { + int nameStartIndex = startIndices.get(i) + 1; + int nameEndIndex = endIndices.get(i) - 1; + recipeName.append(command[nameStartIndex].toLowerCase().trim()); + for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { + recipeName.append(" ").append(command[j].toLowerCase().trim()); + } + recipeNames.add(recipeName.toString()); + recipeName = new StringBuilder(); + } + + // Add each recipe to the weekly plan + for (int i = 0; i < recipeNames.size(); i++) { + if (recipes.findByName(recipeNames.get(i)) != null) { + recipesToAdd.put(recipeNames.get(i), quantities.get(i)); + } else { + throw new IllegalArgumentException("Please indicate a valid recipe name."); + } + } + + return recipesToAdd; + } + + public WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException { + WeeklyPlan recipesToDelete = new WeeklyPlan(); + ArrayList recipeNames = new ArrayList<>(); + ArrayList startIndices = new ArrayList<>(); + StringBuilder recipeName = new StringBuilder(); + + for (int i = 0; i < command.length; i++) { + if (command[i].equals("/r")) { + startIndices.add(i); + } + } + + // Building the recipe names + for (int i = 0; i < startIndices.size(); i++) { + int nameStartIndex = startIndices.get(i) + 1; + int nameEndIndex = + (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; + + recipeName.append(command[nameStartIndex].toLowerCase().trim()); + for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { + recipeName.append(" ").append(command[j].toLowerCase().trim()); + } + recipeNames.add(recipeName.toString()); + recipeName = new StringBuilder(); + } + + // Add each recipe to the weekly plan + for (int i = 0; i < recipeNames.size(); i++) { + if (recipes.findByName(recipeNames.get(i)) != null) { + recipesToDelete.put(recipeNames.get(i), 0); + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } + } + + return recipesToDelete; + } + public RecipeList parseLoadDatabase(String input) { return new RecipeList(); } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index f64835ae62..262d8fa024 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -4,15 +4,23 @@ public class WeeklyPlan extends HashMap { - public void addPlan(WeeklyPlan recipeMap) { + public void addPlans(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { - this.put(recipe, count); + if (this.containsKey(recipe)) { + this.put(recipe, this.get(recipe) + count); + } else { + this.put(recipe, count); + } }); } - public void deletePlan(WeeklyPlan recipeMap) { + public void deletePlans(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { - this.remove(recipe); + if (this.containsKey(recipe)) { + this.remove(recipe); + } else { + throw new IllegalArgumentException("Recipe does not exist in weekly plan!"); + } }); } } diff --git a/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java b/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java new file mode 100644 index 0000000000..12790132ac --- /dev/null +++ b/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java @@ -0,0 +1,8 @@ +package seedu.meal360.exceptions; + +public class InvalidNegativeValueException extends Exception { + + public InvalidNegativeValueException(String message) { + super(message); + } +} diff --git a/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java b/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java new file mode 100644 index 0000000000..33bcb1360b --- /dev/null +++ b/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java @@ -0,0 +1,8 @@ +package seedu.meal360.exceptions; + +public class InvalidRecipeNameException extends Exception{ + + public InvalidRecipeNameException(String message) { + super(message); + } +} From 338466c4fde090fdbd6c1a106c6af141005f49cf Mon Sep 17 00:00:00 2001 From: jaredoong Date: Wed, 22 Mar 2023 23:15:58 +0800 Subject: [PATCH 086/252] Revert "Add functionality to weekly planner" This reverts commit bd046e81026a2fadc26f59576899ed71cb10746d. --- src/main/java/seedu/meal360/Database.java | 2 +- src/main/java/seedu/meal360/Meal360.java | 19 +- src/main/java/seedu/meal360/Parser.java | 164 +++--------------- src/main/java/seedu/meal360/WeeklyPlan.java | 16 +- .../InvalidNegativeValueException.java | 8 - .../InvalidRecipeNameException.java | 8 - 6 files changed, 28 insertions(+), 189 deletions(-) delete mode 100644 src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java delete mode 100644 src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index 05560f5900..3d9bac52b4 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -18,7 +18,7 @@ public RecipeList loadDatabase() throws IOException { RecipeList database; Gson gson = new Gson(); - // Check if the JSON file exists and create one if it does not + // Check if the JSON file exists File file = new File(recipesDatabaseFilepath); if (!file.exists()) { try { diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index dd633b366e..56a7d16c94 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -1,9 +1,6 @@ package seedu.meal360; -import java.io.IOException; import java.util.Scanner; -import seedu.meal360.exceptions.InvalidNegativeValueException; -import seedu.meal360.exceptions.InvalidRecipeNameException; public class Meal360 { @@ -28,7 +25,7 @@ public static void startApp() { try { recipeList = database.loadDatabase(); ui.printMessage("Database loaded successfully."); - } catch (IOException e) { + } catch (Exception e) { ui.printMessage("Error loading database, loading default database instead."); ui.printMessage("Overwriting database with new default database..."); recipeList = database.defaultRecipeList(); @@ -122,17 +119,11 @@ public static void receiveInput(String input) { WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); if (command[1].equals("/add")) { - weeklyPlan.addPlans(recipeMap); ui.printMessage("I've added the recipe to your weekly plan!"); + weeklyPlan.addPlan(recipeMap); } else if (command[1].equals("/delete")) { - weeklyPlan.deletePlans(recipeMap); ui.printMessage("I've deleted the recipe from your weekly plan!"); - } else if (command[1].equals("/multiadd")) { - weeklyPlan.addPlans(recipeMap); - ui.printMessage("I've added the recipes to your weekly plan!"); - } else if (command[1].equals("/multidelete")) { - weeklyPlan.deletePlans(recipeMap); - ui.printMessage("I've deleted the recipes from your weekly plan!"); + weeklyPlan.deletePlan(recipeMap); } } catch (NumberFormatException e) { String errorMessage = String.format("Please enter a valid number as the last argument."); @@ -142,10 +133,6 @@ public static void receiveInput(String input) { } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format("Insufficient number of arguments provided."); ui.printMessage(errorMessage); - } catch (InvalidNegativeValueException e) { - ui.printMessage(e.getMessage()); - } catch (InvalidRecipeNameException e) { - ui.printMessage(e.getMessage()); } ui.printSeparator(); } else if (command[0].equals("weeklyplan")) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 848fc2e01d..03162a93d8 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,19 +1,15 @@ package seedu.meal360; -import java.lang.reflect.Array; -import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; -import seedu.meal360.exceptions.InvalidNegativeValueException; -import seedu.meal360.exceptions.InvalidRecipeNameException; public class Parser { Ui ui = new Ui(); - public String combineWords(String[] input, int startIndex) { + public String combineWords(String[] input, int startIndex){ StringBuilder word = new StringBuilder(input[startIndex]); - for (int i = startIndex + 1; i < input.length - 1; i++) { + for(int i = startIndex+1; i< input.length-1; i++) { word.append(" ").append(input[i]); } @@ -56,7 +52,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { Scanner getInput = new Scanner(System.in); int index = getInput.nextInt(); - if (index == 1) { + if(index == 1){ System.out.println("Please Enter New Ingredients & Quantity: "); while (true) { String line = userInput.nextLine(); @@ -67,7 +63,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { ingredients.put(command[0], Integer.parseInt(command[1])); recipeList.editRecipe(recipeToEdit, ingredients); } - } else if (index == 2) { + } else if(index == 2){ System.out.println("These are the ingredients for the recipe:"); ui.printSeparator(); Recipe recipe = parseViewRecipe(recipeName, recipeList); @@ -79,12 +75,11 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { int count = 0; String ingredientToRemove = null; for (String ingredient : recipeToEdit.getIngredients().keySet()) { - if (ingredientIndex == count) { + if(ingredientIndex == count){ ingredientToRemove = ingredient; System.out.println("Ingredient to be changed:"); ui.printSeparator(); - String toPrint = String.format("%s(%d)", ingredient, - recipeToEdit.getIngredients().get(ingredient)); + String toPrint = String.format("%s(%d)", ingredient, recipeToEdit.getIngredients().get(ingredient)); System.out.println(ui.formatMessage(toPrint)); ui.printSeparator(); break; @@ -96,8 +91,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" "); String newIngredientName = combineWords(command, 0); recipeToEdit.getIngredients().remove(ingredientToRemove); - recipeToEdit.getIngredients() - .put(newIngredientName, Integer.parseInt(command[command.length - 1])); + recipeToEdit.getIngredients().put(newIngredientName, Integer.parseInt(command[command.length-1])); recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); } @@ -171,8 +165,7 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { int recipeIndex = Integer.parseInt(command[1]) - 1; return recipes.get(recipeIndex); } - - public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { + public Recipe parseViewRecipe(String recipeName, RecipeList recipes){ int recipeIndex = 1; for (Recipe recipe : recipes) { if (recipe.getName().equals(recipeName)) { @@ -180,156 +173,39 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { } recipeIndex++; } - return recipes.get(recipeIndex - 1); + return recipes.get(recipeIndex-1); } - public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { - WeeklyPlan updatedWeeklyPlan; - if (command[1].equals("/add")) { - updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); - } else if (command[1].equals("/delete")) { - updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); - } else if (command[1].equals("/multiadd")) { - updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); - } else if (command[1].equals("/multidelete")) { - try { - updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); - } catch (InvalidRecipeNameException error) { - throw error; - } - } else { + public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { + if (!command[1].equals("/add") && !command[1].equals("/delete")) { throw new IllegalArgumentException( "Please indicate if you would want to add or delete the recipe from your weekly " + "plan."); } - return updatedWeeklyPlan; - } - public WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { - int numDays = Integer.parseInt(command[command.length - 1]); - if (numDays < 1) { - throw new InvalidNegativeValueException("Number of days needs to be at least 1."); + int numDays = 0; + if (command[1].equals("/add")) { + numDays = Integer.parseInt(command[command.length - 1]); + if (numDays < 1) { + throw new NumberFormatException(); + } } - int nameLastIndex = command.length - 1; + int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; WeeklyPlan thisWeekPlan = new WeeklyPlan(); StringBuilder recipeName = new StringBuilder(command[2]); for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i].toLowerCase().trim()); + recipeName.append(" ").append(command[i]); } if (recipes.findByName(recipeName.toString().trim()) != null) { thisWeekPlan.put(recipeName.toString(), numDays); return thisWeekPlan; } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } - - public WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - int nameLastIndex = command.length; - WeeklyPlan thisWeekPlan = new WeeklyPlan(); - StringBuilder recipeName = new StringBuilder(command[2]); - for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i].toLowerCase().trim()); - } - - if (recipes.findByName(recipeName.toString().trim()) != null) { - thisWeekPlan.put(recipeName.toString(), 0); - return thisWeekPlan; - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + throw new IllegalArgumentException("Please indicate a valid recipe name."); } } - public WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) { - WeeklyPlan recipesToAdd = new WeeklyPlan(); - ArrayList quantities = new ArrayList<>(); - ArrayList recipeNames = new ArrayList<>(); - ArrayList startIndices = new ArrayList<>(); - ArrayList endIndices = new ArrayList<>(); - StringBuilder recipeName = new StringBuilder(); - - for (int i = 0; i < command.length; i++) { - if (command[i].equals("/r")) { - startIndices.add(i); - } else if (command[i].equals("/q")) { - endIndices.add(i); - quantities.add(Integer.parseInt(command[i + 1])); - } - } - - // Checks that command is entered in the correct - if (startIndices.size() != endIndices.size()) { - throw new IllegalArgumentException("Please ensure the number of recipes and quantities match."); - } - - // Building the recipe names - for (int i = 0; i < startIndices.size(); i++) { - int nameStartIndex = startIndices.get(i) + 1; - int nameEndIndex = endIndices.get(i) - 1; - recipeName.append(command[nameStartIndex].toLowerCase().trim()); - for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { - recipeName.append(" ").append(command[j].toLowerCase().trim()); - } - recipeNames.add(recipeName.toString()); - recipeName = new StringBuilder(); - } - - // Add each recipe to the weekly plan - for (int i = 0; i < recipeNames.size(); i++) { - if (recipes.findByName(recipeNames.get(i)) != null) { - recipesToAdd.put(recipeNames.get(i), quantities.get(i)); - } else { - throw new IllegalArgumentException("Please indicate a valid recipe name."); - } - } - - return recipesToAdd; - } - - public WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - WeeklyPlan recipesToDelete = new WeeklyPlan(); - ArrayList recipeNames = new ArrayList<>(); - ArrayList startIndices = new ArrayList<>(); - StringBuilder recipeName = new StringBuilder(); - - for (int i = 0; i < command.length; i++) { - if (command[i].equals("/r")) { - startIndices.add(i); - } - } - - // Building the recipe names - for (int i = 0; i < startIndices.size(); i++) { - int nameStartIndex = startIndices.get(i) + 1; - int nameEndIndex = - (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; - - recipeName.append(command[nameStartIndex].toLowerCase().trim()); - for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { - recipeName.append(" ").append(command[j].toLowerCase().trim()); - } - recipeNames.add(recipeName.toString()); - recipeName = new StringBuilder(); - } - - // Add each recipe to the weekly plan - for (int i = 0; i < recipeNames.size(); i++) { - if (recipes.findByName(recipeNames.get(i)) != null) { - recipesToDelete.put(recipeNames.get(i), 0); - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } - - return recipesToDelete; - } - public RecipeList parseLoadDatabase(String input) { return new RecipeList(); } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index 262d8fa024..f64835ae62 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -4,23 +4,15 @@ public class WeeklyPlan extends HashMap { - public void addPlans(WeeklyPlan recipeMap) { + public void addPlan(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { - if (this.containsKey(recipe)) { - this.put(recipe, this.get(recipe) + count); - } else { - this.put(recipe, count); - } + this.put(recipe, count); }); } - public void deletePlans(WeeklyPlan recipeMap) { + public void deletePlan(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { - if (this.containsKey(recipe)) { - this.remove(recipe); - } else { - throw new IllegalArgumentException("Recipe does not exist in weekly plan!"); - } + this.remove(recipe); }); } } diff --git a/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java b/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java deleted file mode 100644 index 12790132ac..0000000000 --- a/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java +++ /dev/null @@ -1,8 +0,0 @@ -package seedu.meal360.exceptions; - -public class InvalidNegativeValueException extends Exception { - - public InvalidNegativeValueException(String message) { - super(message); - } -} diff --git a/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java b/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java deleted file mode 100644 index 33bcb1360b..0000000000 --- a/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java +++ /dev/null @@ -1,8 +0,0 @@ -package seedu.meal360.exceptions; - -public class InvalidRecipeNameException extends Exception{ - - public InvalidRecipeNameException(String message) { - super(message); - } -} From b35f1ec5b775b017567c154ccfdc739bcaa869fe Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 23 Mar 2023 00:25:51 +0800 Subject: [PATCH 087/252] add remove recipe from a tag --- src/main/java/seedu/meal360/Meal360.java | 2 +- src/main/java/seedu/meal360/Parser.java | 59 ++++++++++++++++----- src/main/java/seedu/meal360/RecipeList.java | 14 +++++ text-ui-test/EXPECTED.TXT | 8 ++- text-ui-test/input.txt | 2 + 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 28df8f8e5c..0102cd90fb 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -115,7 +115,7 @@ public static void receiveInput(String input) { try { ui.printSeparator(); String tag = parser.parseTagRecipe(command, recipeList); - ui.printMessage("You have added the recipe(s) to this \"" + tag + "\" tag."); + ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); } catch (IllegalArgumentException e) { String errorMessage = "Please enter the command in the correct format."; ui.printMessage(errorMessage); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index ff6e5da318..b13e27789e 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -174,22 +174,55 @@ public String parseTagRecipe(String[] inputs, RecipeList recipeList) { for (int i = 2; i < inputs.length; i++) { commandString.append(" ").append(inputs[i]); } - String[] args = commandString.toString().trim().split("<<"); - if (commandString.indexOf("<<") == -1) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } else if (args.length < 2) { + boolean isAddTag = commandString.indexOf("<<") != -1 && commandString.indexOf(">>") == -1; + boolean isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; + if (!(isAddTag || isRemoveTag)) { throw new IllegalArgumentException("Please enter the command in the correct format."); + } else if (isAddTag) { + tag = parseAddRecipeTag(commandString.toString(), recipeList); + } else if (isRemoveTag) { + tag = parseRemoveRecipeTag(commandString.toString(), recipeList); + } else { + throw new IllegalArgumentException("Invalid command."); } - tag = args[0].trim(); - String[] recipesToTag = args[1].split(","); - for (String recipeName : recipesToTag) { - recipeName = recipeName.trim(); - Recipe recipe = recipeList.findByName(recipeName); - if (recipe == null) { - throw new IndexOutOfBoundsException("Unable to find the recipe."); - } - recipeList.addRecipeToTag(tag, recipe); + } + return tag; + } + + public String parseAddRecipeTag(String command, RecipeList recipeList) { + String tag; + String[] args = command.trim().split("<<"); + if (args.length < 2) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } + tag = args[0].trim(); + String[] recipesToTag = args[1].split(","); + for (String recipeName : recipesToTag) { + recipeName = recipeName.trim(); + Recipe recipe = recipeList.findByName(recipeName); + if (recipe == null) { + throw new IndexOutOfBoundsException("Unable to find the recipe."); + } + recipeList.addRecipeToTag(tag, recipe); + } + return tag; + } + + public String parseRemoveRecipeTag(String command, RecipeList recipeList) { + String tag; + String[] args = command.trim().split(">>"); + if (args.length < 2) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } + tag = args[0].trim(); + String[] recipesToTag = args[1].split(","); + for (String recipeName : recipesToTag) { + recipeName = recipeName.trim(); + Recipe recipe = recipeList.findByName(recipeName); + if (recipe == null) { + throw new IndexOutOfBoundsException("Unable to find the recipe."); } + recipeList.removeRecipeFromTag(tag, recipe); } return tag; } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 7745f77e0b..85c30a8402 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -41,6 +41,20 @@ public void addRecipeToTag(String tag, Recipe recipe) { } } + public void removeRecipeFromTag(String tag, Recipe recipe) { + if (!tags.containsKey(tag)) { + throw new IndexOutOfBoundsException("Invalid tag"); + } else { + ArrayList tagRecipeList = tags.get(tag); + for (int i = 0; i < tagRecipeList.size(); i++) { + Recipe recipeInTag = tagRecipeList.get(i); + if (recipe.getName().equals(recipeInTag.getName())) { + tagRecipeList.remove(i); + } + } + } + } + public RecipeList listRecipes(String[] filters, boolean isTag) { RecipeList filteredRecipeList = new RecipeList(); if (filters == null) { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 49af9dd38f..8d2caa49ab 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -11,7 +11,7 @@ Welcome to Meal360, your ultimate Recipe Manager! | 1. test recipe name (1 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have added the recipe(s) to this "tag#1" tag. | +| You have modified the recipe(s) in this "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes): | @@ -24,6 +24,12 @@ Welcome to Meal360, your ultimate Recipe Manager! | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- +| You have modified the recipe(s) in this "tag#1" tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You did not enter a recipe number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index c49b4762b7..d44391e8c3 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -3,6 +3,8 @@ tag tag#1 << test recipe name list /t tag#1 list /t list apple +tag tag#1 >> test recipe name +list /t tag#1 view view 1 view -2 From dfc50b97361812f2f3742ff474d5cf68c7e9293d Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 23 Mar 2023 00:27:37 +0800 Subject: [PATCH 088/252] Refactor code Edit exception handling and Junit test code --- .gitignore | 2 +- src/main/java/seedu/meal360/Meal360.java | 45 ++----- src/main/java/seedu/meal360/Parser.java | 123 ++++++++++-------- .../InvalidNegativeValueException.java | 6 +- .../InvalidRecipeNameException.java | 8 +- src/main/resources/recipesDatabase.json | 1 - src/test/java/seedu/meal360/Meal360Test.java | 40 ++++-- 7 files changed, 114 insertions(+), 111 deletions(-) delete mode 100644 src/main/resources/recipesDatabase.json diff --git a/.gitignore b/.gitignore index 4bf4c09733..54416cba09 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ # Gradle build files /.gradle/ /build/ -src/main/resources/docs/ +/src/main/resources/ # MacOS custom attributes files created by Finder .DS_Store diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index dd633b366e..9e3523e793 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -28,8 +28,8 @@ public static void startApp() { try { recipeList = database.loadDatabase(); ui.printMessage("Database loaded successfully."); - } catch (IOException e) { - ui.printMessage("Error loading database, loading default database instead."); + } catch (IOException error) { + ui.printMessage(error.getMessage()); ui.printMessage("Overwriting database with new default database..."); recipeList = database.defaultRecipeList(); } @@ -65,20 +65,8 @@ public static void receiveInput(String input) { try { Recipe recipe = parser.parseViewRecipe(command, recipeList); ui.printRecipe(recipe); - } catch (NumberFormatException e) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is not a number.", - command[1]); - ui.printMessage(errorMessage); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number. You did not enter a recipe number."); - ui.printMessage(errorMessage); - } catch (IndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", - command[1]); - ui.printMessage(errorMessage); + } catch (NumberFormatException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); } ui.printSeparator(); } else if (command[0].equals("list")) { @@ -121,30 +109,15 @@ public static void receiveInput(String input) { ui.printSeparator(); WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); - if (command[1].equals("/add")) { - weeklyPlan.addPlans(recipeMap); - ui.printMessage("I've added the recipe to your weekly plan!"); - } else if (command[1].equals("/delete")) { - weeklyPlan.deletePlans(recipeMap); - ui.printMessage("I've deleted the recipe from your weekly plan!"); - } else if (command[1].equals("/multiadd")) { + if (command[1].equals("/add") || command[1].equals("/multiadd")) { weeklyPlan.addPlans(recipeMap); ui.printMessage("I've added the recipes to your weekly plan!"); - } else if (command[1].equals("/multidelete")) { + } else if (command[1].equals("/delete") || command[1].equals("/multidelete")) { weeklyPlan.deletePlans(recipeMap); ui.printMessage("I've deleted the recipes from your weekly plan!"); } - } catch (NumberFormatException e) { - String errorMessage = String.format("Please enter a valid number as the last argument."); - ui.printMessage(errorMessage); - } catch (IllegalArgumentException e) { - ui.printMessage(e.getMessage()); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = String.format("Insufficient number of arguments provided."); - ui.printMessage(errorMessage); - } catch (InvalidNegativeValueException e) { - ui.printMessage(e.getMessage()); - } catch (InvalidRecipeNameException e) { + } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException | + ArrayIndexOutOfBoundsException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -171,7 +144,7 @@ public static void exitApp() { try { database.saveDatabase(recipeList); ui.printMessage("Database saved successfully."); - } catch (Exception e) { + } catch (IOException error) { ui.printMessage("Error saving database."); } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 848fc2e01d..75e4c8e1e7 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,6 +1,5 @@ package seedu.meal360; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; @@ -110,14 +109,14 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { // skip over /r in recipe name String recipeToDelete = input[1].substring(2); if (recipeToDelete.equals("all")) { - String allRecipes = ""; + StringBuilder allRecipes = new StringBuilder(); System.out.println("recipeList size: " + recipeList.size()); int index = 0; while (recipeList.size() != 0) { - allRecipes += recipeList.deleteRecipe(index).getName() + ", "; + allRecipes.append(recipeList.deleteRecipe(index).getName()).append(", "); } - allRecipes = allRecipes.substring(0, allRecipes.length() - 2); - return allRecipes; + allRecipes = new StringBuilder(allRecipes.substring(0, allRecipes.length() - 2)); + return allRecipes.toString(); } else { int recipeIndex = 0; for (Recipe recipe : recipeList) { @@ -133,17 +132,17 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } else { // deleting a range of recipes if (input[1].length() >= 3) { - String rangeRecipes = ""; + StringBuilder rangeRecipes = new StringBuilder(); int startIndex = Integer.parseInt(input[1].charAt(0) + ""); int endIndex = Integer.parseInt(input[1].charAt(2) + ""); startIndex -= 1; endIndex -= 1; int newSize = recipeList.size() - ((endIndex - startIndex) + 1); while (recipeList.size() != newSize) { - rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; + rangeRecipes.append(recipeList.deleteRecipe(startIndex).getName()).append(", "); } - rangeRecipes = rangeRecipes.substring(0, rangeRecipes.length() - 2); - return rangeRecipes; + rangeRecipes = new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2)); + return rangeRecipes.toString(); } else { int recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based @@ -168,8 +167,26 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { public Recipe parseViewRecipe(String[] command, RecipeList recipes) { assert command[0].equals("view"); - int recipeIndex = Integer.parseInt(command[1]) - 1; - return recipes.get(recipeIndex); + Recipe requestedRecipe; + int recipeIndex = 0; + try { + recipeIndex = Integer.parseInt(command[1]); + requestedRecipe = recipes.get(recipeIndex - 1); + } catch (NumberFormatException error) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is not a number.", + command[1]); + throw new NumberFormatException(errorMessage); + } catch (ArrayIndexOutOfBoundsException error) { + String errorMessage = "Please enter a valid recipe number. You did not enter a recipe number."; + throw new ArrayIndexOutOfBoundsException(errorMessage); + } catch (IndexOutOfBoundsException error) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %d, " + "which is out of bounds.", + recipeIndex); + throw new IndexOutOfBoundsException(errorMessage); + } + return requestedRecipe; } public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { @@ -184,29 +201,36 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { } public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { + throws InvalidRecipeNameException, InvalidNegativeValueException { WeeklyPlan updatedWeeklyPlan; - if (command[1].equals("/add")) { - updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); - } else if (command[1].equals("/delete")) { - updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); - } else if (command[1].equals("/multiadd")) { - updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); - } else if (command[1].equals("/multidelete")) { - try { + try { + switch (command[1]) { + case "/add": + updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); + break; + case "/delete": + updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); + break; + case "/multidelete": updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); - } catch (InvalidRecipeNameException error) { - throw error; + break; + default: + throw new IllegalArgumentException( + "Please indicate if you would want to add or delete the recipe from your weekly " + + "plan."); } - } else { - throw new IllegalArgumentException( - "Please indicate if you would want to add or delete the recipe from your weekly " - + "plan."); + } catch (ArrayIndexOutOfBoundsException error) { + throw new ArrayIndexOutOfBoundsException("Insufficient number of arguments provided."); + } catch (NumberFormatException error) { + throw new NumberFormatException("Please enter a valid number as the last argument."); } return updatedWeeklyPlan; } - public WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) + private WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) throws InvalidNegativeValueException, InvalidRecipeNameException { int numDays = Integer.parseInt(command[command.length - 1]); if (numDays < 1) { @@ -228,7 +252,7 @@ public WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) } } - public WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) + private WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) throws InvalidRecipeNameException { int nameLastIndex = command.length; WeeklyPlan thisWeekPlan = new WeeklyPlan(); @@ -245,7 +269,7 @@ public WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recip } } - public WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) { + private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) { WeeklyPlan recipesToAdd = new WeeklyPlan(); ArrayList quantities = new ArrayList<>(); ArrayList recipeNames = new ArrayList<>(); @@ -271,12 +295,7 @@ public WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) for (int i = 0; i < startIndices.size(); i++) { int nameStartIndex = startIndices.get(i) + 1; int nameEndIndex = endIndices.get(i) - 1; - recipeName.append(command[nameStartIndex].toLowerCase().trim()); - for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { - recipeName.append(" ").append(command[j].toLowerCase().trim()); - } - recipeNames.add(recipeName.toString()); - recipeName = new StringBuilder(); + recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); } // Add each recipe to the weekly plan @@ -291,7 +310,18 @@ public WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) return recipesToAdd; } - public WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) + private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, + StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { + recipeName.append(command[nameStartIndex].toLowerCase().trim()); + for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { + recipeName.append(" ").append(command[j].toLowerCase().trim()); + } + recipeNames.add(recipeName.toString()); + recipeName = new StringBuilder(); + return recipeName; + } + + private WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) throws InvalidRecipeNameException { WeeklyPlan recipesToDelete = new WeeklyPlan(); ArrayList recipeNames = new ArrayList<>(); @@ -310,18 +340,13 @@ public WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipe int nameEndIndex = (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; - recipeName.append(command[nameStartIndex].toLowerCase().trim()); - for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { - recipeName.append(" ").append(command[j].toLowerCase().trim()); - } - recipeNames.add(recipeName.toString()); - recipeName = new StringBuilder(); + recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); } // Add each recipe to the weekly plan - for (int i = 0; i < recipeNames.size(); i++) { - if (recipes.findByName(recipeNames.get(i)) != null) { - recipesToDelete.put(recipeNames.get(i), 0); + for (String name : recipeNames) { + if (recipes.findByName(name) != null) { + recipesToDelete.put(name, 0); } else { throw new InvalidRecipeNameException("Please indicate a valid recipe name."); } @@ -329,12 +354,4 @@ public WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipe return recipesToDelete; } - - public RecipeList parseLoadDatabase(String input) { - return new RecipeList(); - } - - public String parseSaveDatabase(String input) { - return "test"; - } } diff --git a/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java b/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java index 12790132ac..490541f099 100644 --- a/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java +++ b/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java @@ -2,7 +2,7 @@ public class InvalidNegativeValueException extends Exception { - public InvalidNegativeValueException(String message) { - super(message); - } + public InvalidNegativeValueException(String message) { + super(message); + } } diff --git a/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java b/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java index 33bcb1360b..ad4a8cf8db 100644 --- a/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java +++ b/src/main/java/seedu/meal360/exceptions/InvalidRecipeNameException.java @@ -1,8 +1,8 @@ package seedu.meal360.exceptions; -public class InvalidRecipeNameException extends Exception{ +public class InvalidRecipeNameException extends Exception { - public InvalidRecipeNameException(String message) { - super(message); - } + public InvalidRecipeNameException(String message) { + super(message); + } } diff --git a/src/main/resources/recipesDatabase.json b/src/main/resources/recipesDatabase.json deleted file mode 100644 index 0beacc58a3..0000000000 --- a/src/main/resources/recipesDatabase.json +++ /dev/null @@ -1 +0,0 @@ -[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 43cdf5a8d9..74e606c301 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -11,6 +11,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import seedu.meal360.exceptions.InvalidNegativeValueException; +import seedu.meal360.exceptions.InvalidRecipeNameException; class Meal360Test { @@ -68,7 +70,6 @@ public void tearDownRecipes() { @Test public void testViewRecipe() { - Parser parser = new Parser(); Recipe recipe = parser.parseViewRecipe(new String[]{"view", "1"}, recipes); assertEquals("burger", recipe.getName()); assertEquals(2, (int) recipe.getIngredients().get("buns")); @@ -115,23 +116,22 @@ public void testDeleteRecipe() { recipes.deleteRecipe(recipes.indexOf(testR)); int newRecipeListSize = recipes.size(); // check if recipe list size is 1 less than before - assertTrue((oldRecipeListSize - 1) == newRecipeListSize); + assertEquals((oldRecipeListSize - 1), newRecipeListSize); } @Test - public void testAddWeeklyPlan() { + public void testAddWeeklyPlan() throws InvalidRecipeNameException, InvalidNegativeValueException { WeeklyPlan weeklyPlan = new WeeklyPlan(); - WeeklyPlan recipeMap; // Testing add recipe to weekly plan - recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "1"}, recipes); - weeklyPlan.addPlan(recipeMap); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "1"}, recipes); + weeklyPlan.addPlans(recipeMap); assertTrue(weeklyPlan.containsKey("burger")); assertEquals(1, (int) weeklyPlan.get("burger")); assertFalse(weeklyPlan.containsKey("pizza")); recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/add", "pizza", "3"}, recipes); - weeklyPlan.addPlan(recipeMap); + weeklyPlan.addPlans(recipeMap); assertTrue(weeklyPlan.containsKey("pizza")); assertEquals(3, (int) weeklyPlan.get("pizza")); @@ -162,13 +162,19 @@ public void testAddWeeklyPlan() { try { parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "0"}, recipes); - } catch (NumberFormatException e) { + } catch (InvalidNegativeValueException e) { assertTrue(true); } try { parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "-9"}, recipes); - } catch (NumberFormatException e) { + } catch (InvalidNegativeValueException e) { + assertTrue(true); + } + + try { + parser.parseWeeklyPlan(new String[]{"weekly", "/add", "unknown", "1"}, recipes); + } catch (InvalidRecipeNameException e) { assertTrue(true); } } @@ -182,13 +188,21 @@ public void testDeleteWeeklyPlan() { // Testing delete recipe from weekly plan int oldWeeklyPlanSize = weeklyPlan.size(); WeeklyPlan toDelete = new WeeklyPlan(); + + // Testing negative case toDelete.put("burger", 0); - weeklyPlan.deletePlan(toDelete); + try { + weeklyPlan.deletePlans(toDelete); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + // Testing positive case int newWeeklyPlanSize = weeklyPlan.size(); assertEquals(oldWeeklyPlanSize, newWeeklyPlanSize); - + toDelete.clear(); toDelete.put("salad", 0); - weeklyPlan.deletePlan(toDelete); + weeklyPlan.deletePlans(toDelete); newWeeklyPlanSize = weeklyPlan.size(); assertEquals(oldWeeklyPlanSize - 1, newWeeklyPlanSize); } @@ -241,6 +255,6 @@ public void testListRecipe() { @Test public void testLoadDatabase() { - assertDoesNotThrow(() -> database.loadDatabase()); + assertDoesNotThrow(database::loadDatabase); } } From b625312ac757b359689b728d0b3f162c1c5e41c8 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 23 Mar 2023 02:50:59 +0800 Subject: [PATCH 089/252] Update JUnit tests for adding and deleting multiple recipes from weekly planner in one command --- src/main/java/seedu/meal360/Database.java | 20 +-- src/main/java/seedu/meal360/Meal360.java | 8 +- src/main/java/seedu/meal360/Parser.java | 30 +++- src/test/java/seedu/meal360/Meal360Test.java | 137 +++++++++++++------ 4 files changed, 129 insertions(+), 66 deletions(-) diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index 05560f5900..85e7dbd6b8 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -70,7 +70,7 @@ public void saveDatabase(RecipeList recipeList) throws IOException { public RecipeList defaultRecipeList() { RecipeList defaultRecipeList = new RecipeList(); - defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap() { + defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap<>() { { put("Chicken", 1); put("Rice", 1); @@ -79,7 +79,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap() { + defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap<>() { { put("Ripe mixed-colour cherry tomatoes ", 250); put("Flat-leaf parsley", 15); @@ -92,7 +92,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap() { + defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap<>() { { put("Chicken breast fillets", 2); put("Mushrooms", 250); @@ -104,7 +104,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Seafood paella", new HashMap() { + defaultRecipeList.add(new Recipe("Seafood paella", new HashMap<>() { { put("Prawns", 500); put("Mussels", 500); @@ -119,7 +119,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Avocado toast", new HashMap() { + defaultRecipeList.add(new Recipe("Avocado toast", new HashMap<>() { { put("Avocado", 1); put("Bread", 2); @@ -129,7 +129,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap() { + defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap<>() { { put("Italian sausage", 1); put("Onion", 1); @@ -147,7 +147,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap() { + defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap<>() { { put("Chicken breast fillets", 2); put("Mushrooms", 250); @@ -160,7 +160,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap() { + defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap<>() { { put("Pasta", 1); put("Hummus", 1); @@ -171,7 +171,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap() { + defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap<>() { { put("Ground beef", 1); put("Potato", 1); @@ -184,7 +184,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap() { + defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap<>() { { put("Chicken breast fillets", 2); put("Macaroni", 1); diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 9e3523e793..23bd4b6865 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -49,9 +49,9 @@ public static void receiveInput(String input) { ui.printMessage(deletedRecipe); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = String.format( + String errorMessage = "Please enter a valid recipe number or name. You did not enter a recipe number or " - + "name."); + + "name."; ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( @@ -79,7 +79,7 @@ public static void receiveInput(String input) { ui.printMessage("I've added this new recipe:" + newRecipe.getName()); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = String.format("Please enter a valid recipe name."); + String errorMessage = "Please enter a valid recipe name."; ui.printMessage(errorMessage); } ui.printSeparator(); @@ -95,7 +95,7 @@ public static void receiveInput(String input) { command[1]); ui.printMessage(errorMessage); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = String.format("Please enter a valid recipe name."); + String errorMessage = "Please enter a valid recipe name."; ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 75e4c8e1e7..7c909fd8c0 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -269,7 +269,8 @@ private WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList reci } } - private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) { + private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidNegativeValueException, InvalidRecipeNameException { WeeklyPlan recipesToAdd = new WeeklyPlan(); ArrayList quantities = new ArrayList<>(); ArrayList recipeNames = new ArrayList<>(); @@ -282,7 +283,12 @@ private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) startIndices.add(i); } else if (command[i].equals("/q")) { endIndices.add(i); - quantities.add(Integer.parseInt(command[i + 1])); + int quantity = Integer.parseInt(command[i + 1]); + if (quantity < 1) { + throw new InvalidNegativeValueException( + "Please enter a positive number for the quantity."); + } + quantities.add(quantity); } } @@ -299,12 +305,18 @@ private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) } // Add each recipe to the weekly plan - for (int i = 0; i < recipeNames.size(); i++) { - if (recipes.findByName(recipeNames.get(i)) != null) { - recipesToAdd.put(recipeNames.get(i), quantities.get(i)); - } else { - throw new IllegalArgumentException("Please indicate a valid recipe name."); + try { + for (int i = 0; i < recipeNames.size(); i++) { + if (recipes.findByName(recipeNames.get(i)) != null) { + recipesToAdd.put(recipeNames.get(i), quantities.get(i)); + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } } + } catch (NumberFormatException error) { + throw new NumberFormatException("Please enter a positive number for the quantity."); + } catch (InvalidRecipeNameException error) { + throw error; } return recipesToAdd; @@ -334,6 +346,10 @@ private WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recip } } + if (startIndices.size() == 0) { + throw new IllegalArgumentException("Please use /r to indicate the recipe to be deleted."); + } + // Building the recipe names for (int i = 0; i < startIndices.size(); i++) { int nameStartIndex = startIndices.get(i) + 1; diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 74e606c301..19decf818d 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayOutputStream; @@ -135,48 +136,70 @@ public void testAddWeeklyPlan() throws InvalidRecipeNameException, InvalidNegati assertTrue(weeklyPlan.containsKey("pizza")); assertEquals(3, (int) weeklyPlan.get("pizza")); - // Testing exceptions - try { - parser.parseWeeklyPlan(new String[]{"weekly", "burger", "1"}, recipes); - } catch (IllegalArgumentException e) { - assertTrue(true); - } + // Testing throwing of exceptions + assertThrows(IllegalArgumentException.class, + () -> parser.parseWeeklyPlan(new String[]{"weekly", "burger", "1"}, recipes)); - try { - parser.parseWeeklyPlan(new String[]{"weekly", "burger"}, recipes); - } catch (IllegalArgumentException e) { - assertTrue(true); - } + assertThrows(IllegalArgumentException.class, + () -> parser.parseWeeklyPlan(new String[]{"weekly", "burger"}, recipes)); - try { - parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger"}, recipes); - } catch (NumberFormatException e) { - assertTrue(true); - } + assertThrows(NumberFormatException.class, + () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger"}, recipes)); - try { - parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "a"}, recipes); - } catch (NumberFormatException e) { - assertTrue(true); - } + assertThrows(NumberFormatException.class, + () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "a"}, recipes)); - try { - parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "0"}, recipes); - } catch (InvalidNegativeValueException e) { - assertTrue(true); - } + assertThrows(InvalidNegativeValueException.class, + () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "0"}, recipes)); - try { - parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "-9"}, recipes); - } catch (InvalidNegativeValueException e) { - assertTrue(true); - } + assertThrows(InvalidNegativeValueException.class, + () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "-9"}, recipes)); - try { - parser.parseWeeklyPlan(new String[]{"weekly", "/add", "unknown", "1"}, recipes); - } catch (InvalidRecipeNameException e) { - assertTrue(true); - } + assertThrows(InvalidRecipeNameException.class, + () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "unknown", "1"}, recipes)); + + // TODO: Check error messages + } + + @Test + public void testAddMultiWeeklyPlan() throws InvalidRecipeNameException, InvalidNegativeValueException { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + + // Testing add recipe to weekly plan + WeeklyPlan recipeMap = parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "pizza", "/q", "5"}, + recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(1, (int) weeklyPlan.get("burger")); + assertTrue(weeklyPlan.containsKey("pizza")); + assertEquals(5, (int) weeklyPlan.get("pizza")); + assertFalse(weeklyPlan.containsKey("salad")); + + // Testing exceptions + assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "1", "/r", "pizza", "/q", "5"}, + recipes)); + + assertThrows(InvalidNegativeValueException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "0", "/r", "pizza", "/q", "5"}, + recipes)); + + assertThrows(InvalidNegativeValueException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "-1", "/r", "pizza", "/q", "5"}, + recipes)); + + assertThrows(NumberFormatException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "one", "/r", "pizza", "/q", "5"}, + recipes)); + + assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "1", "/r", "salad", "/r", "pizza"}, + recipes)); + + assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "1", "/r", "salad", "/q", "/q"}, + recipes)); } @Test @@ -191,11 +214,7 @@ public void testDeleteWeeklyPlan() { // Testing negative case toDelete.put("burger", 0); - try { - weeklyPlan.deletePlans(toDelete); - } catch (IllegalArgumentException e) { - assertTrue(true); - } + assertThrows(IllegalArgumentException.class, () -> weeklyPlan.deletePlans(toDelete)); // Testing positive case int newWeeklyPlanSize = weeklyPlan.size(); @@ -207,6 +226,34 @@ public void testDeleteWeeklyPlan() { assertEquals(oldWeeklyPlanSize - 1, newWeeklyPlanSize); } + @Test + public void testDeleteMultiWeeklyPlan() throws InvalidRecipeNameException, InvalidNegativeValueException { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + weeklyPlan.put("salad", 1); + weeklyPlan.put("pizza", 3); + weeklyPlan.put("burger", 100); + + // Testing delete recipe from weekly plan + WeeklyPlan recipeMap = parser.parseWeeklyPlan( + new String[]{"weekly", "/multidelete", "/r", "burger", "/r", "pizza"}, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(1, weeklyPlan.size()); + + // Testing exceptions + weeklyPlan.put("pizza", 3); + weeklyPlan.put("burger", 100); + assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multidelete", "/r", "burgers", "/r", "pizza"}, recipes)); + + assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multidelete", "burger", "pizza", "salad"}, + recipes)); + + assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( + new String[]{"weekly", "/multidelete", "/r", "burger", "/q", "1", "/r", "pizza"}, + recipes)); + } + @Test public void testViewEmptyWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); @@ -229,26 +276,26 @@ public void testListRecipe() { RecipeList recipeListToPrint; String[] inputs; - inputs = new String[] {"list"}; + inputs = new String[]{"list"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(3, recipeListToPrint.size()); assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); assertEquals(4, recipeListToPrint.get(1).getNumOfIngredients()); assertEquals(3, recipeListToPrint.get(2).getNumOfIngredients()); - inputs = new String[] {"list", "tomato", "sauce"}; + inputs = new String[]{"list", "tomato", "sauce"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(1, recipeListToPrint.size()); assertEquals(4, recipeListToPrint.get(0).getNumOfIngredients()); assertEquals("pizza", recipeListToPrint.get(0).getName()); - inputs = new String[] {"list", "salad", "&", "tomato"}; + inputs = new String[]{"list", "salad", "&", "tomato"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(1, recipeListToPrint.size()); assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); assertEquals("salad", recipeListToPrint.get(0).getName()); - inputs = new String[] {"list", "salad", "&", "pizza"}; + inputs = new String[]{"list", "salad", "&", "pizza"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(0, recipeListToPrint.size()); } From 6de9bdc6fd9c8812027503357a9a2ce75aec063f Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Thu, 23 Mar 2023 10:21:03 +0800 Subject: [PATCH 090/252] no message --- src/main/java/seedu/meal360/Meal360.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 5660939da7..be78e21758 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -135,6 +135,8 @@ public static void exitApp() { public static void main(String[] args) { + assert false : "dummy assertion set to fail"; + startApp(); String line; Scanner userInput = new Scanner(System.in); From c3bce1b1ea4e4fd4a00e9ed81c51800e26fd4977 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Thu, 23 Mar 2023 11:52:31 +0800 Subject: [PATCH 091/252] changed arraylist implementation of IngredientList to hashmap, created new Exceptions class, added date time format checker for parser, added unit member to Ingredient class (yet to be used) --- src/main/java/seedu/meal360/Exceptions.java | 12 +++ src/main/java/seedu/meal360/Ingredient.java | 4 +- .../java/seedu/meal360/IngredientList.java | 84 ++++++++++--------- src/main/java/seedu/meal360/Parser.java | 16 ++-- 4 files changed, 69 insertions(+), 47 deletions(-) create mode 100644 src/main/java/seedu/meal360/Exceptions.java diff --git a/src/main/java/seedu/meal360/Exceptions.java b/src/main/java/seedu/meal360/Exceptions.java new file mode 100644 index 0000000000..2c96cbcd2d --- /dev/null +++ b/src/main/java/seedu/meal360/Exceptions.java @@ -0,0 +1,12 @@ +package seedu.meal360; + +public class Exceptions { + + // ingredient not found exception + public static class IngredientNotFoundException extends Exception { + public IngredientNotFoundException() { + super("Ingredient not found"); + } + } + +} diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java index cab254a5c1..bead660e93 100644 --- a/src/main/java/seedu/meal360/Ingredient.java +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -8,10 +8,12 @@ public class Ingredient { public Integer ingredientCount; public LocalDate expiryDate; public Boolean expired; + private String unit; - public Ingredient(String ingredientName, Integer ingredientCount, String expiryDate) { + public Ingredient(String ingredientName, Integer ingredientCount, String unit, String expiryDate) { this.ingredientName = ingredientName; this.ingredientCount = ingredientCount; + this.unit = unit; // parse expiry date using parseDate method this.expiryDate = parser.parseDate(expiryDate); this.updateExpired(); diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index a578c5bab0..5929999708 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -1,28 +1,19 @@ package seedu.meal360; -import java.util.ArrayList; +import java.util.HashMap; import java.time.LocalDate; -public class IngredientList extends ArrayList { +public class IngredientList extends HashMap { private static final Parser parser = new Parser(); - // private exception for ingredient not found - private class IngredientNotFoundException extends Exception { - public IngredientNotFoundException() { - System.out.println("Ingredient not found"); - } - } - // public method to find count of ingredient - public Integer findCount(String ingredientName) { + public Integer findIngredientCount(String ingredientName) { try { - for (Ingredient ingredient : this) { - if (ingredient.ingredientName.equalsIgnoreCase(ingredientName)) { - return ingredient.ingredientCount; - } + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).ingredientCount; } - throw new IngredientNotFoundException(); - } catch (IngredientNotFoundException e) { + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { return null; } } @@ -30,43 +21,56 @@ public Integer findCount(String ingredientName) { // public method to find expiry date of ingredient public LocalDate findExpiryDate(String ingredientName) { try { - for (Ingredient ingredient : this) { - if (ingredient.ingredientName.equalsIgnoreCase(ingredientName)) { - return ingredient.expiryDate; - } + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).expiryDate; } - throw new IngredientNotFoundException(); - } catch (IngredientNotFoundException e) { + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { return null; } } public void addIngredient(Ingredient ingredient) { - super.add(ingredient); + super.put(ingredient.ingredientName, ingredient); } public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) { - ingredient.ingredientCount = ingredientCount; - ingredient.expiryDate = parser.parseDate(expiryDate); + try { + if (this.containsKey(ingredient.ingredientName)) { + ingredient.ingredientCount = ingredientCount; + ingredient.expiryDate = parser.parseDate(expiryDate); + ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); + super.put(ingredient.ingredientName, ingredient); + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + System.out.println("Ingredient not found"); + } } - public void deleteIngredient(int ingredientNum) { - Ingredient ingredientToDelete = super.get(ingredientNum); - super.remove(ingredientToDelete); + public void deleteIngredient(String ingredient) { + try { + if (this.containsKey(ingredient)) { + this.remove(ingredient); + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + System.out.println("Ingredient not found"); + } } // private indexed list of ingredients, count and expiry date private String listIngredients() { String ingredientList = ""; - for (int i = 0; i < this.size(); i++) { - ingredientList += (i + 1) + ". " + this.get(i).ingredientName + " (" - + this.get(i).ingredientCount + " left, expires on " - + this.get(i).expiryDate + ")\n"; + int index = 1; + for (Ingredient ingredient : this.values()) { + ingredientList += String.format("%d. %s (count: %d, expires on %s)", index, + ingredient.ingredientName, ingredient.ingredientCount, ingredient.expiryDate); } return ingredientList; } - // public method to print ingredients in list + // public method to print ingredients in list with indexing public void printIngredients() { System.out.println(listIngredients()); } @@ -75,10 +79,11 @@ public void printIngredients() { // if no expired ingredients, print "No expired ingredients" public void printExpiredIngredients() { String expiredIngredients = ""; - for (Ingredient ingredient : this) { + int index = 1; + for (Ingredient ingredient : this.values()) { if (ingredient.expired) { - expiredIngredients += ingredient.ingredientName + " (expires on " - + ingredient.expiryDate + ")\n"; + expiredIngredients += String.format("%d. %s (expires on %s)", index, + ingredient.ingredientName, ingredient.expiryDate); } } if (expiredIngredients.equals("")) { @@ -95,11 +100,10 @@ public void clearIngredients() { // public method to clear expired ingredients public void clearExpiredIngredients() { - for (int i = 0; i < this.size(); i++) { - if (this.get(i).expired) { - this.remove(i); + for (Ingredient ingredient : this.values()) { + if (ingredient.expired) { + this.remove(ingredient.ingredientName); } } } - } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 444f3bedec..f11633f9d1 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -2,11 +2,14 @@ import java.util.HashMap; import java.util.Scanner; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.time.LocalDate; public class Parser { Ui ui = new Ui(); + Exceptions exceptions = new Exceptions(); public String combineWords(String[] input, int startIndex) { StringBuilder word = new StringBuilder(input[startIndex]); @@ -227,13 +230,14 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { } } - // parser to read dd/mm/yyyy format as local date + // parser to read dd/mm/yyyy format as local date catching invalid date format public LocalDate parseDate(String input) { - String[] date = input.split("/"); - int day = Integer.parseInt(date[0]); - int month = Integer.parseInt(date[1]); - int year = Integer.parseInt(date[2]); - return LocalDate.of(year, month, day); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + try { + return LocalDate.parse(input, formatter); + } catch (DateTimeParseException e) { + throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy"); + } } public RecipeList parseLoadDatabase(String input) { From 5ca6b91ea16abbd7d11bf1498e751b163931c7de Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 23 Mar 2023 15:05:18 +0800 Subject: [PATCH 092/252] Update DeveloperGuide --- docs/DeveloperGuide.md | 126 ++++++++++++++++-- .../WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp | 1 + .../UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp | Bin 0 -> 29544 bytes docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio | 1 + docs/UML/WeeklyPlan/AddWeeklyPlanUML.png | Bin 0 -> 26817 bytes 5 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp create mode 100644 docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp create mode 100644 docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio create mode 100644 docs/UML/WeeklyPlan/AddWeeklyPlanUML.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 64e1f0ed2b..d41fc2acb9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,38 +1,144 @@ # Developer Guide +* [Acknowledgements](#acknowledgements) +* [Setting up, getting started](#setting-up-getting-started) +* [Design & implementation](#design--implementation) + * [Architecture](#architecture) + * [UI Component](#ui-component) + * [Parser Component](#parser-component) + * [Recipe Component](#recipe-component) + * [RecipeList Component](#recipelist-component) + * [WeeklyPlan Component](#weeklyplan-component) + * [Database Component](#database-component) + +* [Appendix: Requirements](#appendix-requirements) + * [Product scope](#product-scope) + * [Target user profile](#target-user-profile) + * [Value proposition](#value-proposition) + * [User Stories](#user-stories) + * [Non-Functional Requirements](#non-functional-requirements) + * [Glossary](#glossary) + +--- + ## Acknowledgements -{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} +{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- +include links to the original source as well} + +--- + +## Setting up, getting started + +--- ## Design & implementation -{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +* [Architecture](#architecture) +* [UI Component](#ui-component) +* [Parser Component](#parser-component) +* [Recipe Component](#recipe-component) +* [RecipeList Component](#recipelist-component) +* [WeeklyPlan Component](#weeklyplan-component) +* [Database Component](#database-component) + +### Architecture + +### UI Component + +### Parser Component + +### Recipe Component + +### RecipeList Component + +API: `RecipeList.java` +The `RecipeList` component: + +* extends from `ArrayList` +* stores the recipes the user has added as `Recipe` objects +* allows users to add their own recipes +* allows users to delete the existing recipes +* allows users to edit the existing recipes +* allows users to view the entire list of recipes +* allows users to view the ingredients required for a recipe +* allows users to tag single or multiple recipes from the recipe list for filtering + +### WeeklyPlan Component + +API: `WeeklyPlan.java` + +The `WeeklyPlan` component: + +* extends from `HashMap` +* stores the names of recipes that the user plans to prepare for the week as `String` +* stores the number of times the user plans to prepare each recipe as `Integer` +* allows users to add single or multiple recipes from the weekly plan +* allows users to delete single or multiple recipes from the weekly plan + +How the `WeeklyPlan` component works: + +1. When the user enters an input with the first word being `weekly`, the input is passed to + the `Parser` component. +2. Based on the second argument, the `Parser` component will call the appropriate method in the + `Parser` component. +3. `Parser` component then returns a `WeeklyPlan` object to indicate the recipe(s) to be added or + deleted from the weekly plan. +4. `WeeklyPlan` component then uses either `addPlans` or `deletePlans` method to add or delete + the recipe(s) from the weekly plan. + +The sequence diagram below shows how the `WeeklyPlan` component works when the user +inputs `weekly /add burger 1`: +![](//docs/UML/WeeklyPlan/AddWeeklyPlanUML.png) + +### Database Component + +API: `Database.java` + +The `Database` component: + +* stores the recipes in a local database in json format +* loads up automatically upon startup of program +* saves automatically upon exit of program +* comes with a default database of 10 recipes for new users + + +--- + +## Appendix: Requirements +### Product scope -## Product scope ### Target user profile -{Describe the target user profile} +* has a need to manage a significant number of recipes +* has a need to manage a significant number of ingredients +* has a need to manage their meal plan on a weekly basis +* can type fast +* prefers typing to mouse input +* is reasonably comfortable using CLI apps ### Value proposition -{Describe the value proposition: what problem does it solve?} +Allows management of recipes, ingredients and weekly meal plan faster than a typical mosue/GUI +driven app. -## User Stories +### User Stories |Version| As a ... | I want to ... | So that I can ...| |--------|----------|---------------|------------------| |v1.0|new user|see usage instructions|refer to them when I forget how to use the application| |v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| -## Non-Functional Requirements +### Non-Functional Requirements {Give non-functional requirements} -## Glossary +### Glossary * *glossary item* - Definition -## Instructions for manual testing +### 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} +{Give instructions on how to do a manual product testing e.g., how to load sample data to be used +for testing} diff --git a/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp b/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp new file mode 100644 index 0000000000..2db87a437c --- /dev/null +++ b/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp @@ -0,0 +1 @@ +ddHNEoIgEADgp+Gu0Fid7e/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp b/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..88175f2772c0570e1cf33355edc8698c30bcbe52 GIT binary patch literal 29544 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 A)&Kwi literal 0 HcmV?d00001 diff --git a/docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio b/docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio new file mode 100644 index 0000000000..ed707033b3 --- /dev/null +++ b/docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio @@ -0,0 +1 @@ +7VrLcqM4FP0aV/UsmpIQ4rEMcTxdU+maVGfRPUsZZJsKthjAHTtfP1cgngLbie30o8YLB10hAeeecx84E3K73v2ZsmT1WYQ8npgo3E3IdGKa2CQU/kjLvrQ4FioNyzQKS1PL8Bi9cLWysm6jkGfKVppyIeI8SrrGQGw2PMg7Npam4rl72kLEYceQsCXXDI8Bi3Xr1yjMV8qKba+Z+MSj5Upd2jWdcmLNqpPVk2QrFornloncTchtKkReHq13tzyW4HVxmY3M1jeW8k1+ygL/yz1dP/39uNr99fLwcv/JfxH3HytvfGfxVj2xutt8X0GwTMU2UafxNOe7IeDZvDod6TeG68cFnnCx5nm6h1OqjTy7XLKvXK+wfW4Ad03Fo1ULa2I7BlFrmfLzst6+gQIOFBqvQIbg48is8jXsOcUT4i+iOL4VsUiLGbJwAx4EYM/yVDzx1szcpRZFMDOKaBu5A04bxZMgrOFHTWsQvyuBh0+g1Th4IePuYhA8O3D5fHFN8CpBtLAzbfzO3MND3LNjuLQ/h4OlPHhgacbTygyXqWc0pAEjaW8BzuJouYHjALCCTYgvkYwg6t2oiXUUhnK5n/IselHilqxNRLTJi+el/oRO5V7bXGRl3MaazzZiw3sOVqbredCmBkWWDZEIUw9TsxtcTAMhZDq27XiuhT1EdK0MhBrzamHGPO7qr5w/xfuHmG3+d7eePUzXoD0X6+ljIPpdzaXY0l1Kbiq99pwFVUEiD7fr+D5a8Dgq0Ep4GsHNSF9NY2V+aGz+8yrK+WPCArn0GSqvrr8hJ+cMlqT1OI5ZkkWNX1MebNMs+s6/cOVMaRXbXF7ptq6lkB6cZzPTp/ZVBQwarUKucqlFDEpR89ETHKbIoO6Alz3PsOi1xDvo6bZcf3VvmzPfm90p+6N6EBkCrkkAjxpQBDYf61fgArZfVfLogbXNApHmK7EUGxa3efD+SnQAsG5sxcRwvBb6eqzF1EC2Dr5HjLovuzT2FdS/FfYeNqripALfsgB8HXCko12VsZeHmmhQJzKz3YTQvG+WMW+i3weoUNhaBqt/t7LJ9Z+LqYnsEGcsDOFgvk2XMilKEXfP/UNzIA+hMVfDxkd3jbUuc2K+kFtkEDHhlu6L0RSg9vkmvJHvBGA4j0XwJEOj2G5CHqroBx5L998UTYrBP2omZnMe+yx4WhYretVNi1zliSINeTpYAsnH6BAlZ4DBIaJUZD6XUchAFu6WSipIpjxmOaSHzn0NUUft/SAF1KYq1agKVVlF1WqjTGzTgKu1DQ3BI2zfOk2pc/RqFBLA+NVmr1jVyKlRRHk3vT2qWxOLRcbzSV9DNdRnVBJ6wwxJO0r4Z5YcCmWjhfxxqh+V02HK98Q2Qu5zOfsRSEvMXg6ytBDooosQmSI95rpAEtdrPr2uYYTUAxqxtK2hHCG9NzBlMLiARtCJDzKuF30HuN/xHX6cdqqY1k9J3Ux0Wg4azT4HNDcXeS7Wp2iu2yyHfMG2RTt/WGl8F+VFTjIQttW4SEuGLI3L8XRXyVoO9q1Bq4iZorOFCpgUhD8UyuhRRSPkXkvCJrINZLZI6nQ5jC3QXKt+JW+Us6yMEXGo6eHie+AqJsWO5cpv2nuMEZW/a8LR67g3JZwh8ouEw5QfsmxVUL8spqofd1xNFofpPyaaplYzShnU5ZphQZenDI0witG+Pbq0NI5WcidIg1j4MjWZq8VvEzlavjmZ7+ik7X4GYuvZ4BCfL9AL1u9IJtfqBbFt9uLLW7twWHq9Nrxiw28FvdOF3rT06vNdG3DiaiBDHSOrnOxDHcHf0j0P/F7w/o30WLAfCc3HI65zGRrI6HeZZhk73Yqk/sH8wm0yhOfB6/zwcp14r4oSP0/BcV55cIhaqMLkXG5Vb72Vz4lJT+JWs9HYwqsmdhg2/wZTnt78MxG5+w8= \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/AddWeeklyPlanUML.png b/docs/UML/WeeklyPlan/AddWeeklyPlanUML.png new file mode 100644 index 0000000000000000000000000000000000000000..bfb44090988d5ca63078f6b8d43246392c44c4d7 GIT binary patch literal 26817 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 literal 0 HcmV?d00001 From 4465d2e831fabc6bb1532972dff59de9287025ca Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 23 Mar 2023 16:21:42 +0800 Subject: [PATCH 093/252] Update Developer Guide Include guide for database portion. Also fix UML diagram not showing up on github --- docs/DeveloperGuide.md | 15 ++++++++++++++- .../Database/.$AddWeeklyPlanUML.drawio.bkp | 1 + docs/UML/Database/.$AddWeeklyPlanUML.png.bkp | Bin 0 -> 29544 bytes .../Database/.$DatabaseStartupUML.drawio.bkp | 1 + .../Database/.$DatabaseStartupUML.drawio.dtmp | 1 + docs/UML/Database/DatabaseStartupUML.drawio | 1 + docs/UML/Database/DatabaseStartupUML.png | Bin 0 -> 51768 bytes .../WeeklyPlan/.$AddWeeklyPlanUML.drawio.dtmp | 1 + docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio | 2 +- docs/UML/WeeklyPlan/AddWeeklyPlanUML.png | Bin 26817 -> 29420 bytes 10 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 docs/UML/Database/.$AddWeeklyPlanUML.drawio.bkp create mode 100644 docs/UML/Database/.$AddWeeklyPlanUML.png.bkp create mode 100644 docs/UML/Database/.$DatabaseStartupUML.drawio.bkp create mode 100644 docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp create mode 100644 docs/UML/Database/DatabaseStartupUML.drawio create mode 100644 docs/UML/Database/DatabaseStartupUML.png create mode 100644 docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.dtmp diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index d41fc2acb9..b4e163944b 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -89,7 +89,7 @@ How the `WeeklyPlan` component works: The sequence diagram below shows how the `WeeklyPlan` component works when the user inputs `weekly /add burger 1`: -![](//docs/UML/WeeklyPlan/AddWeeklyPlanUML.png) +![](../docs/UML/WeeklyPlan/AddWeeklyPlanUML.png) ### Database Component @@ -102,7 +102,20 @@ The `Database` component: * saves automatically upon exit of program * comes with a default database of 10 recipes for new users +How the `Database` component works at start up: +1. Upon starting up the program, the `Database` component will check for the existence of a + database file in the local directory. +2. If the database file exists, the `Database` component will load the recipes from the database + file into a `RecipeList` and return this `RecipeList`. +3. If the database file does not exist, the `Database` component will check if the parent directory, + and create any missing directories and files as necessary. +4. If the database file does not exist or if the file was empty, the `Database` component will + create a new `RecipeList` + with 10 default recipes and return this `RecipeList`. + +The activity diagram below shows how the `Database` component works at start up: +![](../docs/UML/Database/DatabaseStartupUML.png) --- ## Appendix: Requirements diff --git a/docs/UML/Database/.$AddWeeklyPlanUML.drawio.bkp b/docs/UML/Database/.$AddWeeklyPlanUML.drawio.bkp new file mode 100644 index 0000000000..2db87a437c --- /dev/null +++ b/docs/UML/Database/.$AddWeeklyPlanUML.drawio.bkp @@ -0,0 +1 @@ +ddHNEoIgEADgp+Gu0Fid7e/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file diff --git a/docs/UML/Database/.$AddWeeklyPlanUML.png.bkp b/docs/UML/Database/.$AddWeeklyPlanUML.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..88175f2772c0570e1cf33355edc8698c30bcbe52 GIT binary patch literal 29544 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 A)&Kwi literal 0 HcmV?d00001 diff --git a/docs/UML/Database/.$DatabaseStartupUML.drawio.bkp b/docs/UML/Database/.$DatabaseStartupUML.drawio.bkp new file mode 100644 index 0000000000..ed707033b3 --- /dev/null +++ b/docs/UML/Database/.$DatabaseStartupUML.drawio.bkp @@ -0,0 +1 @@ +7VrLcqM4FP0aV/UsmpIQ4rEMcTxdU+maVGfRPUsZZJsKthjAHTtfP1cgngLbie30o8YLB10hAeeecx84E3K73v2ZsmT1WYQ8npgo3E3IdGKa2CQU/kjLvrQ4FioNyzQKS1PL8Bi9cLWysm6jkGfKVppyIeI8SrrGQGw2PMg7Npam4rl72kLEYceQsCXXDI8Bi3Xr1yjMV8qKba+Z+MSj5Upd2jWdcmLNqpPVk2QrFornloncTchtKkReHq13tzyW4HVxmY3M1jeW8k1+ygL/yz1dP/39uNr99fLwcv/JfxH3HytvfGfxVj2xutt8X0GwTMU2UafxNOe7IeDZvDod6TeG68cFnnCx5nm6h1OqjTy7XLKvXK+wfW4Ad03Fo1ULa2I7BlFrmfLzst6+gQIOFBqvQIbg48is8jXsOcUT4i+iOL4VsUiLGbJwAx4EYM/yVDzx1szcpRZFMDOKaBu5A04bxZMgrOFHTWsQvyuBh0+g1Th4IePuYhA8O3D5fHFN8CpBtLAzbfzO3MND3LNjuLQ/h4OlPHhgacbTygyXqWc0pAEjaW8BzuJouYHjALCCTYgvkYwg6t2oiXUUhnK5n/IselHilqxNRLTJi+el/oRO5V7bXGRl3MaazzZiw3sOVqbredCmBkWWDZEIUw9TsxtcTAMhZDq27XiuhT1EdK0MhBrzamHGPO7qr5w/xfuHmG3+d7eePUzXoD0X6+ljIPpdzaXY0l1Kbiq99pwFVUEiD7fr+D5a8Dgq0Ep4GsHNSF9NY2V+aGz+8yrK+WPCArn0GSqvrr8hJ+cMlqT1OI5ZkkWNX1MebNMs+s6/cOVMaRXbXF7ptq6lkB6cZzPTp/ZVBQwarUKucqlFDEpR89ETHKbIoO6Alz3PsOi1xDvo6bZcf3VvmzPfm90p+6N6EBkCrkkAjxpQBDYf61fgArZfVfLogbXNApHmK7EUGxa3efD+SnQAsG5sxcRwvBb6eqzF1EC2Dr5HjLovuzT2FdS/FfYeNqripALfsgB8HXCko12VsZeHmmhQJzKz3YTQvG+WMW+i3weoUNhaBqt/t7LJ9Z+LqYnsEGcsDOFgvk2XMilKEXfP/UNzIA+hMVfDxkd3jbUuc2K+kFtkEDHhlu6L0RSg9vkmvJHvBGA4j0XwJEOj2G5CHqroBx5L998UTYrBP2omZnMe+yx4WhYretVNi1zliSINeTpYAsnH6BAlZ4DBIaJUZD6XUchAFu6WSipIpjxmOaSHzn0NUUft/SAF1KYq1agKVVlF1WqjTGzTgKu1DQ3BI2zfOk2pc/RqFBLA+NVmr1jVyKlRRHk3vT2qWxOLRcbzSV9DNdRnVBJ6wwxJO0r4Z5YcCmWjhfxxqh+V02HK98Q2Qu5zOfsRSEvMXg6ytBDooosQmSI95rpAEtdrPr2uYYTUAxqxtK2hHCG9NzBlMLiARtCJDzKuF30HuN/xHX6cdqqY1k9J3Ux0Wg4azT4HNDcXeS7Wp2iu2yyHfMG2RTt/WGl8F+VFTjIQttW4SEuGLI3L8XRXyVoO9q1Bq4iZorOFCpgUhD8UyuhRRSPkXkvCJrINZLZI6nQ5jC3QXKt+JW+Us6yMEXGo6eHie+AqJsWO5cpv2nuMEZW/a8LR67g3JZwh8ouEw5QfsmxVUL8spqofd1xNFofpPyaaplYzShnU5ZphQZenDI0witG+Pbq0NI5WcidIg1j4MjWZq8VvEzlavjmZ7+ik7X4GYuvZ4BCfL9AL1u9IJtfqBbFt9uLLW7twWHq9Nrxiw28FvdOF3rT06vNdG3DiaiBDHSOrnOxDHcHf0j0P/F7w/o30WLAfCc3HI65zGRrI6HeZZhk73Yqk/sH8wm0yhOfB6/zwcp14r4oSP0/BcV55cIhaqMLkXG5Vb72Vz4lJT+JWs9HYwqsmdhg2/wZTnt78MxG5+w8= \ No newline at end of file diff --git a/docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp b/docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp new file mode 100644 index 0000000000..03a697e1ec --- /dev/null +++ b/docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp @@ -0,0 +1 @@ +7Vvfc+IqFP5rfNxOCJCQx9b+2JndO7Mzfbjt0x1qULMbxUFs6/71FwyYIFFjq8ap9qVyQgj5zvkO5xxIB3ZH7w+CTob/8JTlnTBI3zvwthOGAAKo/mnJvJDEJCoEA5GlhSgoBY/ZX2butNJZlrKpkRUiyXkus4kr7PHxmPWkI6NC8De3W5/nqSOY0AHzBI89mvvSf7NUDo0UREl54TvLBkPzaBLGxYURtZ3Nm0yHNOVvFRG868Cu4FwWv0bvXZZr8Fxc7tdcXU5MsLFsdEPM58EkfHp8+PH637cfD/jl6fu3CBXDvNJ8Zt7YzFbOLQQDwWcT040Jyd7rgKcvtnvgTwwsX1fZCeMjJsVcdTEDJWYkYyEEF823Eu6EGFCHFaQjQIyajYoHy5FLFNQPA8QOoIB4OyhqGGWCqnEzlCM1+i1QP5WKJ/r6VFIhHyWV+no/y/Muz7lY3AiDxZ/uLAX/wypX7u/NlbVYO5iuV6ePtIEWhB60MPCRtbL9A0saAJsq/pkmF3LIB3xM87tSWgVcY5Qpsl7n2WCsZC9cSj5SF9g4vdbs14NM2LiQGO9C6sBfqkUZ+zhl+i2CxV3qvZ904yoIiBU8LwQIQiu4fa/2v51XW7+YyBR8TFjheyafzPz172IwbFrlSLphBypQ0tA49jDlM9FjmwCPdzIc5VupGLBNHUFSb2GC5VRmr+786gzI3PqLZ2pCSx8AEHGcQBi5IxTzMjetWOFyFp8wzMQzzO6Q9f7o+/p69aLKwVFFd7WCZLn+p9QzlZ7xlsajtfs2zCR7nNCFit7U+uga74pjSCkj/V6dbUY9wl76B3EMdhgceJ4BhDWuITqUa7AP2+QaxJCPXmbT7ci6HF7BmYEUs7gO5ySKIY0OiTMMsGPmse+QSQ3q5GCog304ZBfuss9PzidGI7+ZlHPjf+lM8pV1c603XuP4Gvuz7R4yaej4KjHbxxzf5xQVbnZQBhDlqTKhojG+mFq9j2rMnRPzURgihzsgat1nwXNnj4V7O3vCVtkT1bNnauljFvVMC9hoIudfhjUAuysOiFtnTZPs6sKa0m5bY01NtoZvDFVSzjRZxlwuFxp86+lRWbN0YacmU+spLHVK5KVwoyxNCw2zafbXlBW0WiY6+F+8I77Rz1JjKaVOC/36Gh3z8Wr2bUSHi+6S2OEaQT7VQE0lYzXZ2Z8G/bSm1OBCadOL1kIbAlqtAU9rMTqi0uB5ZEIwdFAPkb8uHTUVgmefClmL3roswVZTIWs4FUX95DTVUZzgo7pizVcJ5YhbKIfQr5QfN5SDZ58AwaahHGw1AYL+No/hTMr6dJZLhzZfhC8IQYcvGMZt8wVf+NKUL2t0eyS++AUDFb9WygNnHzWj0F2MQruBUyGX3SM/TthcU1bANyY/veis0FG0VWfxMfNTdBapTgzhCux+3HbUVAddUp2w4TKEWk11kB+2dQXTx0rqd3y+SOBGIreOBmHScuCGzj5wQ00DN9Rq4IZqA7dLfbqgB3T3gkIcebxCx4zZUG3MdtlaqHGJYbxVdckxVRf5VbjT8ojLk3ug45zaw50tZ/bM8bzySN6zHWTX43l79L6koff9dNpcfzwvjoOrBBCoYmUUJZC4h/UwWBnwwKf1kL8xuQyLvmrxNwZuEoFsu72Y6NSLv+XZ3d08wAnFUuQgbI5CchVgFQ4AHJMExW5UAG0lZQubr4Wg80o3s4hueOpKxcgc9L9v2N+Wc0ubLWawV9diz8Ee14Y/suZ8dH1rM4doesj803b/KceGm4Q2mz7/0J8a7PrxR79f+/3B/tcTu2YTv/Z31G9BMPFAbZdHFeo8O8w5OR7ZHfCtPCosuTUeJRt9qUmZ9qf0TvPvadY4zxNWeVPX2a7Ko5ryy2aWb4nH10P+4ex7Y5iN3TPmyM+yQZDgmig72R1S1Sy//iwCmPIbWnj3Pw== \ No newline at end of file diff --git a/docs/UML/Database/DatabaseStartupUML.drawio b/docs/UML/Database/DatabaseStartupUML.drawio new file mode 100644 index 0000000000..06b67de9a1 --- /dev/null +++ b/docs/UML/Database/DatabaseStartupUML.drawio @@ -0,0 +1 @@ +7Vvfc+IqFP5rfNxOCJCQx9b+2JndO7Mzfbjt0x1qULMbxUFs6/71FwyYIFFjq8ap9qVyQgj5zvkO5xxIB3ZH7w+CTob/8JTlnTBI3zvwthOGAAKo/mnJvJDEJCoEA5GlhSgoBY/ZX2butNJZlrKpkRUiyXkus4kr7PHxmPWkI6NC8De3W5/nqSOY0AHzBI89mvvSf7NUDo0UREl54TvLBkPzaBLGxYURtZ3Nm0yHNOVvFRG868Cu4FwWv0bvXZZr8Fxc7tdcXU5MsLFsdEPM58EkfHp8+PH637cfD/jl6fu3CBXDvNJ8Zt7YzFbOLQQDwWcT040Jyd7rgKcvtnvgTwwsX1fZCeMjJsVcdTEDJWYkYyEEF823Eu6EGFCHFaQjQIyajYoHy5FLFNQPA8QOoIB4OyhqGGWCqnEzlCM1+i1QP5WKJ/r6VFIhHyWV+no/y/Muz7lY3AiDxZ/uLAX/wypX7u/NlbVYO5iuV6ePtIEWhB60MPCRtbL9A0saAJsq/pkmF3LIB3xM87tSWgVcY5Qpsl7n2WCsZC9cSj5SF9g4vdbs14NM2LiQGO9C6sBfqkUZ+zhl+i2CxV3qvZ904yoIiBU8LwQIQiu4fa/2v51XW7+YyBR8TFjheyafzPz172IwbFrlSLphBypQ0tA49jDlM9FjmwCPdzIc5VupGLBNHUFSb2GC5VRmr+786gzI3PqLZ2pCSx8AEHGcQBi5IxTzMjetWOFyFp8wzMQzzO6Q9f7o+/p69aLKwVFFd7WCZLn+p9QzlZ7xlsajtfs2zCR7nNCFit7U+uga74pjSCkj/V6dbUY9wl76B3EMdhgceJ4BhDWuITqUa7AP2+QaxJCPXmbT7ci6HF7BmYEUs7gO5ySKIY0OiTMMsGPmse+QSQ3q5GCog304ZBfuss9PzidGI7+ZlHPjf+lM8pV1c603XuP4Gvuz7R4yaej4KjHbxxzf5xQVbnZQBhDlqTKhojG+mFq9j2rMnRPzURgihzsgat1nwXNnj4V7O3vCVtkT1bNnauljFvVMC9hoIudfhjUAuysOiFtnTZPs6sKa0m5bY01NtoZvDFVSzjRZxlwuFxp86+lRWbN0YacmU+spLHVK5KVwoyxNCw2zafbXlBW0WiY6+F+8I77Rz1JjKaVOC/36Gh3z8Wr2bUSHi+6S2OEaQT7VQE0lYzXZ2Z8G/bSm1OBCadOL1kIbAlqtAU9rMTqi0uB5ZEIwdFAPkb8uHTUVgmefClmL3roswVZTIWs4FUX95DTVUZzgo7pizVcJ5YhbKIfQr5QfN5SDZ58AwaahHGw1AYL+No/hTMr6dJZLhzZfhC8IQYcvGMZt8wVf+NKUL2t0eyS++AUDFb9WygNnHzWj0F2MQruBUyGX3SM/TthcU1bANyY/veis0FG0VWfxMfNTdBapTgzhCux+3HbUVAddUp2w4TKEWk11kB+2dQXTx0rqd3y+SOBGIreOBmHScuCGzj5wQ00DN9Rq4IZqA7dLfbqgB3T3gkIcebxCx4zZUG3MdtlaqHGJYbxVdckxVRf5VbjT8ojLk3ug45zaw50tZ/bM8bzySN6zHWTX43l79L6koff9dNpcfzwvjoOrBBCoYmUUJZC4h/UwWBnwwKf1kL8xuQyLvmrxNwZuEoFsu72Y6NSLv+XZ3d08wAnFUuQgbI5CchVgFQ4AHJMExW5UAG0lZQubr4Wg80o3s4hueOpKxcgc9L9v2N+Wc0ubLWawV9diz8Ee14Y/suZ8dH1rM4doesj803b/KceGm4Q2mz7/0J8a7PrxR79f+/3B/tcTu2YTv/Z31G9BMPFAbZdHFeo8O8w5OR7ZHfCtPCosuTUeJRt9qUmZ9qf0TvPvadY4zxNWeVPX2a7Ko5ryy2aWb4nH10P+4ex7Y5iN3TPmyM+yQZDgmig72R1S1Sy//iwCmPIbWnj3Pw== \ No newline at end of file diff --git a/docs/UML/Database/DatabaseStartupUML.png b/docs/UML/Database/DatabaseStartupUML.png new file mode 100644 index 0000000000000000000000000000000000000000..a19ded4600ea7f9e78b20b14cf6be62329483eef GIT binary patch literal 51768 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

-+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 X{kNZ2rkpqgf8=G9rC(h$di4JQl5*IP literal 0 HcmV?d00001 diff --git a/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.dtmp b/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.dtmp new file mode 100644 index 0000000000..624708bc23 --- /dev/null +++ b/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.dtmp @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio b/docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio index ed707033b3..ef8f47c11e 100644 --- a/docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio +++ b/docs/UML/WeeklyPlan/AddWeeklyPlanUML.drawio @@ -1 +1 @@ -7VrLcqM4FP0aV/UsmpIQ4rEMcTxdU+maVGfRPUsZZJsKthjAHTtfP1cgngLbie30o8YLB10hAeeecx84E3K73v2ZsmT1WYQ8npgo3E3IdGKa2CQU/kjLvrQ4FioNyzQKS1PL8Bi9cLWysm6jkGfKVppyIeI8SrrGQGw2PMg7Npam4rl72kLEYceQsCXXDI8Bi3Xr1yjMV8qKba+Z+MSj5Upd2jWdcmLNqpPVk2QrFornloncTchtKkReHq13tzyW4HVxmY3M1jeW8k1+ygL/yz1dP/39uNr99fLwcv/JfxH3HytvfGfxVj2xutt8X0GwTMU2UafxNOe7IeDZvDod6TeG68cFnnCx5nm6h1OqjTy7XLKvXK+wfW4Ad03Fo1ULa2I7BlFrmfLzst6+gQIOFBqvQIbg48is8jXsOcUT4i+iOL4VsUiLGbJwAx4EYM/yVDzx1szcpRZFMDOKaBu5A04bxZMgrOFHTWsQvyuBh0+g1Th4IePuYhA8O3D5fHFN8CpBtLAzbfzO3MND3LNjuLQ/h4OlPHhgacbTygyXqWc0pAEjaW8BzuJouYHjALCCTYgvkYwg6t2oiXUUhnK5n/IselHilqxNRLTJi+el/oRO5V7bXGRl3MaazzZiw3sOVqbredCmBkWWDZEIUw9TsxtcTAMhZDq27XiuhT1EdK0MhBrzamHGPO7qr5w/xfuHmG3+d7eePUzXoD0X6+ljIPpdzaXY0l1Kbiq99pwFVUEiD7fr+D5a8Dgq0Ep4GsHNSF9NY2V+aGz+8yrK+WPCArn0GSqvrr8hJ+cMlqT1OI5ZkkWNX1MebNMs+s6/cOVMaRXbXF7ptq6lkB6cZzPTp/ZVBQwarUKucqlFDEpR89ETHKbIoO6Alz3PsOi1xDvo6bZcf3VvmzPfm90p+6N6EBkCrkkAjxpQBDYf61fgArZfVfLogbXNApHmK7EUGxa3efD+SnQAsG5sxcRwvBb6eqzF1EC2Dr5HjLovuzT2FdS/FfYeNqripALfsgB8HXCko12VsZeHmmhQJzKz3YTQvG+WMW+i3weoUNhaBqt/t7LJ9Z+LqYnsEGcsDOFgvk2XMilKEXfP/UNzIA+hMVfDxkd3jbUuc2K+kFtkEDHhlu6L0RSg9vkmvJHvBGA4j0XwJEOj2G5CHqroBx5L998UTYrBP2omZnMe+yx4WhYretVNi1zliSINeTpYAsnH6BAlZ4DBIaJUZD6XUchAFu6WSipIpjxmOaSHzn0NUUft/SAF1KYq1agKVVlF1WqjTGzTgKu1DQ3BI2zfOk2pc/RqFBLA+NVmr1jVyKlRRHk3vT2qWxOLRcbzSV9DNdRnVBJ6wwxJO0r4Z5YcCmWjhfxxqh+V02HK98Q2Qu5zOfsRSEvMXg6ytBDooosQmSI95rpAEtdrPr2uYYTUAxqxtK2hHCG9NzBlMLiARtCJDzKuF30HuN/xHX6cdqqY1k9J3Ux0Wg4azT4HNDcXeS7Wp2iu2yyHfMG2RTt/WGl8F+VFTjIQttW4SEuGLI3L8XRXyVoO9q1Bq4iZorOFCpgUhD8UyuhRRSPkXkvCJrINZLZI6nQ5jC3QXKt+JW+Us6yMEXGo6eHie+AqJsWO5cpv2nuMEZW/a8LR67g3JZwh8ouEw5QfsmxVUL8spqofd1xNFofpPyaaplYzShnU5ZphQZenDI0witG+Pbq0NI5WcidIg1j4MjWZq8VvEzlavjmZ7+ik7X4GYuvZ4BCfL9AL1u9IJtfqBbFt9uLLW7twWHq9Nrxiw28FvdOF3rT06vNdG3DiaiBDHSOrnOxDHcHf0j0P/F7w/o30WLAfCc3HI65zGRrI6HeZZhk73Yqk/sH8wm0yhOfB6/zwcp14r4oSP0/BcV55cIhaqMLkXG5Vb72Vz4lJT+JWs9HYwqsmdhg2/wZTnt78MxG5+w8= \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/AddWeeklyPlanUML.png b/docs/UML/WeeklyPlan/AddWeeklyPlanUML.png index bfb44090988d5ca63078f6b8d43246392c44c4d7..fd7c954ee4b5f1fff65672e717f4dd0194c4b3a1 100644 GIT binary patch literal 29420 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 E04#9?xBvhE literal 26817 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 From 7832ed5c3599dc4089a9ac78b14c933112d2eef9 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 17:03:24 +0800 Subject: [PATCH 094/252] clear weekly plan & view weekly ingredients --- docs/UserGuide.md | 14 ++++++++++- src/main/java/seedu/meal360/Meal360.java | 7 ++++++ src/main/java/seedu/meal360/Parser.java | 3 ++- src/main/java/seedu/meal360/Ui.java | 17 +++++++++++++ src/main/java/seedu/meal360/WeeklyPlan.java | 5 ++++ src/test/java/seedu/meal360/Meal360Test.java | 25 ++++++++++++++++++++ 6 files changed, 69 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 17735c92ce..63cc49ff93 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -125,7 +125,13 @@ Format: `weekly /delete RECIPE NAME` Example of usage: -* `weekly /remove pizza` removes pizza from this week's plan. +* `weekly /delete pizza` removes pizza from this week's plan. + +### Clearing this week's plan: `weekly /clear` + +Clears this week's plan by removing all recipes listed in weekly plan. + +Format: `weekly /clear` ### View this week's plan: `weeklyplan` @@ -133,6 +139,12 @@ View this week's plan. Format: `weeklyplan` +### View this week's ingredients: `weeklyingredients` + +View this week's ingredients. + +Format: `weeklyingredients` + ### Exit the program: `bye` Exits the program. diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index da6b49bad7..442cb7a537 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -144,6 +144,9 @@ public static void receiveInput(String input) { } else if (command[1].equals("/delete")) { ui.printMessage("I've deleted the recipe from your weekly plan!"); weeklyPlan.deletePlan(recipeMap); + } else if (command[1].equals("/clear")) { + weeklyPlan.clearPlan(); + ui.printMessage("I've cleared your entire weekly plan!"); } } catch (NumberFormatException e) { String errorMessage = String.format("Please enter a valid number as the last argument."); @@ -155,6 +158,10 @@ public static void receiveInput(String input) { ui.printMessage(errorMessage); } ui.printSeparator(); + } else if (command[0].equals("weeklyingredients")) { + ui.printSeparator(); + ui.printWeeklyIngredients(weeklyPlan, recipeList); + ui.printSeparator(); } else if (command[0].equals("weeklyplan")) { ui.printSeparator(); ui.printWeeklyPlan(weeklyPlan); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index b13e27789e..8f324bf4db 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -118,6 +118,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } public String parseDeleteRecipe(String[] input, RecipeList recipeList) { + assert input[0].equals("delete"); // user inputted recipe name if (input[1].contains("r/")) { // skip over /r in recipe name @@ -268,7 +269,7 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { } public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) { - if (!command[1].equals("/add") && !command[1].equals("/delete")) { + if (!command[1].equals("/add") && !command[1].equals("/delete") && !command[1].equals("/clear")) { throw new IllegalArgumentException( "Please indicate if you would want to add or delete the recipe from your weekly " + "plan."); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 9528f83051..60236a4bd9 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -52,6 +52,23 @@ public void printWeeklyPlan(WeeklyPlan weeklyPlan) { } } + + public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) { + if (weeklyPlan.isEmpty()) { + printMessage("Your weekly plan is empty!"); + } else { + printMessage("Here are your weekly ingredients:"); + weeklyPlan.forEach((recipe, count) -> { + Recipe currRecipe = recipeList.findByName(recipe.toString().trim()); + for (String ingredient : currRecipe.getIngredients().keySet()) { + String outputMessage = String.format("%s (%d)", ingredient, + currRecipe.getIngredients().get(ingredient) * count); + System.out.println(formatMessage(outputMessage)); + } + }); + } + + } public void listRecipe(RecipeList recipeListToPrint) { int numberOfRecipes = recipeListToPrint.size(); diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index f64835ae62..544890c7fe 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -15,4 +15,9 @@ public void deletePlan(WeeklyPlan recipeMap) { this.remove(recipe); }); } + + public void clearPlan() { + this.clear(); + } + } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 43cdf5a8d9..ece0a8ab98 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -193,6 +193,31 @@ public void testDeleteWeeklyPlan() { assertEquals(oldWeeklyPlanSize - 1, newWeeklyPlanSize); } + @Test + public void testClearWeeklyPlan() { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + weeklyPlan.put("salad", 1); + weeklyPlan.put("pizza", 3); + + // Testing clearing weekly plan + weeklyPlan.clearPlan(); + assertEquals(weeklyPlan.size(), 0); + } + + @Test + public void testViewIngredients() { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + HashMap testIngredients = new HashMap<>(); + testIngredients.put("test ingredient", 100); + // create a fake recipe + Recipe testR = new Recipe("test recipe name", testIngredients); + recipes.addRecipe(testR); + ui.printWeeklyIngredients(weeklyPlan, recipes); + assertEquals( + ui.formatMessage("Here are your weekly ingredients:") + System.lineSeparator() + ui.formatMessage( + "test ingredient (100)"), outContent.toString().trim()); + } + @Test public void testViewEmptyWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); From ffb707e058f592e657b7020a9cef320e0e3b31ca Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 18:28:27 +0800 Subject: [PATCH 095/252] add testing for viewing ingredients --- src/test/java/seedu/meal360/Meal360Test.java | 9 ++++++++- text-ui-test/EXPECTED.TXT | 15 +++++++++++++-- text-ui-test/input.txt | 4 +++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index ece0a8ab98..0bd5881cdb 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -209,13 +209,20 @@ public void testViewIngredients() { WeeklyPlan weeklyPlan = new WeeklyPlan(); HashMap testIngredients = new HashMap<>(); testIngredients.put("test ingredient", 100); + // create a fake recipe Recipe testR = new Recipe("test recipe name", testIngredients); recipes.addRecipe(testR); ui.printWeeklyIngredients(weeklyPlan, recipes); assertEquals( ui.formatMessage("Here are your weekly ingredients:") + System.lineSeparator() + ui.formatMessage( - "test ingredient (100)"), outContent.toString().trim()); + "Salt (1)"), outContent.toString().trim()); + assertEquals( + ui.formatMessage("Pepper (1)"), outContent.toString().trim()); + assertEquals( + ui.formatMessage("Chicken (1)"), outContent.toString().trim()); + assertEquals( + ui.formatMessage("Rice (1)"), outContent.toString().trim()); } @Test diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 389d9f1cbc..8146eb4f06 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -72,10 +72,21 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Your weekly plan is empty! | +| I've added the recipe to your weekly plan! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please indicate a valid recipe name. | +| Here are your weekly ingredients: | +| Salt (1) | +| Pepper (1) | +| Chicken (1) | +| Rice (1) | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your weekly plan: | +| Chicken Rice x1 | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| I've deleted the recipe from your weekly plan! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Your weekly plan is empty! | diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index d44391e8c3..dbb7026081 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -13,7 +13,9 @@ weekly weekly random name weekly /add random name 1 weekly /add test recipe name 1 +weekly /add Chicken Rice 1 +weeklyingredients weeklyplan -weekly /delete test recipe name +weekly /delete Chicken Rice weeklyplan bye From 87182baf269b1393cc748ccf46d889db57a8a4b6 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Thu, 23 Mar 2023 19:34:54 +0800 Subject: [PATCH 096/252] changed input.txt --- text-ui-test/input.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 6617787d55..04a886d36d 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -8,6 +8,6 @@ weekly random name weekly /add random name 1 weekly /add test recipe name 1 weeklyplan -weekly /delete test recipe name +weekly /delete Chicken Rice weeklyplan bye From 958c350ff8c73b3fc296bdbdb8d51210ea86028a Mon Sep 17 00:00:00 2001 From: notbingsu Date: Thu, 23 Mar 2023 19:38:13 +0800 Subject: [PATCH 097/252] changed input.txt --- text-ui-test/input.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 04a886d36d..8cfb21607d 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -6,7 +6,7 @@ view abc weekly weekly random name weekly /add random name 1 -weekly /add test recipe name 1 +weekly /add Chicken Rice weeklyplan weekly /delete Chicken Rice weeklyplan From c60594ee4f05f25f0be78f20e613087a49f3e7c8 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 19:57:02 +0800 Subject: [PATCH 098/252] change testing for viewing ingredients --- src/test/java/seedu/meal360/Meal360Test.java | 16 ++++++---------- text-ui-test/EXPECTED.TXT | 17 +++-------------- text-ui-test/input.txt | 6 ++---- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 0bd5881cdb..76fc841522 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -207,22 +207,18 @@ public void testClearWeeklyPlan() { @Test public void testViewIngredients() { WeeklyPlan weeklyPlan = new WeeklyPlan(); - HashMap testIngredients = new HashMap<>(); - testIngredients.put("test ingredient", 100); + weeklyPlan.put("salad", 1); + + HashMap testIngredients = new HashMap<>(); + testIngredients.put("lettuce", 1); // create a fake recipe - Recipe testR = new Recipe("test recipe name", testIngredients); + Recipe testR = new Recipe("salad", testIngredients); recipes.addRecipe(testR); ui.printWeeklyIngredients(weeklyPlan, recipes); assertEquals( ui.formatMessage("Here are your weekly ingredients:") + System.lineSeparator() + ui.formatMessage( - "Salt (1)"), outContent.toString().trim()); - assertEquals( - ui.formatMessage("Pepper (1)"), outContent.toString().trim()); - assertEquals( - ui.formatMessage("Chicken (1)"), outContent.toString().trim()); - assertEquals( - ui.formatMessage("Rice (1)"), outContent.toString().trim()); + "salad (1)"), outContent.toString().trim()); } @Test diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 8146eb4f06..590dffbc9a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -72,21 +72,10 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| I've added the recipe to your weekly plan! | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Here are your weekly ingredients: | -| Salt (1) | -| Pepper (1) | -| Chicken (1) | -| Rice (1) | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Here is your weekly plan: | -| Chicken Rice x1 | +| Your weekly plan is empty! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| I've deleted the recipe from your weekly plan! | +| Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Your weekly plan is empty! | @@ -95,4 +84,4 @@ Welcome to Meal360, your ultimate Recipe Manager! | Saving database... | | Database saved successfully. | | Bye. Hope to see you again soon! | ----------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index dbb7026081..d87afb168e 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -13,9 +13,7 @@ weekly weekly random name weekly /add random name 1 weekly /add test recipe name 1 -weekly /add Chicken Rice 1 -weeklyingredients weeklyplan -weekly /delete Chicken Rice +weekly /delete test recipe name weeklyplan -bye +bye \ No newline at end of file From 41b1b4c03f8f56d681c97f5188f549f9518e6f7d Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 20:02:53 +0800 Subject: [PATCH 099/252] update testing with correct output --- src/test/java/seedu/meal360/Meal360Test.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 76fc841522..56db4be49e 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -209,16 +209,10 @@ public void testViewIngredients() { WeeklyPlan weeklyPlan = new WeeklyPlan(); weeklyPlan.put("salad", 1); - - HashMap testIngredients = new HashMap<>(); - testIngredients.put("lettuce", 1); - // create a fake recipe - Recipe testR = new Recipe("salad", testIngredients); - recipes.addRecipe(testR); ui.printWeeklyIngredients(weeklyPlan, recipes); assertEquals( ui.formatMessage("Here are your weekly ingredients:") + System.lineSeparator() + ui.formatMessage( - "salad (1)"), outContent.toString().trim()); + "cucumber (1) tomato (1) lettuce (1)"), outContent.toString().trim()); } @Test From 9ace85e8260eb2a1212bd1b11ee214d0db0e79de Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 20:07:21 +0800 Subject: [PATCH 100/252] add in new recipe for testing purposes --- src/test/java/seedu/meal360/Meal360Test.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 56db4be49e..c574670835 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -206,13 +206,18 @@ public void testClearWeeklyPlan() { @Test public void testViewIngredients() { + + HashMap pastaIngredients = new HashMap<>(); + pastaIngredients.put("penne", 1); + Recipe salad = new Recipe("pasta", pastaIngredients); + WeeklyPlan weeklyPlan = new WeeklyPlan(); - weeklyPlan.put("salad", 1); + weeklyPlan.put("pasta", 1); ui.printWeeklyIngredients(weeklyPlan, recipes); assertEquals( ui.formatMessage("Here are your weekly ingredients:") + System.lineSeparator() + ui.formatMessage( - "cucumber (1) tomato (1) lettuce (1)"), outContent.toString().trim()); + "penne (1)"), outContent.toString().trim()); } @Test From b9180fb4192b339aa75371d892aef8cb1a3b3380 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 20:10:26 +0800 Subject: [PATCH 101/252] fix testing bug --- src/test/java/seedu/meal360/Meal360Test.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index c574670835..65c9471914 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -209,7 +209,8 @@ public void testViewIngredients() { HashMap pastaIngredients = new HashMap<>(); pastaIngredients.put("penne", 1); - Recipe salad = new Recipe("pasta", pastaIngredients); + Recipe pasta = new Recipe("pasta", pastaIngredients); + recipes.add(pasta); WeeklyPlan weeklyPlan = new WeeklyPlan(); weeklyPlan.put("pasta", 1); From e641c646df11d5543e046617aa91614159c1a025 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 20:37:48 +0800 Subject: [PATCH 102/252] match actual & expected output --- text-ui-test/EXPECTED.TXT | 2 +- text-ui-test/input.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 590dffbc9a..389d9f1cbc 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -84,4 +84,4 @@ Welcome to Meal360, your ultimate Recipe Manager! | Saving database... | | Database saved successfully. | | Bye. Hope to see you again soon! | ----------------------------------------------------------------------------------------------------- \ No newline at end of file +---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index d87afb168e..d44391e8c3 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -16,4 +16,4 @@ weekly /add test recipe name 1 weeklyplan weekly /delete test recipe name weeklyplan -bye \ No newline at end of file +bye From ed0d983fc7b11af972f9c7a1e8d73ee70a140530 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 20:41:32 +0800 Subject: [PATCH 103/252] fix json formatting --- src/main/resources/recipesDatabase.json | 2 +- text-ui-test/src/main/resources/recipesDatabase.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 text-ui-test/src/main/resources/recipesDatabase.json diff --git a/src/main/resources/recipesDatabase.json b/src/main/resources/recipesDatabase.json index 0beacc58a3..1e358670c6 100644 --- a/src/main/resources/recipesDatabase.json +++ b/src/main/resources/recipesDatabase.json @@ -1 +1 @@ -[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file +[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] diff --git a/text-ui-test/src/main/resources/recipesDatabase.json b/text-ui-test/src/main/resources/recipesDatabase.json new file mode 100644 index 0000000000..0beacc58a3 --- /dev/null +++ b/text-ui-test/src/main/resources/recipesDatabase.json @@ -0,0 +1 @@ +[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file From 486b3dcac1f53618c0dd10c7b1f886f385d4d563 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 20:53:09 +0800 Subject: [PATCH 104/252] fix actual vs expected bug --- text-ui-test/EXPECTED.TXT | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 389d9f1cbc..d3b528d58a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -7,8 +7,6 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- | Loading database... | -| Database directory does not exist, creating one now... | -| Database file does not exist, creating one now... | | Database loaded successfully. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- @@ -25,11 +23,10 @@ Welcome to Meal360, your ultimate Recipe Manager! | 10. Buffalo Chicken Mac 'n' Cheese (8 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| Sorry, I am unable to find the recipes you entered. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes): | -| 1. test recipe name (1 ingredients) | +| There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter the command in the valid format. Some arguments might be missing. | @@ -38,7 +35,7 @@ Welcome to Meal360, your ultimate Recipe Manager! | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| Sorry, I am unable to find the recipes you entered. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | There is nothing to list. | From 1caa24433ed0201eaa1033fa6710ec5eebca5f70 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 21:07:41 +0800 Subject: [PATCH 105/252] fix formatting of expected.txt --- 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 d3b528d58a..a8580406e5 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -81,4 +81,4 @@ Welcome to Meal360, your ultimate Recipe Manager! | Saving database... | | Database saved successfully. | | Bye. Hope to see you again soon! | ----------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- \ No newline at end of file From 0fc3ca68158d7fcc57d4ef464117377e2822b5cf Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Thu, 23 Mar 2023 21:09:20 +0800 Subject: [PATCH 106/252] Changes: Accepting ingredient name in 1 line --- src/main/java/seedu/meal360/Meal360.java | 10 ++- src/main/java/seedu/meal360/Parser.java | 81 +++++++++++++++++++----- src/main/resources/recipesDatabase.json | 2 +- 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index bc20de12ea..25dbd7e3ea 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -12,7 +12,7 @@ public class Meal360 { private static final Ui ui = new Ui(); private static final Parser parser = new Parser(); private static final Database database = new Database(); - private static RecipeList recipeList; + private static RecipeList recipeList = new RecipeList(); private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); public static void startApp() { @@ -35,7 +35,9 @@ public static void startApp() { } public static void receiveInput(String input) { + input = input.replaceAll("\\s+", " "); String[] command = input.trim().split(" "); + if (input.equalsIgnoreCase("bye")) { canExit = true; } else if (command[0].equals("delete")) { @@ -97,6 +99,9 @@ public static void receiveInput(String input) { } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format("Please enter a valid recipe name."); ui.printMessage(errorMessage); + } catch (NullPointerException e){ + String errorMessage = String.format("Recipe already exists. Add a new recipe."); + ui.printMessage(errorMessage); } ui.printSeparator(); } else if (command[0].equals("edit")) { @@ -118,6 +123,9 @@ public static void receiveInput(String input) { "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", command[1]); ui.printMessage(errorMessage); + } catch (NullPointerException e){ + String errorMessage = String.format("Recipe doesn't exist for editing."); + ui.printMessage(errorMessage); } ui.printSeparator(); } else if (command[0].equals("tag")) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index b13e27789e..ea063ec29f 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -7,17 +7,65 @@ public class Parser { Ui ui = new Ui(); - public String combineWords(String[] input, int startIndex) { + public String combineWords(String[] input, int startIndex, int length) { StringBuilder word = new StringBuilder(input[startIndex]); - for (int i = startIndex + 1; i < input.length - 1; i++) { + for (int i = startIndex + 1; i < length; i++) { word.append(" ").append(input[i]); } return word.toString(); } + public HashMap parseIngredientName(String[] command){ + HashMap ingredients = new HashMap<>(); + int flag = 0; + String add = null; + String ingredientName = null; + int ingredientQuantity; + int indexOfEqual; + + for (String s : command) { + try{ + indexOfEqual = s.indexOf("="); + if (indexOfEqual == -1) { + if (add != null) { + add = add + " " + s; + } else { + add = s; + } + flag++; + + } else { + if (flag > 0) { + indexOfEqual = s.indexOf("="); + ingredientName = (s.substring(0, indexOfEqual)); + ingredientName = add + " " + ingredientName; + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + flag = 0; + add = null; + } else { + ingredientName = s.substring(0, indexOfEqual); + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + } + + ingredients.put(ingredientName, ingredientQuantity); + + } + } catch (NumberFormatException e) { + ui.printSeparator(); + String errorMessage = String.format("Please enter ingredients properly![eg: chicken=100]"); + ui.printMessage(errorMessage); + ui.printSeparator(); + } + } + return ingredients; + } + public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { - String recipeName = combineWords(input, 2); + String recipeName = combineWords(input, 2, input.length); + if(recipeList.findByName(recipeName)!=null){ + return null; + } HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); System.out.println("Please Enter The Ingredients & Quantity: "); @@ -28,8 +76,7 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { break; } else { String[] command = line.trim().split(" "); - String ingredientName = combineWords(command, 0); - ingredients.put(ingredientName, Integer.parseInt(command[command.length - 1])); + ingredients = parseIngredientName(command); } } Recipe newRecipe = new Recipe(recipeName, ingredients); @@ -38,15 +85,14 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { } public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { - String recipeName = combineWords(input, 2); + String recipeName = combineWords(input, 2, input.length); Recipe recipeToEdit; - HashMap ingredients = new HashMap<>(); + HashMap ingredients = null; Scanner userInput = new Scanner(System.in); if (recipeList.findByName(recipeName) == null) { return null; - } else { - recipeToEdit = recipeList.findByName(recipeName); } + recipeToEdit = recipeList.findByName(recipeName); System.out.println("Do you want to edit recipe fully or partially?"); System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); @@ -60,7 +106,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { break; } String[] command = line.trim().split(" "); - ingredients.put(command[0], Integer.parseInt(command[1])); + ingredients = parseIngredientName(command); recipeList.editRecipe(recipeToEdit, ingredients); } } else if (index == 2) { @@ -88,12 +134,15 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } System.out.println("Please enter the new ingredient:"); String line = userInput.nextLine(); - String[] command = line.trim().split(" "); - String newIngredientName = combineWords(command, 0); + String command = line.replaceAll("\\s+", " "); + int indexOfEqual = command.indexOf("="); + String newIngredientName = command.substring(0,indexOfEqual); + int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual+1)); recipeToEdit.getIngredients().remove(ingredientToRemove); - recipeToEdit.getIngredients().put(newIngredientName, Integer.parseInt(command[command.length - 1])); + recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); } else if (index == 3) { + HashMap newIngredientList = recipeToEdit.getIngredients(); System.out.println("These are the current ingredients:"); ui.printSeparator(); Recipe recipe = parseViewRecipe(recipeName, recipeList); @@ -107,11 +156,11 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { break; } else { String[] command = line.trim().split(" "); - String ingredientName = combineWords(command, 0); - recipeToEdit.getIngredients().put(ingredientName, Integer.parseInt(command[command.length - 1])); + ingredients = parseIngredientName(command); + newIngredientList.putAll(ingredients); } } - recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); + recipeList.editRecipe(recipeToEdit, newIngredientList); } return recipeToEdit; diff --git a/src/main/resources/recipesDatabase.json b/src/main/resources/recipesDatabase.json index 0beacc58a3..428fc1b411 100644 --- a/src/main/resources/recipesDatabase.json +++ b/src/main/resources/recipesDatabase.json @@ -1 +1 @@ -[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file +[{"ingredients":{"vegetable and oil":300,"new chicken":100},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file From c47d3bbf74754b1999478db8574e7e4768662987 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 21:10:05 +0800 Subject: [PATCH 107/252] add back newline --- 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 a8580406e5..d3b528d58a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -81,4 +81,4 @@ Welcome to Meal360, your ultimate Recipe Manager! | Saving database... | | Database saved successfully. | | Bye. Hope to see you again soon! | ----------------------------------------------------------------------------------------------------- \ No newline at end of file +---------------------------------------------------------------------------------------------------- From 9ed5b9059215139049c43e1d5f8208a9abe5b582 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Thu, 23 Mar 2023 21:17:49 +0800 Subject: [PATCH 108/252] runtest works --- text-ui-test/EXPECTED.TXT | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 389d9f1cbc..f487e28113 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -25,11 +25,10 @@ Welcome to Meal360, your ultimate Recipe Manager! | 10. Buffalo Chicken Mac 'n' Cheese (8 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| Sorry, I am unable to find the recipes you entered. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes): | -| 1. test recipe name (1 ingredients) | +| There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter the command in the valid format. Some arguments might be missing. | @@ -38,7 +37,7 @@ Welcome to Meal360, your ultimate Recipe Manager! | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| Sorry, I am unable to find the recipes you entered. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | There is nothing to list. | From 3d5e0d5c9dd21549e8ea313cca6da887d4740b8e Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 21:21:00 +0800 Subject: [PATCH 109/252] add another newline --- 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 d3b528d58a..128788593c 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -82,3 +82,4 @@ Welcome to Meal360, your ultimate Recipe Manager! | Database saved successfully. | | Bye. Hope to see you again soon! | ---------------------------------------------------------------------------------------------------- + From bda137936758989b95eee5f3bfa1148ba68af639 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 21:28:22 +0800 Subject: [PATCH 110/252] copy in new expected file --- text-ui-test/EXPECTED.TXT | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 128788593c..f487e28113 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -7,6 +7,8 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- | Loading database... | +| Database directory does not exist, creating one now... | +| Database file does not exist, creating one now... | | Database loaded successfully. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- @@ -82,4 +84,3 @@ Welcome to Meal360, your ultimate Recipe Manager! | Database saved successfully. | | Bye. Hope to see you again soon! | ---------------------------------------------------------------------------------------------------- - From 7f98a2c4b8c4b7c90d310a77e0595bbb036a68e2 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 22:01:26 +0800 Subject: [PATCH 111/252] add back file --- src/main/resources/recipesDatabase.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/recipesDatabase.json b/src/main/resources/recipesDatabase.json index 1e358670c6..e69de29bb2 100644 --- a/src/main/resources/recipesDatabase.json +++ b/src/main/resources/recipesDatabase.json @@ -1 +0,0 @@ -[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] From fd161d86bb51ff6e1bb5d2c21ea8e20b2bab9e7c Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 22:01:39 +0800 Subject: [PATCH 112/252] add newline --- src/main/resources/recipesDatabase.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/recipesDatabase.json b/src/main/resources/recipesDatabase.json index e69de29bb2..1e358670c6 100644 --- a/src/main/resources/recipesDatabase.json +++ b/src/main/resources/recipesDatabase.json @@ -0,0 +1 @@ +[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] From 76650e879e6233101de0fc4b005a6397855723dd Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 23 Mar 2023 22:06:47 +0800 Subject: [PATCH 113/252] delete test --- text-ui-test/EXPECTED.TXT | 75 --------------------------------------- text-ui-test/input.txt | 19 ---------- 2 files changed, 94 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index f487e28113..81ec07f65e 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -7,80 +7,5 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- | Loading database... | -| Database directory does not exist, creating one now... | -| Database file does not exist, creating one now... | | Database loaded successfully. | ---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| These are the recipes you have (10 recipes): | -| 1. Chicken Rice (4 ingredients) | -| 2. Tomato fritters (8 ingredients) | -| 3. Chicken and mushroom pie (7 ingredients) | -| 4. Seafood paella (10 ingredients) | -| 5. Avocado toast (5 ingredients) | -| 6. Italian sausage orzo soup (13 ingredients) | -| 7. Chicken and mushroom pasta (8 ingredients) | -| 8. Creamy Hummus Pasta (6 ingredients) | -| 9. Ground beef and potato casserole (8 ingredients) | -| 10. Buffalo Chicken Mac 'n' Cheese (8 ingredients) | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Sorry, I am unable to find the recipes you entered. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| There is nothing to list. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please enter the command in the valid format. Some arguments might be missing. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| There is nothing to list. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Sorry, I am unable to find the recipes you entered. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| There is nothing to list. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please enter a valid recipe number. You did not enter a recipe number. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Name of recipe: Chicken Rice | -| 1. Salt(1) | -| 2. Pepper(1) | -| 3. Chicken(1) | -| 4. Rice(1) | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please enter a valid recipe number. You entered -2, which is out of bounds. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please enter a valid recipe number. You entered abc, which is not a number. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Insufficient number of arguments provided. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please indicate if you would want to add or delete the recipe from your weekly plan. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please indicate a valid recipe name. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please indicate a valid recipe name. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Your weekly plan is empty! | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Please indicate a valid recipe name. | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Your weekly plan is empty! | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| Saving database... | -| Database saved successfully. | -| Bye. Hope to see you again soon! | ----------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index d44391e8c3..e69de29bb2 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,19 +0,0 @@ -list -tag tag#1 << test recipe name -list /t tag#1 -list /t -list apple -tag tag#1 >> test recipe name -list /t tag#1 -view -view 1 -view -2 -view abc -weekly -weekly random name -weekly /add random name 1 -weekly /add test recipe name 1 -weeklyplan -weekly /delete test recipe name -weeklyplan -bye From 85d8c49fc07bc80d78f9ccddd570fc5b991dbb0c Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Thu, 23 Mar 2023 23:08:32 +0800 Subject: [PATCH 114/252] removed assert statement in main --- src/main/java/seedu/meal360/Meal360.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 25dbd7e3ea..05c268a5df 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -195,9 +195,7 @@ public static void exitApp() { } public static void main(String[] args) { - - assert false : "dummy assertion set to fail"; - + startApp(); String line; From 47b97859cb8775ebb563d7752fc3f7a5740abc01 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 23 Mar 2023 23:14:57 +0800 Subject: [PATCH 115/252] Fix merge conflicts --- src/main/java/seedu/meal360/Meal360.java | 8 ++++---- text-ui-test/EXPECTED.TXT | 7 ++++--- text-ui-test/input.txt | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 05c268a5df..4a4a2b2af2 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -86,7 +86,8 @@ public static void receiveInput(String input) { RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); ui.listRecipe(recipeListToPrint); } catch (IllegalArgumentException e) { - String errorMessage = "Please enter the command in the valid format. Some arguments might be missing."; + String errorMessage = + "Please enter the command in the valid format. Some arguments might " + "be missing."; ui.printMessage(errorMessage); } ui.printSeparator(); @@ -99,7 +100,7 @@ public static void receiveInput(String input) { } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = String.format("Please enter a valid recipe name."); ui.printMessage(errorMessage); - } catch (NullPointerException e){ + } catch (NullPointerException e) { String errorMessage = String.format("Recipe already exists. Add a new recipe."); ui.printMessage(errorMessage); } @@ -123,7 +124,7 @@ public static void receiveInput(String input) { "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", command[1]); ui.printMessage(errorMessage); - } catch (NullPointerException e){ + } catch (NullPointerException e) { String errorMessage = String.format("Recipe doesn't exist for editing."); ui.printMessage(errorMessage); } @@ -195,7 +196,6 @@ public static void exitApp() { } public static void main(String[] args) { - startApp(); String line; diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index f487e28113..e111cff0f1 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -25,10 +25,11 @@ Welcome to Meal360, your ultimate Recipe Manager! | 10. Buffalo Chicken Mac 'n' Cheese (8 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Sorry, I am unable to find the recipes you entered. | +| You have modified the recipe(s) in this "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| There is nothing to list. | +| These are the recipes you have (1 recipes): | +| 1. Avocado toast (5 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter the command in the valid format. Some arguments might be missing. | @@ -37,7 +38,7 @@ Welcome to Meal360, your ultimate Recipe Manager! | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Sorry, I am unable to find the recipes you entered. | +| You have modified the recipe(s) in this "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | There is nothing to list. | diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index d44391e8c3..7fa2749f5e 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,9 +1,9 @@ list -tag tag#1 << test recipe name +tag tag#1 << avocado toast list /t tag#1 list /t list apple -tag tag#1 >> test recipe name +tag tag#1 >> avocado toast list /t tag#1 view view 1 @@ -16,4 +16,4 @@ weekly /add test recipe name 1 weeklyplan weekly /delete test recipe name weeklyplan -bye +bye \ No newline at end of file From 11f155b0498b2726e9544d3b8f9a5be6351e6269 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 23 Mar 2023 23:59:11 +0800 Subject: [PATCH 116/252] Edit sourcing of database Remove print statements and change to use universal path separator --- src/main/java/seedu/meal360/Database.java | 9 ++++----- text-ui-test/EXPECTED.TXT | 2 -- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index 85e7dbd6b8..a9ece4bbc0 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -11,8 +11,10 @@ public class Database { - private static final Ui ui = new Ui(); - private static final String recipesDatabaseFilepath = "./src/main/resources/recipesDatabase.json"; + private static final String recipesDatabaseFilepath = + "." + System.getProperty("file.separator") + "src" + System.getProperty("file.separator") + "main" + + System.getProperty("file.separator") + "resources" + System.getProperty( + "file.separator") + "recipesDatabase.json"; public RecipeList loadDatabase() throws IOException { RecipeList database; @@ -25,10 +27,8 @@ public RecipeList loadDatabase() throws IOException { // Create the parent directory if it does not exist File parentDir = file.getParentFile(); if (!parentDir.exists()) { - ui.printMessage("Database directory does not exist, creating one now..."); parentDir.mkdirs(); } - ui.printMessage("Database file does not exist, creating one now..."); file.createNewFile(); } catch (IOException e) { throw new IOException("Error creating database file."); @@ -52,7 +52,6 @@ public RecipeList loadDatabase() throws IOException { // Ensure non empty recipeList is returned if (database == null) { - ui.printMessage("Database file is empty, loading default database"); return defaultRecipeList(); } else { return database; diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index e111cff0f1..244da9d06a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -7,8 +7,6 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- | Loading database... | -| Database directory does not exist, creating one now... | -| Database file does not exist, creating one now... | | Database loaded successfully. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- From d062a0cdb7aa8a42554713d7254e3e8ecdfa6fd7 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 24 Mar 2023 02:52:14 +0800 Subject: [PATCH 117/252] update DG (add 'list' and 'tag') --- docs/DeveloperGuide.md | 89 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 8 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b4e163944b..b60db3db9a 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -2,7 +2,7 @@ * [Acknowledgements](#acknowledgements) * [Setting up, getting started](#setting-up-getting-started) -* [Design & implementation](#design--implementation) +* [Design](#design) * [Architecture](#architecture) * [UI Component](#ui-component) * [Parser Component](#parser-component) @@ -10,6 +10,9 @@ * [RecipeList Component](#recipelist-component) * [WeeklyPlan Component](#weeklyplan-component) * [Database Component](#database-component) +* [Implementation](#implementation) + * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) + * [List Recipes Feature](#list-recipes-feature) * [Appendix: Requirements](#appendix-requirements) * [Product scope](#product-scope) @@ -32,7 +35,7 @@ include links to the original source as well} --- -## Design & implementation +## Design * [Architecture](#architecture) * [UI Component](#ui-component) @@ -44,15 +47,25 @@ include links to the original source as well} ### Architecture + ### UI Component +API: `Ui.java` ### Parser Component +API: `Parser.java` ### Recipe Component +API: `Recipe.java` + +The `Recipe` component: + +* contains `name` and `ingredients` attribute +* store the ingredients details the user has added in `ingredients` ### RecipeList Component API: `RecipeList.java` + The `RecipeList` component: * extends from `ArrayList` @@ -118,6 +131,56 @@ The activity diagram below shows how the `Database` component works at start up: ![](../docs/UML/Database/DatabaseStartupUML.png) --- +## Implementation +* [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) +* [List Recipes Feature](#list-recipes-feature) + +### Categorise/Tag Recipes Feature + +The current implementation: +* add recipes into a tag +* remove recipes from a tag + +It is implemented through the following step: +1. When the user enters an input with the first word being `tag`, the input is passed to + the `Parser` component. +2. In `Parser`, `parseTagRecipe()` is executed to identify whether user want to add recipes + to a tag (`<<`), or remove recipes from a tag(`>>`). Then, + * If user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to extract + the all the recipes to be added, separated by `,`. and pass those recipes to `RecipeList` + component. + * If user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be executed to + extract the all the recipes to be removed, separated by `,`. and pass those recipes to + `RecipeList` component. +3. In `RecipeList`, + * If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in + to the tag. + * If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to add recipes + in to the tag. + +The sequence diagram below shows how this feature works: +{UML will be added here.} + +### List Recipes Feature + +The current implementation: +* list all recipes +* list recipe with filters (name, ingredients, tags) + +It is implemented through the following step: +1. When the user enters an input with the first word being `list`, the input is passed to + the `Parser` component. +2. In `Parser`, `parseListRecipe()` is executed to identify whether user want to filter + by tag (`/t`), otherwise the list is filtered by name and ingredients, and whether + there are many filters (`&`). All the filters is extracted out and passed to `RecipeList` + component. +3. In `RecipeList`, `listRecipes()` is executed to filter all recipes that match the filters, + and return the `recipeList`containing all relevant recipes to `ParserRecipe()`. + +The sequence diagram below shows how this feature works: +{UML will be added here.} + +--- ## Appendix: Requirements ### Product scope @@ -133,15 +196,25 @@ The activity diagram below shows how the `Database` component works at start up: ### Value proposition -Allows management of recipes, ingredients and weekly meal plan faster than a typical mosue/GUI +Allows management of recipes, ingredients and weekly meal plan faster than a typical mouse/GUI driven app. ### User Stories -|Version| As a ... | I want to ... | So that I can ...| -|--------|----------|---------------|------------------| -|v1.0|new user|see usage instructions|refer to them when I forget how to use the application| -|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| +| Version | As a ... | I want to ... | So that I can ... | +|---------|----------|---------------------------------------------------|-------------------------------------------------------------------| +| v1.0 | user | add my own recipes to the list | refer to them when next time | +| v1.0 | user | edit the existing recipe | | +| v1.0 | user | delete a recipe from the list | clear the unused recipes | +| v1.0 | user | view ingredients of the recipe | know what is needed to be prepared | +| v1.0 | user | list all recipes I have | know what I have some idea of what to cook | +| v1.0 | user | find the recipe that contain specific ingredients | find specific recipe without having to go through the entire list | +| v1.0 | user | exit from the program | | +| v2.0 | new user | list all the command that can be used | know what command I can use | +| v2.0 | user | add meals I plan to make for the week | refer to the weekly meals plan next time | +| v2.0 | user | delete meals I plan to make for the week | remove some meals from the weekly plan if I change my mind | +| v2.0 | user | categorise recipes using tags | group recipes with similar theme together | +| v2.0 | user | list the recipes by tag | list recipes that are under the specific category | ### Non-Functional Requirements @@ -154,4 +227,4 @@ driven app. ### 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} +for testing} \ No newline at end of file From e9e4f1449a3e0c1281dfe7f5c4a24d30a3379626 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 24 Mar 2023 10:02:23 +0800 Subject: [PATCH 118/252] no message --- src/main/java/seedu/meal360/Meal360.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 05c268a5df..b2d5314340 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -195,7 +195,7 @@ public static void exitApp() { } public static void main(String[] args) { - + startApp(); String line; From c7a331a3118d06f4d6d0655169873c45ce237bee Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 24 Mar 2023 11:38:34 +0800 Subject: [PATCH 119/252] update DG & some comments --- docs/DeveloperGuide.md | 21 ++++++++++++++++++++- src/main/java/seedu/meal360/Parser.java | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b60db3db9a..18484d84d9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -13,6 +13,7 @@ * [Implementation](#implementation) * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) + * [Delete Recipes Feature](#delete-recipes-feature) * [Appendix: Requirements](#appendix-requirements) * [Product scope](#product-scope) @@ -87,7 +88,7 @@ The `WeeklyPlan` component: * stores the names of recipes that the user plans to prepare for the week as `String` * stores the number of times the user plans to prepare each recipe as `Integer` * allows users to add single or multiple recipes from the weekly plan -* allows users to delete single or multiple recipes from the weekly plan +* allows users to delete single, multiple, or all recipes from the weekly plan How the `WeeklyPlan` component works: @@ -180,6 +181,24 @@ It is implemented through the following step: The sequence diagram below shows how this feature works: {UML will be added here.} +### Delete Recipes Feature + +The current implementation: +* deletes a single recipe by name or recipe's index in recipe list +* deletes a range of recipes +* deletes all recipes + +It is implemented through the following step: +1. When the user enters an input with the first word being `delete`, the input is passed to + the `Parser` component. +2. In `Parser`, `parseDeleteRecipe()` is executed to identify whether the user wants to delete all recipes, a single + recipe, or range of recipes. +4. In `RecipeList`, `deleteRecipe()` is executed to delete the recipe at whatever index is passed as a parameter, + and return the `Recipe` object at that index/the one just deleted. + +The sequence diagram below shows how this feature works: +{UML will be added here.} + --- ## Appendix: Requirements diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 8ec6fa330e..43f6bfdb3c 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -200,7 +200,7 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } // user inputted index of recipe in list } else { - // deleting a range of recipes + // check if deleting a range of recipes if (input[1].length() >= 3) { StringBuilder rangeRecipes = new StringBuilder(); int startIndex = Integer.parseInt(input[1].charAt(0) + ""); From 8deb9707010f6d9b362706cfb20de88552f9c905 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 24 Mar 2023 11:55:52 +0800 Subject: [PATCH 120/252] DG --- docs/DeveloperGuide.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b60db3db9a..40391533b7 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -11,6 +11,8 @@ * [WeeklyPlan Component](#weeklyplan-component) * [Database Component](#database-component) * [Implementation](#implementation) + * [Add Recipes Feature](#add-recipes-feature) + * [Edit Recipes Feature](#edit-recipes-feature) * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) @@ -134,6 +136,8 @@ The activity diagram below shows how the `Database` component works at start up: ## Implementation * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) +* [Add Recipes Feature](#add-recipes-feature) +* [Edit Recipes Feature](#edit-recipes-feature) ### Categorise/Tag Recipes Feature @@ -180,6 +184,36 @@ It is implemented through the following step: The sequence diagram below shows how this feature works: {UML will be added here.} +### Add Recipes Feature + +The current implementation: +* Add a single recipe in 1 line and followed by all the ingredients in next another line after being prompted. + +It is implemented through the following steps: +1. When the user enters an input with the first word being `add`, the input is passed to the `Parser` component. +2. In `Parser`, the `parseAddRecipe` is executed to identify whether the recipe is an already existing recipe or + it's a new recipe that is being added. +3. After the user enters the ingredients in 1 line, the input is passed to `parseIngredientName` which returns a + hashmap with the ingredient name as 'key' and quantity as 'value'. +4. After the recipe name and ingredients are accepted and processed, the input is sent to `recipeList.addRecipe()` + to store the new recipe data. + +### Edit Recipes Feature + +The current implementation: +* There are 3 ways to edit: + * Edit all ingredients. + * Edit 1 particular ingredient. + * Add new ingredient. + +It is implemented through the following steps: + +1. When the user enters an input with the first word being `edit`, the input is passed to the `Parser` component. +2. In `Parser`, the `parseEditRecipe` is executed to identify whether the recipe is an already existing recipe to make edits. +3. The user will then be prompted with 3 options as mentioned above to make edits to the recipe ingredients. +4. After the new ingredients are accepted and processed, the input is sent to `recipeList.editRecipe()` + to update the new recipe data. + --- ## Appendix: Requirements From 4158a1400abba2281956dd2c9bf563e35b405c2f Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 24 Mar 2023 12:28:51 +0800 Subject: [PATCH 121/252] add list and tag UML in DG --- docs/DeveloperGuide.md | 4 ++-- .../ListFunction/ListFunction.drawio | 1 + .../ListFunction/ListFunction.png | Bin 0 -> 12796 bytes .../TagFunction/TagFunction.drawio | 1 + .../Implementation/TagFunction/TagFunction.png | Bin 0 -> 32388 bytes 5 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 docs/UML/Implementation/ListFunction/ListFunction.drawio create mode 100644 docs/UML/Implementation/ListFunction/ListFunction.png create mode 100644 docs/UML/Implementation/TagFunction/TagFunction.drawio create mode 100644 docs/UML/Implementation/TagFunction/TagFunction.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b60db3db9a..43a3594445 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -159,7 +159,7 @@ It is implemented through the following step: in to the tag. The sequence diagram below shows how this feature works: -{UML will be added here.} +![](../docs/UML/Implementation/TagFunction/TagFunction.png) ### List Recipes Feature @@ -178,7 +178,7 @@ It is implemented through the following step: and return the `recipeList`containing all relevant recipes to `ParserRecipe()`. The sequence diagram below shows how this feature works: -{UML will be added here.} +![](../docs/UML/Implementation/ListFunction/ListFunction.png) --- ## Appendix: Requirements diff --git a/docs/UML/Implementation/ListFunction/ListFunction.drawio b/docs/UML/Implementation/ListFunction/ListFunction.drawio new file mode 100644 index 0000000000..f5ac2e7347 --- /dev/null +++ b/docs/UML/Implementation/ListFunction/ListFunction.drawio @@ -0,0 +1 @@ +7ZjJbtswEIafRkB7SKHFsuNjbKfpIQWCuG16KxhpLBGlRIWkvOTpS0rUSm8xEiRtczL5czhc5uOItOVNk/UVQ1n8lYZALNcO15Y3s1zXsX1b/ihlUyq+45dCxHCojRphjh+h6qnVHIfAO4aCUiJw1hUDmqYQiI6GGKOrrtmCku6oGYrAEOYBIqZ6h0MRl+p5tSylfwEcxdXIjq1bElQZa4HHKKSrluRdWt6UUSrKUrKeAlGbV+1L2e/zjtZ6YgxScUyHXwNxt/nhTp3xw9335Xj88/Fseqa9LBHJ9YIt7+IWApzBNeZCz1xsqu2Qi8hUMU/INV4AwamsTTJgOAEBTLYQLd802mQVYwHzDAWq60qCIrVYJETWHFmUsRNIdmG6HjKafUMsArUuuzAgBGUc3xfTUAqDIGccL+EWeMmMUmku1NDTmgUlZpQJqXDB5BhKBMTFCuTivEkKq8tQxrta4GhiucOHXIVkAnVDLcm9abWTe9rq3Ri5057RDgdLYAJL0nZ0lQtcQtjpa3cMGM3T0LAYzWRJ74lnF077nFRBl+PDuiVpbq6AysCxjTTRrf5IM1wdYl1dNSei5j5un4ZzLSJ9CqPadQOqLGhWn8Cta3LbR7UFWEZl5Isp+BPLn/WIlXzENKIpIm1mt7IkCirn6hBw8xT8h6CZcO1NM0cTN/A7wI22AWfy5r8Ubt62NHmDGJeovKfIv5LcZ06Rnt0l9vVT5OA9Rb4J0I5Mkd5TiRscAZzJ24vh5hu4ZSo/qltkeZ/8ENAkQWlY7JvN6jvmx31YVnG5IDhKpXZPhaCJCmYaXqjrvdIIDX53IJFcdYGogu/N6kDXQdXZUgewrO1MCKLKuQdOnZrLMUE8sz85RtyqGDEgSMgE3n3UbAmcdn+jznDj2xl0b211/qlccJqzAHSv9suh58gdH3BU7soeR5UhXSw4dGwK1up9OR2/4UH8FpjItMVL/DD/hqJ/izzn7ZDnDXvAuCeS1394GI7eAHkjg7ySNAj3vKNfH7QQ8bioOPuoO0jT88MzdLofNmd0IjwGhX1HO+B5LjDODTDYOxCnZBO/B0T/DnMsEMYHse/oZCBktfkjrzRv/g71Lv8A \ No newline at end of file diff --git a/docs/UML/Implementation/ListFunction/ListFunction.png b/docs/UML/Implementation/ListFunction/ListFunction.png new file mode 100644 index 0000000000000000000000000000000000000000..558159798935fb2ef0cdc9bc8adec7b069f4ec53 GIT binary patch literal 12796 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 J7-reZ{{WNhb7Ztdb6M4FIZ/TaTORSrAgSSX/ZzdVSpVbdXZuVq5wSFWDWaN8zW/fk2wCRgnoSmknW56UzjYxj5+/Pr4oHTAVbj8zmA8vaM+Ih3H8pcdcN1xHNtyLfEvtawyi2u7mSFg2JeFNoZH/AupmtI6wz5KSgU5pYTjuGwc0yhCY16yQcboolxsQkn5rTEMUMXwOIakav2BfT7NrAM1rNT+B8LBVL3ZtuSTEKrC0pBMoU8XBRO46YArRinPrsLlFSKp85Rfsnq3W57mHWMo4nUqwOenxWRge/jpLni982Pr3vrZ7WWtzCGZyQFDwmV/+Uo5QXQ9Ti9nIbllMBSXl4sp5ugxhuPUvhBzL2xTHhJxZ4vLmOKII3YzF51LZ8AStmqH5RjmiHG0LJjkAL4jGiLOVqKIeupJZ66UuyVNi83ceMrh0+K89GRBKHkI8rY3LhMX0mtmD6Ln0d/Pi9VkOHqx//qx/HN42f/H4MGK+xidRT7ypRv2eG6CCbmihDJxH9EIteM4R93vd5z1fsfFo1+jcLYM7GW3O7RfgRP8fOh6VceBiwc0xjEa4WQnhCM8QQSvfRMjhkV/UOouIs33G9s+bwvZ4FBUYfLeZzR+gixAXM7WmBIC4wS/rLuRWhgaz1iC5+gBJZlcpVY64+mrr3IZstargHFhSTgT70iNCCZ8gcTgwGWEFje+kBo1wL6YZu/fWaoGlyh/kJuEbwrPyQst1N4Ucq60QlsaSMHBQuS2VBUDnAtei3WtUgFFdLlE/1pcSZ+Ahla8NyiD26tym0tukdue3Ra3NRa8LoTrLriXHfdaI1bwMaUBjSApMmtkia+pfEwXQVJdBf9D0Kpw7ZSZ2sT1tC0GVIkzCSVoizfXpJP3kCWClZNG/pboNqyRwHJLyLp1NdJqi1lw0shPAVpNjXTfSpymkQbgjBLZhEYajzEn3r42b26Zt2E93vptyduggluc7sdPMMjOL2djGoYw8tdus1h+pvm2i0o1LRcEB5GwvVDOaZjOZeRfpJmM1Ebo+LXEiMCqzIOae3Cdz3M+p3JzLh1Ht+4/XG3xe0Q+7UudOexa53Zl2lR0zxCBXMQLpR6Y5k02f58u4cLxVg/a9J0toTM2RrJWMUmiNZSjta2hzCs7GlIF6WSSoFKZNWq5Xw6nz1YBQiFp4/sZeU9UQHjGYVBE77fCLpup/Vr/FuwsB7RFHtDOp7YuOnXJ6zt7GvoM5FX32QkmYoNE/o7EzcfD5sNkur6xd5G3l6jm6alM+nB4Dop//cNgAn1Pb7cWTI2BUj20rjXpREZtXemVz3RODzRChr5TinbbIsOo3sMKGCIIx8mF74uNKw3GdUZEhMjL+QgRUdNXpOXIDWlzKFEaoyiL4XXGQuz7ZNvHjJrbVf0YNs8Q5d8uDCn4lhJLxi8XTptrtLSwxHP5ZW+wb/mW3S4q3mKi3n+0mEGEDJ7XL81W12loXQ+1da3nqWtLvKc1pHOyZSGLiYKrQjF5GN7RYcvY4Q15WYtb4mmtstbHRkIVI9yGr0upzjygkM7RV5caWwtKjV/7jik1hnhgfWK+yM8t4tQiD82PnOEoOOc0uzj71t4p+oiy1MQJ2iBLttvUMaasJraOQv3I0zV3sGVZUh3eI0vtC49tUJ4dvJ5ykcfLRb5ZR/XjGbCBWILDzZ9XkdW2Pg2aWeufWPsqrAFXi+cGB7HWRM7bzFo16c3WwVS2gd8yGn6l1OPO9fZJc4/b5Om9qch97R43M2memWpe4ZSZbDIzCXrOuWsVE1CHxodepd0D2GqKGzXKU6KyqUQlGHiNgKInKtN2PxKU6ke3r5Ata2SbO2K6DLjNbHF69gz0D9ri3ntq3TKcT55bU6cMPZvzUIgHv2RCp/6CAEP1XUXlJ7yGFoSe9t0D7qF5G2f4IQtiy3BazOqI281vcLLim18ygZv/AA== \ No newline at end of file diff --git a/docs/UML/Implementation/TagFunction/TagFunction.png b/docs/UML/Implementation/TagFunction/TagFunction.png new file mode 100644 index 0000000000000000000000000000000000000000..b7a69f63aa4f87939587f859a5cf010991b26ab0 GIT binary patch literal 32388 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 z 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%0A&#sxs9o14uK1)=b01VNopq@QWz-dUcGRgf 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 S06bQnOkG)9saWyGgZ~BjEbu-6 literal 0 HcmV?d00001 From 4febdbeadb7f1eda80457dff2c1ff74cbf88c540 Mon Sep 17 00:00:00 2001 From: JuneNita <88151966+JuneNita@users.noreply.github.com> Date: Fri, 24 Mar 2023 15:27:33 +0800 Subject: [PATCH 122/252] edit the UML pic format --- docs/DeveloperGuide.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 4b30736092..c043dd632b 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -183,6 +183,7 @@ It is implemented through the following step: and return the `recipeList`containing all relevant recipes to `ParserRecipe()`. The sequence diagram below shows how this feature works: + ![](../docs/UML/Implementation/ListFunction/ListFunction.png) ### Delete Recipes Feature @@ -280,4 +281,4 @@ driven app. ### 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} \ No newline at end of file +for testing} From 2bcb81005c8070721c28b687bead25b8b316e4a6 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Sat, 25 Mar 2023 23:55:37 +0800 Subject: [PATCH 123/252] Merge branch 'master' of https://github.com/AY2223S2-CS2113-F10-3/tp into JuneNita-withUpstream --- docs/DeveloperGuide.md | 82 ++++++++++++++++++++----- src/main/java/seedu/meal360/Parser.java | 2 +- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 43a3594445..79b4a660ff 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -11,8 +11,11 @@ * [WeeklyPlan Component](#weeklyplan-component) * [Database Component](#database-component) * [Implementation](#implementation) + * [Add Recipes Feature](#add-recipes-feature) + * [Edit Recipes Feature](#edit-recipes-feature) * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) + * [Delete Recipes Feature](#delete-recipes-feature) * [Appendix: Requirements](#appendix-requirements) * [Product scope](#product-scope) @@ -87,7 +90,7 @@ The `WeeklyPlan` component: * stores the names of recipes that the user plans to prepare for the week as `String` * stores the number of times the user plans to prepare each recipe as `Integer` * allows users to add single or multiple recipes from the weekly plan -* allows users to delete single or multiple recipes from the weekly plan +* allows users to delete single, multiple, or all recipes from the weekly plan How the `WeeklyPlan` component works: @@ -134,6 +137,8 @@ The activity diagram below shows how the `Database` component works at start up: ## Implementation * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) +* [Add Recipes Feature](#add-recipes-feature) +* [Edit Recipes Feature](#edit-recipes-feature) ### Categorise/Tag Recipes Feature @@ -144,19 +149,19 @@ The current implementation: It is implemented through the following step: 1. When the user enters an input with the first word being `tag`, the input is passed to the `Parser` component. -2. In `Parser`, `parseTagRecipe()` is executed to identify whether user want to add recipes +2. In `Parser`, `parseTagRecipe()` is executed to identify whether user want to add recipes to a tag (`<<`), or remove recipes from a tag(`>>`). Then, - * If user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to extract - the all the recipes to be added, separated by `,`. and pass those recipes to `RecipeList` - component. - * If user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be executed to - extract the all the recipes to be removed, separated by `,`. and pass those recipes to - `RecipeList` component. + * If user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to extract + the all the recipes to be added, separated by `,`. and pass those recipes to `RecipeList` + component. + * If user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be executed to + extract the all the recipes to be removed, separated by `,`. and pass those recipes to + `RecipeList` component. 3. In `RecipeList`, - * If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in - to the tag. - * If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to add recipes - in to the tag. + * If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in + to the tag. + * If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to add recipes + in to the tag. The sequence diagram below shows how this feature works: ![](../docs/UML/Implementation/TagFunction/TagFunction.png) @@ -170,16 +175,65 @@ The current implementation: It is implemented through the following step: 1. When the user enters an input with the first word being `list`, the input is passed to the `Parser` component. -2. In `Parser`, `parseListRecipe()` is executed to identify whether user want to filter - by tag (`/t`), otherwise the list is filtered by name and ingredients, and whether +2. In `Parser`, `parseListRecipe()` is executed to identify whether user want to filter + by tag (`/t`), otherwise the list is filtered by name and ingredients, and whether there are many filters (`&`). All the filters is extracted out and passed to `RecipeList` component. 3. In `RecipeList`, `listRecipes()` is executed to filter all recipes that match the filters, and return the `recipeList`containing all relevant recipes to `ParserRecipe()`. The sequence diagram below shows how this feature works: + ![](../docs/UML/Implementation/ListFunction/ListFunction.png) +### Delete Recipes Feature + +The current implementation: +* deletes a single recipe by name or recipe's index in recipe list +* deletes a range of recipes +* deletes all recipes + +It is implemented through the following step: +1. When the user enters an input with the first word being `delete`, the input is passed to + the `Parser` component. +2. In `Parser`, `parseDeleteRecipe()` is executed to identify whether the user wants to delete all recipes, a single + recipe, or range of recipes. +3. In `RecipeList`, `deleteRecipe()` is executed to delete the recipe at whatever index is passed as a parameter, + and return the `Recipe` object at that index/the one just deleted. + +The sequence diagram below shows how this feature works: +{UML will be added here.} + +### Add Recipes Feature + +The current implementation: +* Add a single recipe in 1 line and followed by all the ingredients in next another line after being prompted. + +It is implemented through the following steps: +1. When the user enters an input with the first word being `add`, the input is passed to the `Parser` component. +2. In `Parser`, the `parseAddRecipe` is executed to identify whether the recipe is an already existing recipe or + it's a new recipe that is being added. +3. After the user enters the ingredients in 1 line, the input is passed to `parseIngredientName` which returns a + hashmap with the ingredient name as 'key' and quantity as 'value'. +4. After the recipe name and ingredients are accepted and processed, the input is sent to `recipeList.addRecipe()` + to store the new recipe data. + +### Edit Recipes Feature + +The current implementation: +* There are 3 ways to edit: + * Edit all ingredients. + * Edit 1 particular ingredient. + * Add new ingredient. + +It is implemented through the following steps: + +1. When the user enters an input with the first word being `edit`, the input is passed to the `Parser` component. +2. In `Parser`, the `parseEditRecipe` is executed to identify whether the recipe is an already existing recipe to make edits. +3. The user will then be prompted with 3 options as mentioned above to make edits to the recipe ingredients. +4. After the new ingredients are accepted and processed, the input is sent to `recipeList.editRecipe()` + to update the new recipe data. + --- ## Appendix: Requirements diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 8ec6fa330e..43f6bfdb3c 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -200,7 +200,7 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } // user inputted index of recipe in list } else { - // deleting a range of recipes + // check if deleting a range of recipes if (input[1].length() >= 3) { StringBuilder rangeRecipes = new StringBuilder(); int startIndex = Integer.parseInt(input[1].charAt(0) + ""); From eb273f333ce2feb4cbc34571fe24d52a804a815c Mon Sep 17 00:00:00 2001 From: jaredoong Date: Tue, 28 Mar 2023 21:05:08 +0800 Subject: [PATCH 124/252] Update Database Now includes database for ingredients and weeklyplan --- build.gradle | 13 ++- database/recipesDatabase.json | 1 + database/userIngredientsDatabase.json | 1 + database/weeklyPlanDatabase.json | 1 + src/main/java/seedu/meal360/Meal360.java | 56 ++++++++-- src/main/java/seedu/meal360/Ui.java | 5 +- .../seedu/meal360/{ => storage}/Database.java | 103 ++++++++---------- .../meal360/storage/JsonDatabaseHelper.java | 82 ++++++++++++++ .../meal360/storage/LocalDateJsonAdapter.java | 38 +++++++ .../storage/LocalDateTimeJsonAdapter.java | 39 +++++++ src/test/java/seedu/meal360/Meal360Test.java | 3 +- 11 files changed, 271 insertions(+), 71 deletions(-) create mode 100644 database/recipesDatabase.json create mode 100644 database/userIngredientsDatabase.json create mode 100644 database/weeklyPlanDatabase.json rename src/main/java/seedu/meal360/{ => storage}/Database.java (65%) create mode 100644 src/main/java/seedu/meal360/storage/JsonDatabaseHelper.java create mode 100644 src/main/java/seedu/meal360/storage/LocalDateJsonAdapter.java create mode 100644 src/main/java/seedu/meal360/storage/LocalDateTimeJsonAdapter.java diff --git a/build.gradle b/build.gradle index fae2e74093..8eec0184b2 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ repositories { } dependencies { - implementation 'com.google.code.gson:gson:2.10.1' + implementation 'com.google.code.gson:gson:2.8.9' 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' } @@ -42,7 +42,7 @@ checkstyle { toolVersion = '10.2' } -run{ +run { standardInput = System.in enableAssertions = true } @@ -56,3 +56,12 @@ jar { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } } + +tasks.withType(Copy).all { duplicatesStrategy 'exclude' } + +sourceSets { + main.java.srcDirs 'src/main/java' + main.resources.srcDirs 'src/main/resources' + test.java.srcDirs 'src/test/java' + test.resources.srcDirs 'src/test/resources' +} diff --git a/database/recipesDatabase.json b/database/recipesDatabase.json new file mode 100644 index 0000000000..0beacc58a3 --- /dev/null +++ b/database/recipesDatabase.json @@ -0,0 +1 @@ +[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file diff --git a/database/userIngredientsDatabase.json b/database/userIngredientsDatabase.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/database/userIngredientsDatabase.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/database/weeklyPlanDatabase.json b/database/weeklyPlanDatabase.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/database/weeklyPlanDatabase.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 28f701c8d1..b2d41fd694 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -4,6 +4,7 @@ import java.util.Scanner; import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; +import seedu.meal360.storage.Database; public class Meal360 { @@ -16,24 +17,43 @@ public class Meal360 { private static final Parser parser = new Parser(); private static final Database database = new Database(); private static RecipeList recipeList = new RecipeList(); - private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); + private static WeeklyPlan weeklyPlan = new WeeklyPlan(); + + private static IngredientList userIngredients = new IngredientList(); public static void startApp() { ui.printSeparator(); ui.printWelcomeMessage(); ui.printSeparator(); - // Load database - ui.printMessage("Loading database..."); + // Load databases try { - recipeList = database.loadDatabase(); - ui.printMessage("Database loaded successfully."); + ui.printMessage("Loading recipes..."); + recipeList = database.loadRecipesDatabase(); + ui.printMessage("Recipes loaded successfully."); } catch (Exception e) { - ui.printMessage("Error loading database, loading default database instead."); - ui.printMessage("Overwriting database with new default database..."); + ui.printMessage("Error loading recipes, loading default recipes instead."); recipeList = database.defaultRecipeList(); } + try { + ui.printMessage("Loading weekly plan..."); + weeklyPlan = database.loadWeeklyPlanDatabase(); + ui.printMessage("Weekly plan loaded successfully."); + } catch (Exception e) { + ui.printMessage("Error loading weekly plan, loading default empty weekly plan instead."); + weeklyPlan = new WeeklyPlan(); + } + + try { + ui.printMessage("Loading ingredients..."); + userIngredients = database.loadUserIngredientsDatabase(); + ui.printMessage("Ingredients loaded successfully."); + } catch (Exception e) { + ui.printMessage("Error loading ingredients, loading default empty list of ingredients instead."); + userIngredients = new IngredientList(); + } + ui.printSeparator(); } @@ -185,14 +205,32 @@ public static void exitApp() { ui.printSeparator(); // Save database - ui.printMessage("Saving database..."); + ui.printMessage("Saving recipes..."); try { - database.saveDatabase(recipeList); + database.saveRecipesDatabase(recipeList); ui.printMessage("Database saved successfully."); } catch (IOException error) { ui.printMessage("Error saving database."); } + // Save weekly plan + ui.printMessage("Saving weekly plan..."); + try { + database.saveWeeklyPlanDatabase(weeklyPlan); + ui.printMessage("Weekly plan saved successfully."); + } catch (IOException error) { + ui.printMessage("Error saving weekly plan."); + } + + // Save ingredients + ui.printMessage("Saving ingredients..."); + try { + database.saveIngredientsDatabase(userIngredients); + ui.printMessage("Ingredients saved successfully."); + } catch (IOException error) { + ui.printMessage("Error saving ingredients."); + } + ui.printGoodbyeMessage(); ui.printSeparator(); } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 60236a4bd9..fa1322b8d3 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -93,6 +93,9 @@ public void printHelp() { printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); printMessage("5. List All Recipes: list"); - printMessage("6. Exit: bye"); + printMessage("6. Add to Weekly Plan: add /r {recipe name} {quantity}"); + printMessage("7. Delete from Weekly Plan: delete /r {recipe name}"); + printMessage("8. View Weekly Plan: weeklyplan"); + printMessage("9. Exit: bye"); } } diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/storage/Database.java similarity index 65% rename from src/main/java/seedu/meal360/Database.java rename to src/main/java/seedu/meal360/storage/Database.java index a9ece4bbc0..0ec86df249 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/storage/Database.java @@ -1,70 +1,57 @@ -package seedu.meal360; - -import com.google.gson.Gson; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; +package seedu.meal360.storage; + import java.io.IOException; import java.util.HashMap; +import seedu.meal360.IngredientList; +import seedu.meal360.Recipe; +import seedu.meal360.RecipeList; +import seedu.meal360.WeeklyPlan; public class Database { private static final String recipesDatabaseFilepath = - "." + System.getProperty("file.separator") + "src" + System.getProperty("file.separator") + "main" - + System.getProperty("file.separator") + "resources" + System.getProperty( - "file.separator") + "recipesDatabase.json"; - - public RecipeList loadDatabase() throws IOException { - RecipeList database; - Gson gson = new Gson(); - - // Check if the JSON file exists and create one if it does not - File file = new File(recipesDatabaseFilepath); - if (!file.exists()) { - try { - // Create the parent directory if it does not exist - File parentDir = file.getParentFile(); - if (!parentDir.exists()) { - parentDir.mkdirs(); - } - file.createNewFile(); - } catch (IOException e) { - throw new IOException("Error creating database file."); - } + "." + System.getProperty("file.separator") + "database" + System.getProperty("file.separator") + + "recipesDatabase.json"; + + private static final String weeklyPlanDatabaseFilepath = + "." + System.getProperty("file.separator") + "database" + System.getProperty("file.separator") + + "weeklyPlanDatabase.json"; + + private static final String userIngredientsDatabaseFilepath = + "." + System.getProperty("file.separator") + "database" + System.getProperty( + "file.separator") + "userIngredientsDatabase.json"; + + JsonDatabaseHelper recipeListJsonDatabaseHelper = new JsonDatabaseHelper<>( + recipesDatabaseFilepath, defaultRecipeList(), RecipeList.class); + + JsonDatabaseHelper weeklyPlanJsonDatabaseHelper = new JsonDatabaseHelper<>( + weeklyPlanDatabaseFilepath, new WeeklyPlan(), WeeklyPlan.class); + + JsonDatabaseHelper userIngredientsJsonDatabaseHelper = new JsonDatabaseHelper<>( + userIngredientsDatabaseFilepath, new IngredientList(), IngredientList.class); + + public RecipeList loadRecipesDatabase() throws IOException { + return recipeListJsonDatabaseHelper.loadDatabase(); + } + + public void saveRecipesDatabase(RecipeList recipeList) throws IOException { + recipeListJsonDatabaseHelper.saveDatabase(recipeList); + } + + public WeeklyPlan loadWeeklyPlanDatabase() throws IOException { + return weeklyPlanJsonDatabaseHelper.loadDatabase(); + } + + public void saveWeeklyPlanDatabase(WeeklyPlan weeklyPlan) throws IOException { + weeklyPlanJsonDatabaseHelper.saveDatabase(weeklyPlan); + } - // Return a default recipe list if database file does not exist - return defaultRecipeList(); - } - - // Read the JSON data from the file if it already exists - try { - // Read the JSON data from the file - BufferedReader reader = new BufferedReader(new FileReader(recipesDatabaseFilepath)); - database = gson.fromJson(reader, RecipeList.class); - reader.close(); - } catch (FileNotFoundException e) { - throw new FileNotFoundException("Unable to find database file."); - } catch (IOException e) { - throw new IOException("Error reading from database file."); - } - - // Ensure non empty recipeList is returned - if (database == null) { - return defaultRecipeList(); - } else { - return database; - } + public IngredientList loadUserIngredientsDatabase() throws IOException { + return userIngredientsJsonDatabaseHelper.loadDatabase(); } - public void saveDatabase(RecipeList recipeList) throws IOException { - Gson gson = new Gson(); - // Write the data object to the JSON file - FileWriter writer; - writer = new FileWriter(recipesDatabaseFilepath); - gson.toJson(recipeList, writer); - writer.close(); + public void saveIngredientsDatabase(IngredientList userIngredients) throws IOException { + userIngredientsJsonDatabaseHelper.saveDatabase(userIngredients); } public RecipeList defaultRecipeList() { diff --git a/src/main/java/seedu/meal360/storage/JsonDatabaseHelper.java b/src/main/java/seedu/meal360/storage/JsonDatabaseHelper.java new file mode 100644 index 0000000000..aa8934796d --- /dev/null +++ b/src/main/java/seedu/meal360/storage/JsonDatabaseHelper.java @@ -0,0 +1,82 @@ +package seedu.meal360.storage; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class JsonDatabaseHelper { + + private final String databaseFilepath; + private final T defaultObject; + private final Class objectType; + private final Gson gson; + + public JsonDatabaseHelper(String databaseFilepath, T defaultObject, Class objectType) { + this.databaseFilepath = databaseFilepath; + this.defaultObject = defaultObject; + this.objectType = objectType; + + // Register the LocalDateTimeJsonAdapter and LocalDateJsonAdapter with Gson + this.gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, + LocalDateTimeJsonAdapter.INSTANCE) + .registerTypeAdapter(LocalDate.class, LocalDateJsonAdapter.INSTANCE).create(); + } + + public T loadDatabase() throws IOException { + T database; + Gson gson = new Gson(); + + // Check if the JSON file exists and create one if it does not + File file = new File(databaseFilepath); + if (!file.exists()) { + try { + // Create the parent directory if it does not exist + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + file.createNewFile(); + } catch (IOException e) { + throw new IOException("Error creating database file."); + } + + // Return a default object if database file does not exist + return defaultObject; + } + + // Read the JSON data from the file if it already exists + try { + // Read the JSON data from the file + BufferedReader reader = new BufferedReader(new FileReader(databaseFilepath)); + database = gson.fromJson(reader, objectType); + reader.close(); + } catch (FileNotFoundException e) { + throw new FileNotFoundException("Unable to find database file."); + } catch (IOException e) { + throw new IOException("Error reading from database file."); + } + + // Ensure non-empty object is returned + if (database == null) { + return defaultObject; + } else { + return database; + } + } + + public void saveDatabase(T dataObject) throws IOException { + Gson gson = new Gson(); + // Write the data object to the JSON file + FileWriter writer; + writer = new FileWriter(databaseFilepath); + gson.toJson(dataObject, writer); + writer.close(); + } +} diff --git a/src/main/java/seedu/meal360/storage/LocalDateJsonAdapter.java b/src/main/java/seedu/meal360/storage/LocalDateJsonAdapter.java new file mode 100644 index 0000000000..232bdda8b7 --- /dev/null +++ b/src/main/java/seedu/meal360/storage/LocalDateJsonAdapter.java @@ -0,0 +1,38 @@ +package seedu.meal360.storage; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public final class LocalDateJsonAdapter implements JsonSerializer, JsonDeserializer { + + public static final LocalDateJsonAdapter INSTANCE = new LocalDateJsonAdapter(); + + private LocalDateJsonAdapter() { + } + + @Override + public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (!json.isJsonNull()) { + return LocalDate.parse(json.getAsString(), DateTimeFormatter.ISO_LOCAL_DATE); + } + return null; + } + + @Override + public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) { + if (src != null) { + return new JsonPrimitive(src.format(DateTimeFormatter.ISO_LOCAL_DATE)); + } + return JsonNull.INSTANCE; + } +} diff --git a/src/main/java/seedu/meal360/storage/LocalDateTimeJsonAdapter.java b/src/main/java/seedu/meal360/storage/LocalDateTimeJsonAdapter.java new file mode 100644 index 0000000000..d1f8e67ed4 --- /dev/null +++ b/src/main/java/seedu/meal360/storage/LocalDateTimeJsonAdapter.java @@ -0,0 +1,39 @@ +package seedu.meal360.storage; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public final class LocalDateTimeJsonAdapter implements JsonSerializer, + JsonDeserializer { + + public static final LocalDateTimeJsonAdapter INSTANCE = new LocalDateTimeJsonAdapter(); + + private LocalDateTimeJsonAdapter() { + } + + @Override + public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (!json.isJsonNull()) { + return LocalDateTime.parse(json.getAsString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME); + } + return null; + } + + @Override + public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) { + if (src != null) { + return new JsonPrimitive(src.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + } + return JsonNull.INSTANCE; + } +} diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 5dca965305..288605bf22 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -14,6 +14,7 @@ import org.junit.jupiter.api.Test; import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; +import seedu.meal360.storage.Database; class Meal360Test { @@ -314,6 +315,6 @@ public void testListRecipe() { @Test public void testLoadDatabase() { - assertDoesNotThrow(database::loadDatabase); + assertDoesNotThrow(database::loadRecipesDatabase); } } From cf03e593e46ef5afce74a3810c169c62a11736ea Mon Sep 17 00:00:00 2001 From: JuneNita Date: Wed, 29 Mar 2023 12:03:55 +0800 Subject: [PATCH 125/252] add 'random function' and make it more readable --- src/main/java/seedu/meal360/Meal360.java | 23 ++-- src/main/java/seedu/meal360/Parser.java | 113 +++++++++++++------ src/main/java/seedu/meal360/RecipeList.java | 96 +++++++++++----- src/test/java/seedu/meal360/Meal360Test.java | 4 +- text-ui-test/EXPECTED.TXT | 51 ++++++++- text-ui-test/input.txt | 19 +++- 6 files changed, 224 insertions(+), 82 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 271f5d9931..73dc07a291 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -76,10 +76,8 @@ public static void receiveInput(String input) { ui.printSeparator(); RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); ui.listRecipe(recipeListToPrint); - } catch (IllegalArgumentException e) { - String errorMessage = - "Please enter the command in the valid format. Some arguments might " + "be missing."; - ui.printMessage(errorMessage); + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { + ui.printMessage(e.getMessage()); } ui.printSeparator(); } else if (command[0].equals("add")) { @@ -125,12 +123,17 @@ public static void receiveInput(String input) { ui.printSeparator(); String tag = parser.parseTagRecipe(command, recipeList); ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); - } catch (IllegalArgumentException e) { - String errorMessage = "Please enter the command in the correct format."; - ui.printMessage(errorMessage); - } catch (IndexOutOfBoundsException e) { - String errorMessage = "Sorry, I am unable to find the recipes you entered."; - ui.printMessage(errorMessage); + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("random")) { + ui.printSeparator(); + try { + Recipe randomRecipe = parser.parseRandomRecipe(recipeList); + ui.printRecipe(randomRecipe); + } catch (NumberFormatException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); } ui.printSeparator(); } else if (command[0].equals("weekly")) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 43f6bfdb3c..d56e54c855 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -223,41 +223,54 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { public String parseTagRecipe(String[] inputs, RecipeList recipeList) { String tag; - if (inputs.length == 1) { + boolean isOnlyTagWordInCommand = inputs.length == 1; + boolean isAddTag; + boolean isRemoveTag; + + if (isOnlyTagWordInCommand) { throw new IllegalArgumentException("Please indicate at least a tag and a recipe."); + } + + StringBuilder commandString = new StringBuilder(inputs[1]); + for (int i = 2; i < inputs.length; i++) { + commandString.append(" ").append(inputs[i]); + } + + isAddTag = commandString.indexOf(">>") == -1 && commandString.indexOf("<<") != -1; + isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; + + if (!(isAddTag || isRemoveTag)) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } else if (isAddTag) { + tag = parseAddRecipeTag(commandString.toString(), recipeList); + } else if (isRemoveTag) { + tag = parseRemoveRecipeTag(commandString.toString(), recipeList); } else { - StringBuilder commandString = new StringBuilder(inputs[1]); - for (int i = 2; i < inputs.length; i++) { - commandString.append(" ").append(inputs[i]); - } - boolean isAddTag = commandString.indexOf("<<") != -1 && commandString.indexOf(">>") == -1; - boolean isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; - if (!(isAddTag || isRemoveTag)) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } else if (isAddTag) { - tag = parseAddRecipeTag(commandString.toString(), recipeList); - } else if (isRemoveTag) { - tag = parseRemoveRecipeTag(commandString.toString(), recipeList); - } else { - throw new IllegalArgumentException("Invalid command."); - } + throw new IllegalArgumentException("Invalid command."); } return tag; } public String parseAddRecipeTag(String command, RecipeList recipeList) { String tag; + Recipe recipe; + String[] recipesToTag; + boolean isUnableToFindTheRecipe; String[] args = command.trim().split("<<"); - if (args.length < 2) { + boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); + + if (isNotEnoughArgs) { throw new IllegalArgumentException("Please enter the command in the correct format."); } + tag = args[0].trim(); - String[] recipesToTag = args[1].split(","); + recipesToTag = args[1].split("&&"); for (String recipeName : recipesToTag) { recipeName = recipeName.trim(); - Recipe recipe = recipeList.findByName(recipeName); - if (recipe == null) { - throw new IndexOutOfBoundsException("Unable to find the recipe."); + recipe = recipeList.findByName(recipeName); + isUnableToFindTheRecipe = recipe == null; + if (isUnableToFindTheRecipe) { + throw new IndexOutOfBoundsException("Unable to find the recipe: \"" + recipeName +"\"."); } recipeList.addRecipeToTag(tag, recipe); } @@ -266,17 +279,31 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) { public String parseRemoveRecipeTag(String command, RecipeList recipeList) { String tag; + Recipe recipe; + String[] recipesToRemove; + boolean isUnableToFindTag; + boolean isUnableToFindTheRecipe; String[] args = command.trim().split(">>"); - if (args.length < 2) { + boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); + + if (isNotEnoughArgs) { throw new IllegalArgumentException("Please enter the command in the correct format."); } + tag = args[0].trim(); - String[] recipesToTag = args[1].split(","); - for (String recipeName : recipesToTag) { + isUnableToFindTag = !recipeList.tags.containsKey(tag); + if (isUnableToFindTag) { + throw new IndexOutOfBoundsException("There is no \"" + tag + "\" tag found. Please make sure you have " + + "entered the correct tag."); + } + + recipesToRemove = args[1].split("&&"); + for (String recipeName : recipesToRemove) { recipeName = recipeName.trim(); - Recipe recipe = recipeList.findByName(recipeName); - if (recipe == null) { - throw new IndexOutOfBoundsException("Unable to find the recipe."); + recipe = recipeList.findByName(recipeName); + isUnableToFindTheRecipe = recipe == null; + if (isUnableToFindTheRecipe) { + throw new IndexOutOfBoundsException("Unable to find the recipe: \"" + recipeName +"\"."); } recipeList.removeRecipeFromTag(tag, recipe); } @@ -285,25 +312,31 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) { public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { String[] filters; + RecipeList recipeListToPrint; + boolean hasTagArgs = inputs.length > 2; + boolean isOnlyListWordInCommand = inputs.length == 1; boolean isTag = false; - if (inputs.length == 1) { + int firstArgsIndex = 1; + + if (isOnlyListWordInCommand) { filters = null; } else { - int firstArgsIndex = 1; - if (inputs[1].equals("/t")) { - if (inputs.length == 2) { - throw new IllegalArgumentException("argument is missing."); - } + isTag = inputs[1].equals("/t"); + if (isTag && !hasTagArgs) { + throw new IllegalArgumentException("Please include at least a tag."); + } else if (isTag) { firstArgsIndex = 2; - isTag = true; } + StringBuilder filterString = new StringBuilder(inputs[firstArgsIndex]); for (int i = firstArgsIndex + 1; i < inputs.length; i++) { filterString.append(" ").append(inputs[i]); } - filters = filterString.toString().split("&"); + + filters = filterString.toString().split("&&"); } - return recipeList.listRecipes(filters, isTag); + recipeListToPrint = recipeList.listRecipes(filters, isTag); + return recipeListToPrint; } public Recipe parseViewRecipe(String[] command, RecipeList recipes) { @@ -341,6 +374,14 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { return recipes.get(recipeIndex - 1); } + public Recipe parseRandomRecipe(RecipeList recipes) { + Recipe randomRecipe = recipes.randomRecipe(); + if (recipes.size() == 0) { + throw new NullPointerException("There is no recipe in the list to random"); + } + return randomRecipe; + } + public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) throws InvalidRecipeNameException, InvalidNegativeValueException { WeeklyPlan updatedWeeklyPlan; diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 85c30a8402..dc688edce5 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -2,9 +2,10 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Random; public class RecipeList extends ArrayList { - private HashMap> tags = new HashMap>(); + public HashMap> tags = new HashMap<>(); public Recipe findByName(String name) { for (Recipe recipe : this) { @@ -30,55 +31,90 @@ public Recipe deleteRecipe(int recipeNum) { } public void addRecipeToTag(String tag, Recipe recipe) { - if (tags.containsKey(tag)) { - tags.get(tag).add(recipe); + boolean hasTag = tags.containsKey(tag); + int tagDummy = 0; + if (hasTag) { + tags.get(tag).put(recipe, tagDummy); } else { - assert !tags.containsKey(tags); - ArrayList tagRecipes = new ArrayList(); - tagRecipes.add(recipe); + assert !tags.containsKey(tag); + HashMap tagRecipes = new HashMap<>(); + tagRecipes.put(recipe, tagDummy); tags.put(tag, tagRecipes); assert tags.size() > 0 : "tag's size is still 0."; } } public void removeRecipeFromTag(String tag, Recipe recipe) { - if (!tags.containsKey(tag)) { - throw new IndexOutOfBoundsException("Invalid tag"); - } else { - ArrayList tagRecipeList = tags.get(tag); - for (int i = 0; i < tagRecipeList.size(); i++) { - Recipe recipeInTag = tagRecipeList.get(i); - if (recipe.getName().equals(recipeInTag.getName())) { - tagRecipeList.remove(i); - } - } - } + HashMap tagRecipeList = tags.get(tag); + tagRecipeList.remove(recipe); } public RecipeList listRecipes(String[] filters, boolean isTag) { RecipeList filteredRecipeList = new RecipeList(); - if (filters == null) { + boolean isNoFilter = filters == null; + boolean isNotPassTheFilter; + + if (isTag) { + filteredRecipeList = this.listTagRecipes(filters); + } + if (!isTag && isNoFilter) { return this; } - if (isTag) { - for (String filter : filters) { - filter = filter.trim(); - ArrayList tagRecipes = this.tags.get(filter); - if (tagRecipes != null) { - filteredRecipeList.addAll(this.tags.get(filter)); + if (!isTag) { + for (Recipe recipe : this) { + filteredRecipeList.add(recipe); + for (String filter : filters) { + filter = filter.trim(); + isNotPassTheFilter = !recipe.getName().contains(filter) && + !recipe.getIngredients().containsKey(filter); + if (isNotPassTheFilter) { + filteredRecipeList.remove(recipe); + } } } - return filteredRecipeList; } - for (Recipe recipe : this) { - filteredRecipeList.add(recipe); - for (String filter : filters) { - filter = filter.trim(); - if (!recipe.getName().contains(filter) && !recipe.getIngredients().containsKey(filter)) { + return filteredRecipeList; + } + + public RecipeList listTagRecipes(String[] filters) { + RecipeList filteredRecipeList = new RecipeList(); + HashMap tagRecipes; + boolean hasNoRecipeInTheTag; + boolean hasNoRecipeToReturn; + boolean isNotFoundTag; + + //add all recipe from first tag to the list + isNotFoundTag = !this.tags.containsKey(filters[0].trim()); + if (isNotFoundTag) { + throw new NullPointerException("There is no \"" + filters[0] + "\" tag found. Please make sure you have " + + "entered the correct tag."); + } + this.tags.get(filters[0].trim()).forEach((recipe, dummy) -> filteredRecipeList.add(recipe)); + + for (String filter : filters) { + filter = filter.trim(); + tagRecipes = this.tags.get(filter); + hasNoRecipeInTheTag = tagRecipes == null; + hasNoRecipeToReturn = filteredRecipeList.size() == 0; + + if (hasNoRecipeInTheTag) { + continue; + } + if (hasNoRecipeToReturn) { + return filteredRecipeList; + } + for (Recipe recipe : filteredRecipeList) { + if (!tagRecipes.containsKey(recipe)) { filteredRecipeList.remove(recipe); } } } return filteredRecipeList; } + + public Recipe randomRecipe() { + Random random = new Random(); + Recipe randomRecipe = this.get(random.nextInt(this.size())); + return randomRecipe; + } } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 5dca965305..37f61f61f5 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -301,13 +301,13 @@ public void testListRecipe() { assertEquals(4, recipeListToPrint.get(0).getNumOfIngredients()); assertEquals("pizza", recipeListToPrint.get(0).getName()); - inputs = new String[]{"list", "salad", "&", "tomato"}; + inputs = new String[]{"list", "salad", "&&", "tomato"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(1, recipeListToPrint.size()); assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); assertEquals("salad", recipeListToPrint.get(0).getName()); - inputs = new String[]{"list", "salad", "&", "pizza"}; + inputs = new String[]{"list", "salad", "&&", "pizza"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(0, recipeListToPrint.size()); } diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 244da9d06a..d7cff059e5 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -23,6 +23,46 @@ Welcome to Meal360, your ultimate Recipe Manager! | 10. Buffalo Chicken Mac 'n' Cheese (8 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- +| Please include at least a tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is no "random tag" tag found. Please make sure you have entered the correct tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is no "/t" tag found. Please make sure you have entered the correct tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| These are the recipes you have (1 recipes): | +| 1. Italian sausage orzo soup (13 ingredients) | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| There is no "tag#1" tag found. Please make sure you have entered the correct tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please include at least a tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please enter the command in the correct format. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| You have modified the recipe(s) in this "tag#1" tag. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- | You have modified the recipe(s) in this "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- @@ -30,10 +70,14 @@ Welcome to Meal360, your ultimate Recipe Manager! | 1. Avocado toast (5 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please enter the command in the valid format. Some arguments might be missing. | +| These are the recipes you have (1 recipes): | +| 1. Avocado toast (5 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| There is nothing to list. | +| Please enter the command in the correct format. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| You have modified the recipe(s) in this "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | You have modified the recipe(s) in this "tag#1" tag. | @@ -42,6 +86,9 @@ Welcome to Meal360, your ultimate Recipe Manager! | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- +| There is nothing to list. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You did not enter a recipe number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 7fa2749f5e..b3b2c08e00 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,10 +1,25 @@ list -tag tag#1 << avocado toast -list /t tag#1 list /t +list /t random tag +list /t /t list apple +list soup && apple +list soup apple +list soup +list soup /t +list soup && /t +list /t tag#1 +list /t +tag tag#1 << avocado toast >> +tag tag#1 << avocado toast << +tag tag#1 << avocado toast +list /t tag#1 +list /t tag#1 && tag#2 +tag tag#1 >> avocado toast << +tag tag#1 >> avocado toast >> tag tag#1 >> avocado toast list /t tag#1 +list /t tag#1 && tag#2 /t view view 1 view -2 From 75f985148079f33c97e9634256b12f3ee2795e17 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Wed, 29 Mar 2023 15:14:38 +0800 Subject: [PATCH 126/252] update error message --- src/main/java/seedu/meal360/Parser.java | 29 ++++++++++++++++----- src/main/java/seedu/meal360/RecipeList.java | 10 ++++++- text-ui-test/EXPECTED.TXT | 11 ++++---- text-ui-test/input.txt | 6 ++--- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index d56e54c855..db108cc4a9 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -270,7 +270,11 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) { recipe = recipeList.findByName(recipeName); isUnableToFindTheRecipe = recipe == null; if (isUnableToFindTheRecipe) { - throw new IndexOutOfBoundsException("Unable to find the recipe: \"" + recipeName +"\"."); + String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + + "successfully added from the tag."; + throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } recipeList.addRecipeToTag(tag, recipe); } @@ -282,7 +286,7 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) { Recipe recipe; String[] recipesToRemove; boolean isUnableToFindTag; - boolean isUnableToFindTheRecipe; + boolean isNoRecipeInTheList; String[] args = command.trim().split(">>"); boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); @@ -301,11 +305,24 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) { for (String recipeName : recipesToRemove) { recipeName = recipeName.trim(); recipe = recipeList.findByName(recipeName); - isUnableToFindTheRecipe = recipe == null; - if (isUnableToFindTheRecipe) { - throw new IndexOutOfBoundsException("Unable to find the recipe: \"" + recipeName +"\"."); + isNoRecipeInTheList = recipe == null; + if (isNoRecipeInTheList) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } + + try { + recipeList.removeRecipeFromTag(tag, recipe); + } catch (IndexOutOfBoundsException e) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } - recipeList.removeRecipeFromTag(tag, recipe); } return tag; } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index dc688edce5..620f6e1d4f 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -46,6 +46,14 @@ public void addRecipeToTag(String tag, Recipe recipe) { public void removeRecipeFromTag(String tag, Recipe recipe) { HashMap tagRecipeList = tags.get(tag); + boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); + if (!isAbleToFindTheRecipe) { + String errorMessage1 = "Unable to find the recipe: \"" + recipe.getName() +"\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipe.getName() +"\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } tagRecipeList.remove(recipe); } @@ -98,7 +106,7 @@ public RecipeList listTagRecipes(String[] filters) { hasNoRecipeToReturn = filteredRecipeList.size() == 0; if (hasNoRecipeInTheTag) { - continue; + throw new NullPointerException("There is nothing to list."); } if (hasNoRecipeToReturn) { return filteredRecipeList; diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index d7cff059e5..06829dde54 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -63,24 +63,25 @@ Welcome to Meal360, your ultimate Recipe Manager! | You have modified the recipe(s) in this "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| I'm sorry, but I don't know what that means :-( | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes): | | 1. Avocado toast (5 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes): | -| 1. Avocado toast (5 ingredients) | +| There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter the command in the correct format. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| Unable to find the recipe: "strawberry" in the tag. | +| All the recipe before "strawberry" (if any) are successfully removed from the tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| Unable to find the recipe: "avocado toast" in the tag. | +| All the recipe before "avocado toast" (if any) are successfully removed from the tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | There is nothing to list. | diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index b3b2c08e00..8e0aaf32c1 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -12,12 +12,12 @@ list /t tag#1 list /t tag tag#1 << avocado toast >> tag tag#1 << avocado toast << -tag tag#1 << avocado toast +c list /t tag#1 list /t tag#1 && tag#2 tag tag#1 >> avocado toast << -tag tag#1 >> avocado toast >> -tag tag#1 >> avocado toast +tag tag#1 >> avocado toast && strawberry>> +tag tag#1 >> avocado toast && strawberry list /t tag#1 list /t tag#1 && tag#2 /t view From 4c743da2837d222621eaff34237a76e884b23578 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Wed, 29 Mar 2023 15:43:04 +0800 Subject: [PATCH 127/252] update UserGuide --- docs/UserGuide.md | 100 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 63cc49ff93..01c5c9050c 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -15,11 +15,13 @@ ___ ## Features -* View recipes -* Listing relevant recipes -* Add recipes to weekly plan -* Remove recipes from weekly plan -* View weekly plan +* [View recipes](#viewing-recipes--view) +* [List relevant recipes](#listing-recipes--list) +* [Tag/Categorise recipes](#taggingcategorising-recipes--tag) +* [Add recipes to weekly plan](#adding-to-this-weeks-plan--weekly-add) +* [Remove recipes from weekly plan](#deleting-from-this-weeks-plan--weekly-delete) +* [View weekly plan](#view-this-weeks-plan--weeklyplan) +* [Random a recipe](#random-a-recipe--random) ### Adding recipes: `add` @@ -54,17 +56,25 @@ Example of usage: List all recipes or filtered list recipes by the name or ingredients. -Format: `list [KEYWORD & KEYWORD & ...]` +Format: `list [/t] [KEYWORD && KEYWORD && ...]` -* The `KEYWORD` is optional. It can be a name of recipe or ingredients. -* To list all recipes, do not add `KEYWORD`. -* Use `&` to list all the recipe that contain all specified keywords. + +* The `KEYWORD` and `/t` are optional. +* `KEYWORD` can be a name of recipe or ingredients or tag. +* If user want to list recipes from tags `/t` is required. When `/t` is used, +at least one `KEYWORD`, replacing by the tag name, is required. +* To list all recipes, do not add `KEYWORD` and `/t`. +* Use `&&` to list all the recipe that contain **all** specified `KEYWORD`. Example of usage: -`list` -`list pizza` -`list milk & egg` +* `list` lists all the recipes. +* `list pizza` lists recipes that contain 'pizza' in the name or ingredients. +* `list milk && egg` lists recipes that contain __both__ 'milk' and 'egg' in the +name or ingredients. +* `list /t western` lists the recipes that are in 'western' tag. +* `list /t western && chinese` lists recipes that is under __both__ 'western' and +'chinese' tag. ### Viewing recipes: `view` @@ -97,6 +107,43 @@ Example of usage: `delete r/pizza` `delete r/all` +### Tagging/Categorising recipes: `tag` +__Categorize recipes into a specific tag__ + +Adding one or more recipes into a tag. + +Format: `tag LABEL << [RECIPE_NAME && RECIPE_NAME && ...]` + +* `LABEL` is required, and replace with the tag label that user want to +add the recipes into. This is case-sensitive. +* At least one `RECIPE_NAME` is required. +* To add multiple recipes into the tag, use `&&` followed by next `RECIPE_NAME`. + +Example of usage: + +* `tag western << burger` adds burger into 'western' tag. +* `tag junk foods << burger && hotdog` adds burger and hotdog into 'junk foods' tag. +* `tag breakfast << milk && boiled egg && bread` adds milk, boiled egg and +bread into 'breakfast' tag. + +__Removing recipes form a tag__ + +Remove recipes from a specific tag. + +Format: `tag LABEL >> [RECIPE_NAME && RECIPE_NAME && ...]` + +* `LABEL` is required, and replace with the tag label that user want to + remove the recipes from. This is case-sensitive. +* At least one `RECIPE_NAME` is required. +* To remove multiple recipes from the tag, use `&&` followed by next `RECIPE_NAME`. + +Example of usage: + +* `tag western>> burger` removes burger from 'western' tag. +* `tag junk foods >> burger && hotdog` remove burger and hotdog from 'junk foods' tag. +* `tag breakfast >> milk && boilded egg && bread` removes milk, boiled egg, and bread +from 'breakfast' tag. + ### Adding to this week's plan: `weekly /add` @@ -145,6 +192,15 @@ View this week's ingredients. Format: `weeklyingredients` +### Random a recipe: `random` + +Random a recipe from all the recipes that user have, and show the list of +ingredients and their quantities for a recipe. + +Format: `random` + + + ### Exit the program: `bye` Exits the program. @@ -158,12 +214,14 @@ Format: `bye` **A**: {your answer here} ## Command Summary -| Action | Format, Examples | -|--------|---------------------------------------| -|Add recipe | `add /r [recipe_name]`
e.g `add /r chicken rice` | -|Edit recipe | `edit /r [recipe_name]`
e.g `edit /r chicken rice` | -|List recipe | `list [KEYWORD]`
e.g `list pizza` | -|View recipe | `view INDEX`
e.g `view 1` | -|Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | -|Delete from weekly plan | `weekly /delete RECIPE NAME`
e.g `weekly /delete pizza` | -|View weekly plan | `weeklyplan` | +| Action | Format, Examples | +|------------------------------------|------------------------------------------------------------------| +| Add recipe | `add /r [recipe_name]`
e.g `add /r chicken rice` | +| Edit recipe | `edit /r [recipe_name]`
e.g `edit /r chicken rice` | +| List recipe | `list [/t] [KEYWORD]`
e.g `list pizza` | +| View recipe | `view INDEX`
e.g `view 1` | +| Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | +| Remove tag/Categorise from recipes | `tag LABEL >> RECIPE_NAME`
e.g `tag western >> pizza` | +| Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | +| Delete from weekly plan | `weekly /delete RECIPE NAME`
e.g `weekly /delete pizza` | +| View weekly plan | `weeklyplan` | From a84fb95399306db4e072e472c0c7d7d46ddc40fb Mon Sep 17 00:00:00 2001 From: JuneNita Date: Wed, 29 Mar 2023 18:02:39 +0800 Subject: [PATCH 128/252] update develop guide --- docs/DeveloperGuide.md | 60 ++++++--- .../ListFunction/ListFunction.png | Bin 12796 -> 17039 bytes .../TagFunction/TagFunction.drawio | 123 +++++++++++++++++- .../TagFunction/TagFunction.png | Bin 32388 -> 46831 bytes .../randomFunction/randomFunction.drawio | 49 +++++++ .../randomFunction/randomFunction.png | Bin 0 -> 17610 bytes 6 files changed, 215 insertions(+), 17 deletions(-) create mode 100644 docs/UML/Implementation/randomFunction/randomFunction.drawio create mode 100644 docs/UML/Implementation/randomFunction/randomFunction.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 79b4a660ff..157739c80e 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -78,7 +78,8 @@ The `RecipeList` component: * allows users to edit the existing recipes * allows users to view the entire list of recipes * allows users to view the ingredients required for a recipe -* allows users to tag single or multiple recipes from the recipe list for filtering +* allows users to add and remove recipes from a tag +* allows users to random a recipe from all the recipes that users have ### WeeklyPlan Component @@ -139,31 +140,34 @@ The activity diagram below shows how the `Database` component works at start up: * [List Recipes Feature](#list-recipes-feature) * [Add Recipes Feature](#add-recipes-feature) * [Edit Recipes Feature](#edit-recipes-feature) +* [Random a Recipe Feature](#random-a-recipe-feature) ### Categorise/Tag Recipes Feature The current implementation: -* add recipes into a tag -* remove recipes from a tag +* add single or multiples recipes into a tag +* remove single or multiples recipes from a tag It is implemented through the following step: 1. When the user enters an input with the first word being `tag`, the input is passed to the `Parser` component. 2. In `Parser`, `parseTagRecipe()` is executed to identify whether user want to add recipes to a tag (`<<`), or remove recipes from a tag(`>>`). Then, - * If user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to extract - the all the recipes to be added, separated by `,`. and pass those recipes to `RecipeList` + * If `isAddTag`, user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to extract + the all the recipes to be added, separated by `&&`, and pass those recipes and tag label to `RecipeList` component. - * If user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be executed to - extract the all the recipes to be removed, separated by `,`. and pass those recipes to + * If `isRemoveTag`, user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be executed to + extract the all the recipes to be removed, separated by `&&`, and pass those recipes and tag label to `RecipeList` component. + * If user enter invalid command, an error message will be thrown. 3. In `RecipeList`, * If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in to the tag. - * If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to add recipes - in to the tag. + * If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to remove recipes + from the tag. The sequence diagram below shows how this feature works: + ![](../docs/UML/Implementation/TagFunction/TagFunction.png) ### List Recipes Feature @@ -175,13 +179,22 @@ The current implementation: It is implemented through the following step: 1. When the user enters an input with the first word being `list`, the input is passed to the `Parser` component. -2. In `Parser`, `parseListRecipe()` is executed to identify whether user want to filter - by tag (`/t`), otherwise the list is filtered by name and ingredients, and whether - there are many filters (`&`). All the filters is extracted out and passed to `RecipeList` - component. -3. In `RecipeList`, `listRecipes()` is executed to filter all recipes that match the filters, - and return the `recipeList`containing all relevant recipes to `ParserRecipe()`. - +2. In `Parser`, `parseListRecipe()` is executed to first identify whether user want to filter + by tag (`/t`). + * If user filters the recipes by tag (`/t`), `isTag` is set to `true`. + * Otherwise, `isTag` is set to `false`. + + Then, it will extract all the filters separated by `&&`, if any. All the filters are + extracted out and passed to `RecipeList`component. +3. In `RecipeList`, `listRecipes()` is executed to first identify whether user want to + filter by tag. + * If `isTag` is true, `listTagRecipes()` is called to filter all recipes that meet + all the filters by tag, and return the `recipeList` containing all relevant recipes to `listRecipes()` + and `ParserRecipe()`, respectively. + * If user `isTag` is false, it filters all recipes that meet all the filters by name + and ingredients, and return `recipeList` containing all relevant recipes to + `ParselistRecipe()`. + The sequence diagram below shows how this feature works: ![](../docs/UML/Implementation/ListFunction/ListFunction.png) @@ -234,6 +247,21 @@ It is implemented through the following steps: 4. After the new ingredients are accepted and processed, the input is sent to `recipeList.editRecipe()` to update the new recipe data. +### Random a Recipe Feature + +The current implementation: +* randomly pick a recipe and display to the user + +It is implemented through the following step: +1. When the user enters an input with the first word being `random`, the `Parser` + component will be executed. +2. In `Parser`, `parseRandomRecipe()` is executed and call `randomRecipe()` in + `RecipeList` component. +3. In `RecipeList`, `randomRecipe()` is executed to random a recipe and return a + `recipe` to `parseRandomRecipe()`. + +The sequence diagram below shows how this feature works: +![](../docs/UML/Implementation/RandomFunction/RandomFunction.png) --- ## Appendix: Requirements diff --git a/docs/UML/Implementation/ListFunction/ListFunction.png b/docs/UML/Implementation/ListFunction/ListFunction.png index 558159798935fb2ef0cdc9bc8adec7b069f4ec53..847b360464cf0f58c66c6e98fc6890b73f36cd7e 100644 GIT binary patch literal 17039 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�fJT;J|ct+~^FYUlv<8uSlrPyP%;atfSOy~PHgFa4kkY7M#%w`4%|gyXko z(Vv-BU?R%fE@q!b$Xg>kr_&fohF0A9rxm{VP<1?UQtY9<9J8Xu8PGJS*0bx9^I+HO zD}Cxz%R{E+x~!rW+E)G(8jCNjR$|I#G6*7F0zZKYdY9JeB=#IRp~ZL1sQbz}4{I7v zXf!=)HSYE1JO3)C?-7;nXnt#B`N~YzbOgcwj{M;>@Q1wF@gQYJ#PewhI}BKQo`nx# z+RCI(a^m<`yUPNW2AV~Ni_Mk@y_2UNFGny-nZO>1kQXak+N}8-q)=hu4c77R7-$y_DiUQE zzkU&(Q5=?b8TqY*!IpRvd|#sZ?4@X2#CuN7rs4L*E6F<> zoCNR@pBbZam32;MnM>4k?-gZimnW~4>#Z)21ue9gjoprV3XhKn#sv&}&fyfR zO6ieJy>0y{?R4d$oB59)$MhXtn0y?XrqO36e#btnJu|lh-)^wYX1x%LL5o(WW#H+PH@yq8|9aEu#^+`U3bX3#PL#5ZG8cK3qX5bA9V94Caj9! zpL7Z;EpK=$D}p!H)32V;(5MM~c)drhFHZ_tRbX~ru4~)}v6hNEBV^u!j)|cx^`xo> zNQJ3W`zKO6iddOinpG=R;HC{X>QQ5p<*WxG`Y;6`y@=lof`lZ!XRjb=V~Pg zA;k=7cnd?eaTFjwfcD@(2%K0GV+RTk2I?2xdJHg?(@fA?jxZLQjSmB8Es@!Im5o(2 z8=n!tgcHFh3GWf7{b9nvRG6`?Dya-GTCk4OPQv5UHPW!uDphSeYVgA30`xMaiatce z0my9lSS=5Gr4PM&NbqBNOHJztZK8kR^d8!)M8N{vot3dE!UdN3aOf{Fg>%nJu<1y&Bkz5z`%j80*xiX4{xDK z*&f}83T6GmB?h|p;O)&<9d$bR{p(=a33txo;bux})P-C)!^UR{_ai~uES+KdHi!}Q zQ9}a@HObI4^%pvtt=kP}MPb)6k$^6LCL@RH-ELMcF*Fhc>AL_0Vj*BA0woNGk@!_& z81`D;I9t(43l%ek0*JjTx9q^eog#OVRZlOhQ9swCfCAS)-MDp-hW%=$DDQ4sir!UB z!FLv?F59uge&z*w;<6|@4^-0!BiGRA*;oWukj}j-sEOx*2UpO7nVPU16)t!Jm5!*p zx9d(CH*oY^r2ZszcdC#Cu;@(rgKgVFKCe-)Dl_Czc18snXD((%MbW3>8y}FILa4wz zG!k6745NXL&bSP+0U$*4w6QUWMYvMaFz=G+VYBfCD`5sR*^pH<|CbKe-|5mIH8o6+ zYwcheX#W!q_B+&r;Sc}t#;D3OaVS?;4W<|HA~8j)sAHChGK={{^rq BP__U7 literal 12796 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 J7-reZ{{WNhb7Ztdb6M4FIZ/TaTORSrAgSSX/ZzdVSpVbdXZuVq5wSFWDWaN8zW/fk2wCRgnoSmknW56UzjYxj5+/Pr4oHTAVbj8zmA8vaM+Ih3H8pcdcN1xHNtyLfEvtawyi2u7mSFg2JeFNoZH/AupmtI6wz5KSgU5pYTjuGwc0yhCY16yQcboolxsQkn5rTEMUMXwOIakav2BfT7NrAM1rNT+B8LBVL3ZtuSTEKrC0pBMoU8XBRO46YArRinPrsLlFSKp85Rfsnq3W57mHWMo4nUqwOenxWRge/jpLni982Pr3vrZ7WWtzCGZyQFDwmV/+Uo5QXQ9Ti9nIbllMBSXl4sp5ugxhuPUvhBzL2xTHhJxZ4vLmOKII3YzF51LZ8AStmqH5RjmiHG0LJjkAL4jGiLOVqKIeupJZ66UuyVNi83ceMrh0+K89GRBKHkI8rY3LhMX0mtmD6Ln0d/Pi9VkOHqx//qx/HN42f/H4MGK+xidRT7ypRv2eG6CCbmihDJxH9EIteM4R93vd5z1fsfFo1+jcLYM7GW3O7RfgRP8fOh6VceBiwc0xjEa4WQnhCM8QQSvfRMjhkV/UOouIs33G9s+bwvZ4FBUYfLeZzR+gixAXM7WmBIC4wS/rLuRWhgaz1iC5+gBJZlcpVY64+mrr3IZstargHFhSTgT70iNCCZ8gcTgwGWEFje+kBo1wL6YZu/fWaoGlyh/kJuEbwrPyQst1N4Ucq60QlsaSMHBQuS2VBUDnAtei3WtUgFFdLlE/1pcSZ+Ahla8NyiD26tym0tukdue3Ra3NRa8LoTrLriXHfdaI1bwMaUBjSApMmtkia+pfEwXQVJdBf9D0Kpw7ZSZ2sT1tC0GVIkzCSVoizfXpJP3kCWClZNG/pboNqyRwHJLyLp1NdJqi1lw0shPAVpNjXTfSpymkQbgjBLZhEYajzEn3r42b26Zt2E93vptyduggluc7sdPMMjOL2djGoYw8tdus1h+pvm2i0o1LRcEB5GwvVDOaZjOZeRfpJmM1Ebo+LXEiMCqzIOae3Cdz3M+p3JzLh1Ht+4/XG3xe0Q+7UudOexa53Zl2lR0zxCBXMQLpR6Y5k02f58u4cLxVg/a9J0toTM2RrJWMUmiNZSjta2hzCs7GlIF6WSSoFKZNWq5Xw6nz1YBQiFp4/sZeU9UQHjGYVBE77fCLpup/Vr/FuwsB7RFHtDOp7YuOnXJ6zt7GvoM5FX32QkmYoNE/o7EzcfD5sNkur6xd5G3l6jm6alM+nB4Dop//cNgAn1Pb7cWTI2BUj20rjXpREZtXemVz3RODzRChr5TinbbIsOo3sMKGCIIx8mF74uNKw3GdUZEhMjL+QgRUdNXpOXIDWlzKFEaoyiL4XXGQuz7ZNvHjJrbVf0YNs8Q5d8uDCn4lhJLxi8XTptrtLSwxHP5ZW+wb/mW3S4q3mKi3n+0mEGEDJ7XL81W12loXQ+1da3nqWtLvKc1pHOyZSGLiYKrQjF5GN7RYcvY4Q15WYtb4mmtstbHRkIVI9yGr0upzjygkM7RV5caWwtKjV/7jik1hnhgfWK+yM8t4tQiD82PnOEoOOc0uzj71t4p+oiy1MQJ2iBLttvUMaasJraOQv3I0zV3sGVZUh3eI0vtC49tUJ4dvJ5ykcfLRb5ZR/XjGbCBWILDzZ9XkdW2Pg2aWeufWPsqrAFXi+cGB7HWRM7bzFo16c3WwVS2gd8yGn6l1OPO9fZJc4/b5Om9qch97R43M2memWpe4ZSZbDIzCXrOuWsVE1CHxodepd0D2GqKGzXKU6KyqUQlGHiNgKInKtN2PxKU6ke3r5Ata2SbO2K6DLjNbHF69gz0D9ri3ntq3TKcT55bU6cMPZvzUIgHv2RCp/6CAEP1XUXlJ7yGFoSe9t0D7qF5G2f4IQtiy3BazOqI281vcLLim18ygZv/AA== \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/UML/Implementation/TagFunction/TagFunction.png b/docs/UML/Implementation/TagFunction/TagFunction.png index b7a69f63aa4f87939587f859a5cf010991b26ab0..b990e53b652738842a230889df1e3e26afb456d6 100644 GIT binary patch literal 46831 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 KCs)hr*8c%wVORG6 literal 32388 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 z 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%0A&#sxs9o14uK1)=b01VNopq@QWz-dUcGRgf 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 S06bQnOkG)9saWyGgZ~BjEbu-6 diff --git a/docs/UML/Implementation/randomFunction/randomFunction.drawio b/docs/UML/Implementation/randomFunction/randomFunction.drawio new file mode 100644 index 0000000000..0c4e525c64 --- /dev/null +++ b/docs/UML/Implementation/randomFunction/randomFunction.drawio @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/UML/Implementation/randomFunction/randomFunction.png b/docs/UML/Implementation/randomFunction/randomFunction.png new file mode 100644 index 0000000000000000000000000000000000000000..8ebd0d09dba04ac3b166c3d05d2df6488a299bb2 GIT binary patch literal 17610 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 U4tDULlhB Date: Wed, 29 Mar 2023 23:57:48 +0800 Subject: [PATCH 129/252] no message --- text-ui-test/EXPECTED.TXT | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 15c52f07bf..b913f39e6d 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -33,14 +33,13 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| I've added the recipe to your weekly plan! | +| Please enter a valid number as the last argument. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Here is your weekly plan: | -| test recipe name x1 | +| Your weekly plan is empty! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| I've deleted the recipe from your weekly plan! | +| Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Your weekly plan is empty! | From 6e4262eb1acba9d2718bd15efbbbb22fd74493ff Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 30 Mar 2023 01:24:06 +0800 Subject: [PATCH 130/252] Refactor weeklyplan code Refactored duplicated code. User can now select the quantity of recipes to be deleted from the recipe. Updated user guide accordingly. --- database/weeklyPlanDatabase.json | 2 +- docs/UserGuide.md | 106 ++++++++++++++------ src/main/java/seedu/meal360/Meal360.java | 4 + src/main/java/seedu/meal360/Parser.java | 81 ++------------- src/main/java/seedu/meal360/Ui.java | 12 ++- src/main/java/seedu/meal360/WeeklyPlan.java | 22 +++- 6 files changed, 118 insertions(+), 109 deletions(-) diff --git a/database/weeklyPlanDatabase.json b/database/weeklyPlanDatabase.json index 9e26dfeeb6..5d909f1bf2 100644 --- a/database/weeklyPlanDatabase.json +++ b/database/weeklyPlanDatabase.json @@ -1 +1 @@ -{} \ No newline at end of file +{"chicken rice":2447,"avocado toast":50} \ No newline at end of file diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 01c5c9050c..f67671b65c 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,13 +2,15 @@ ## Introduction -Meal360 is a desktop app for managing your recipes, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI apps. +Meal360 is a desktop app for managing your recipes, optimized for use via a Command Line Interface ( +CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, +Meal360 can get your recipe management tasks done faster than traditional GUI apps. ___ ## Quick Start -1. Ensure that you have Java 11 or above installed. +1. Ensure that you have Java 11 or above installed. 2. Down the latest version of `Duke` from [here](http://link.to/duke). ___ @@ -18,8 +20,10 @@ ___ * [View recipes](#viewing-recipes--view) * [List relevant recipes](#listing-recipes--list) * [Tag/Categorise recipes](#taggingcategorising-recipes--tag) -* [Add recipes to weekly plan](#adding-to-this-weeks-plan--weekly-add) -* [Remove recipes from weekly plan](#deleting-from-this-weeks-plan--weekly-delete) +* [Add single recipe to weekly plan](#adding-to-this-weeks-plan--weekly-add) +* [Add multiple recipe to weekly plan](#adding-to-this-weeks-plan--weekly-add) +* [Remove single recipe from weekly plan](#deleting-from-this-weeks-plan--weekly-delete) +* [Remove multiple recipe from weekly plan](#deleting-from-this-weeks-plan--weekly-delete) * [View weekly plan](#view-this-weeks-plan--weeklyplan) * [Random a recipe](#random-a-recipe--random) @@ -46,7 +50,6 @@ Format: `edit /r [recipe_name]` * `recipe_name` is basically a string. * Type the recipe name after typing `/r `. - Example of usage: `edit /r chicken rice` @@ -58,11 +61,10 @@ List all recipes or filtered list recipes by the name or ingredients. Format: `list [/t] [KEYWORD && KEYWORD && ...]` - -* The `KEYWORD` and `/t` are optional. +* The `KEYWORD` and `/t` are optional. * `KEYWORD` can be a name of recipe or ingredients or tag. -* If user want to list recipes from tags `/t` is required. When `/t` is used, -at least one `KEYWORD`, replacing by the tag name, is required. +* If user want to list recipes from tags `/t` is required. When `/t` is used, + at least one `KEYWORD`, replacing by the tag name, is required. * To list all recipes, do not add `KEYWORD` and `/t`. * Use `&&` to list all the recipe that contain **all** specified `KEYWORD`. @@ -70,11 +72,11 @@ Example of usage: * `list` lists all the recipes. * `list pizza` lists recipes that contain 'pizza' in the name or ingredients. -* `list milk && egg` lists recipes that contain __both__ 'milk' and 'egg' in the -name or ingredients. +* `list milk && egg` lists recipes that contain __both__ 'milk' and 'egg' in the + name or ingredients. * `list /t western` lists the recipes that are in 'western' tag. * `list /t western && chinese` lists recipes that is under __both__ 'western' and -'chinese' tag. + 'chinese' tag. ### Viewing recipes: `view` @@ -108,6 +110,7 @@ Example of usage: `delete r/all` ### Tagging/Categorising recipes: `tag` + __Categorize recipes into a specific tag__ Adding one or more recipes into a tag. @@ -115,8 +118,8 @@ Adding one or more recipes into a tag. Format: `tag LABEL << [RECIPE_NAME && RECIPE_NAME && ...]` * `LABEL` is required, and replace with the tag label that user want to -add the recipes into. This is case-sensitive. -* At least one `RECIPE_NAME` is required. + add the recipes into. This is case-sensitive. +* At least one `RECIPE_NAME` is required. * To add multiple recipes into the tag, use `&&` followed by next `RECIPE_NAME`. Example of usage: @@ -124,7 +127,7 @@ Example of usage: * `tag western << burger` adds burger into 'western' tag. * `tag junk foods << burger && hotdog` adds burger and hotdog into 'junk foods' tag. * `tag breakfast << milk && boiled egg && bread` adds milk, boiled egg and -bread into 'breakfast' tag. + bread into 'breakfast' tag. __Removing recipes form a tag__ @@ -142,16 +145,15 @@ Example of usage: * `tag western>> burger` removes burger from 'western' tag. * `tag junk foods >> burger && hotdog` remove burger and hotdog from 'junk foods' tag. * `tag breakfast >> milk && boilded egg && bread` removes milk, boiled egg, and bread -from 'breakfast' tag. + from 'breakfast' tag. - -### Adding to this week's plan: `weekly /add` +### Adding single recipe this week's plan: `weekly /add` Adds an existing recipe to this week's plan. Format: `weekly /add RECIPE NAME QUANTITY` -* Adds the specified `RECIPE NAME` to this week's plan`[QUANTITY]` number of times. +* Adds the specified `RECIPE NAME` to this week's plan`QUANTITY` number of times. * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive integer** 1,2,3, ... @@ -161,6 +163,24 @@ Example of usage: * `weekly /add pizza 2` adds pizza to this week's plan twice. * `weekly /add burger 1` adds burger to this week's plan once. +### Adding multiple recipes to this week's plan: `weekly /multiadd` + +Adds multiple existing recipe to this week's plan. + +Format: `weekly /multiadd [/r RECIPE NAME /q QUANTITY]` + +* Adds the specified `RECIPE NAME` to this week's plan`QUANTITY` number of times. +* At least one pair of `RECIPE_NAME` and `QUANTITY` is required. +* Each `RECIPE_NAME` and `QUANTITY` requires `/r` and `/q` before it respectively. +* The recipe name refers to the name of the recipe shown in the displayed recipe list. +* The quantity **must be a positive + integer** 1,2,3, ... + +Example of usage: + +* `weekly /multiadd /r pizza /q 2 /r burger /q 9` adds pizza twice and burger once to this week's + plan. + ### Deleting from this week's plan: `weekly /delete` Deletes an existing recipe from this week's plan. @@ -174,6 +194,25 @@ Example of usage: * `weekly /delete pizza` removes pizza from this week's plan. +### Deleting multiple recipes from this week's plan: `weekly /multidelete` + +Deletes multiple existing recipe from this week's plan. + +Format: `weekly /multidelete [/r RECIPE NAME /q QUANTITY]` + +* Deletes the specified `RECIPE NAME` from this week's plan`QUANTITY` number of times. +* At least one pair of `RECIPE_NAME` and `QUANTITY` is required. +* Each `RECIPE_NAME` and `QUANTITY` requires `/r` and `/q` before it respectively. +* The recipe name refers to the name of the recipe shown in the displayed recipe list. +* The quantity **must be a positive + integer** 1,2,3, ... + +Example of usage: + +* `weekly /multidelete /r pizza /q 2 /r burger /q 9` deletes pizza twice and burger once from this + week's + plan. + ### Clearing this week's plan: `weekly /clear` Clears this week's plan by removing all recipes listed in weekly plan. @@ -194,13 +233,11 @@ Format: `weeklyingredients` ### Random a recipe: `random` -Random a recipe from all the recipes that user have, and show the list of +Random a recipe from all the recipes that user have, and show the list of ingredients and their quantities for a recipe. Format: `random` - - ### Exit the program: `bye` Exits the program. @@ -214,14 +251,17 @@ Format: `bye` **A**: {your answer here} ## Command Summary -| Action | Format, Examples | -|------------------------------------|------------------------------------------------------------------| -| Add recipe | `add /r [recipe_name]`
e.g `add /r chicken rice` | -| Edit recipe | `edit /r [recipe_name]`
e.g `edit /r chicken rice` | -| List recipe | `list [/t] [KEYWORD]`
e.g `list pizza` | -| View recipe | `view INDEX`
e.g `view 1` | -| Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | -| Remove tag/Categorise from recipes | `tag LABEL >> RECIPE_NAME`
e.g `tag western >> pizza` | -| Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | -| Delete from weekly plan | `weekly /delete RECIPE NAME`
e.g `weekly /delete pizza` | -| View weekly plan | `weeklyplan` | + +| Action | Format, Examples | +|------------------------------------|-------------------------------------------------------------------------------------------------------------| +| Add recipe | `add /r [recipe_name]`
e.g `add /r chicken rice` | +| Edit recipe | `edit /r [recipe_name]`
e.g `edit /r chicken rice` | +| List recipe | `list [/t] [KEYWORD]`
e.g `list pizza` | +| View recipe | `view INDEX`
e.g `view 1` | +| Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | +| Remove tag/Categorise from recipes | `tag LABEL >> RECIPE_NAME`
e.g `tag western >> pizza` | +| Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | +| Add multiple to weekly plan | `weekly /multiadd [/r RECIPE NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 3` | +| Delete from weekly plan | `weekly /delete RECIPE NAME`
e.g `weekly /delete pizza` | +| Delete multiple from weekly plan | `weekly /multidelete [/r RECIPE NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 4` | +| View weekly plan | `weeklyplan` | diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 2b626a9ad2..fdbe2f9a3f 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -39,6 +39,10 @@ public static void startApp() { try { ui.printMessage("Loading weekly plan..."); weeklyPlan = database.loadWeeklyPlanDatabase(); + boolean isClean = weeklyPlan.checkValidity(recipeList); + if (!isClean) { + ui.printMessage("Weekly plan has invalid recipes, removing them..."); + } ui.printMessage("Weekly plan loaded successfully."); } catch (Exception e) { ui.printMessage("Error loading weekly plan, loading default empty weekly plan instead."); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index db108cc4a9..1d9a06f7e4 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -405,16 +405,12 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) try { switch (command[1]) { case "/add": - updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); - break; case "/delete": - updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); + updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); break; case "/multiadd": - updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); - break; case "/multidelete": - updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); + updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); break; default: throw new IllegalArgumentException( @@ -430,48 +426,31 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) } } - private WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) + private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipes) throws InvalidNegativeValueException, InvalidRecipeNameException { int numDays = Integer.parseInt(command[command.length - 1]); if (numDays < 1) { throw new InvalidNegativeValueException("Number of days needs to be at least 1."); } - int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; - WeeklyPlan thisWeekPlan = new WeeklyPlan(); + int nameLastIndex = command.length - 1; + WeeklyPlan edits = new WeeklyPlan(); StringBuilder recipeName = new StringBuilder(command[2]); for (int i = 3; i < nameLastIndex; i++) { recipeName.append(" ").append(command[i]); } if (recipes.findByName(recipeName.toString().trim()) != null) { - thisWeekPlan.put(recipeName.toString(), numDays); - return thisWeekPlan; + edits.put(recipeName.toString(), numDays); + return edits; } else { throw new InvalidRecipeNameException("Please indicate a valid recipe name."); } } - private WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - int nameLastIndex = command.length; - WeeklyPlan thisWeekPlan = new WeeklyPlan(); - StringBuilder recipeName = new StringBuilder(command[2]); - for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i].toLowerCase().trim()); - } - - if (recipes.findByName(recipeName.toString().trim()) != null) { - thisWeekPlan.put(recipeName.toString(), 0); - return thisWeekPlan; - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } - - private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) + private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes) throws InvalidNegativeValueException, InvalidRecipeNameException { - WeeklyPlan recipesToAdd = new WeeklyPlan(); + WeeklyPlan recipesToEdit = new WeeklyPlan(); ArrayList quantities = new ArrayList<>(); ArrayList recipeNames = new ArrayList<>(); ArrayList startIndices = new ArrayList<>(); @@ -508,7 +487,7 @@ private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) try { for (int i = 0; i < recipeNames.size(); i++) { if (recipes.findByName(recipeNames.get(i)) != null) { - recipesToAdd.put(recipeNames.get(i), quantities.get(i)); + recipesToEdit.put(recipeNames.get(i), quantities.get(i)); } else { throw new InvalidRecipeNameException("Please indicate a valid recipe name."); } @@ -517,45 +496,7 @@ private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) throw new NumberFormatException("Please enter a positive number for the quantity."); } - return recipesToAdd; - } - - private WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - WeeklyPlan recipesToDelete = new WeeklyPlan(); - ArrayList recipeNames = new ArrayList<>(); - ArrayList startIndices = new ArrayList<>(); - StringBuilder recipeName = new StringBuilder(); - - for (int i = 0; i < command.length; i++) { - if (command[i].equals("/r")) { - startIndices.add(i); - } - } - - if (startIndices.size() == 0) { - throw new IllegalArgumentException("Please use /r to indicate the recipe to be deleted."); - } - - // Building the recipe names - for (int i = 0; i < startIndices.size(); i++) { - int nameStartIndex = startIndices.get(i) + 1; - int nameEndIndex = - (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; - - recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); - } - - // Add each recipe to the weekly plan - for (String name : recipeNames) { - if (recipes.findByName(name) != null) { - recipesToDelete.put(name, 0); - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } - - return recipesToDelete; + return recipesToEdit; } private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index fa1322b8d3..fd7ca7de98 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -93,9 +93,13 @@ public void printHelp() { printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); printMessage("5. List All Recipes: list"); - printMessage("6. Add to Weekly Plan: add /r {recipe name} {quantity}"); - printMessage("7. Delete from Weekly Plan: delete /r {recipe name}"); - printMessage("8. View Weekly Plan: weeklyplan"); - printMessage("9. Exit: bye"); + printMessage("6. Add Single Recipe to Weekly Plan: add {recipe name} {quantity}"); + printMessage("7. Add Multiple Recipes to Weekly Plan: add /r {recipe name} /q {quantity}"); + printMessage(" /r {recipe name} /q {quantity} ..."); + printMessage("8. Delete Single Recipe from Weekly Plan: delete {recipe name} {quantity}"); + printMessage("9. Delete Multiple Recipes from Weekly Plan: delete /r {recipe name} /q"); + printMessage(" {quantity} /r {recipe name} /q {quantity} ..."); + printMessage("10. View Weekly Plan: weeklyplan"); + printMessage("11. Exit: bye"); } } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index 41e781a1b9..56417cbd0f 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -1,5 +1,6 @@ package seedu.meal360; +import java.util.ArrayList; import java.util.HashMap; public class WeeklyPlan extends HashMap { @@ -7,7 +8,7 @@ public class WeeklyPlan extends HashMap { public void addPlans(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { if (this.containsKey(recipe)) { - this.put(recipe, this.get(recipe) + count); + this.put(recipe, this.get(recipe) + count); // Case when recipe already exists in plan } else { this.put(recipe, count); } @@ -17,7 +18,12 @@ public void addPlans(WeeklyPlan recipeMap) { public void deletePlans(WeeklyPlan recipeMap) { recipeMap.forEach((recipe, count) -> { if (this.containsKey(recipe)) { + int currentCount = this.get(recipe); + int newCount = currentCount - count; this.remove(recipe); + if (newCount > 0) { + this.put(recipe, newCount); + } } else { throw new IllegalArgumentException("Recipe does not exist in weekly plan!"); } @@ -28,4 +34,18 @@ public void clearPlan() { this.clear(); } + public boolean checkValidity(RecipeList recipeList) { + ArrayList toRemove = new ArrayList<>(); + this.forEach((recipe, count) -> { + if (recipeList.findByName(recipe) == null) { + toRemove.add(recipe); + } + }); + + if (toRemove.size() == 0) { + return true; + } + toRemove.forEach(recipe -> this.remove(recipe)); + return false; + } } From f7eea6afef262e9487141b33f1fd77b240967d6b Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 30 Mar 2023 02:55:03 +0800 Subject: [PATCH 131/252] Add commands User can now add, delete and view their ingredients --- src/main/java/seedu/meal360/Ingredient.java | 4 +- .../java/seedu/meal360/IngredientList.java | 10 +- src/main/java/seedu/meal360/Meal360.java | 22 ++++ src/main/java/seedu/meal360/Parser.java | 112 ++++++++++++++---- src/main/java/seedu/meal360/Ui.java | 17 +++ 5 files changed, 136 insertions(+), 29 deletions(-) diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java index bead660e93..cab254a5c1 100644 --- a/src/main/java/seedu/meal360/Ingredient.java +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -8,12 +8,10 @@ public class Ingredient { public Integer ingredientCount; public LocalDate expiryDate; public Boolean expired; - private String unit; - public Ingredient(String ingredientName, Integer ingredientCount, String unit, String expiryDate) { + public Ingredient(String ingredientName, Integer ingredientCount, String expiryDate) { this.ingredientName = ingredientName; this.ingredientCount = ingredientCount; - this.unit = unit; // parse expiry date using parseDate method this.expiryDate = parser.parseDate(expiryDate); this.updateExpired(); diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index 5929999708..f635881298 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -48,10 +48,16 @@ public void editIngredient(Ingredient ingredient, Integer ingredientCount, Strin } } - public void deleteIngredient(String ingredient) { + public void deleteIngredient(String ingredient, Integer ingredientCount) { try { if (this.containsKey(ingredient)) { - this.remove(ingredient); + int currentCount = this.get(ingredient).ingredientCount; + int newCount = currentCount - ingredientCount; + if (newCount > 0) { + this.get(ingredient).ingredientCount = newCount; + } else { + this.remove(ingredient); + } } throw new Exceptions.IngredientNotFoundException(); } catch (Exceptions.IngredientNotFoundException e) { diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index fdbe2f9a3f..1a7d784c45 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -197,6 +197,28 @@ public static void receiveInput(String input) { ui.printSeparator(); ui.printWeeklyPlan(weeklyPlan); ui.printSeparator(); + } else if (command[0].equals("add_i")) { + ui.printSeparator(); + try { + parser.parseAddUserIngredients(command, userIngredients); + ui.printMessage("Ingredient successfully added!"); + } catch (IllegalArgumentException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("del_i")) { + ui.printSeparator(); + try { + parser.parseDeleteUserIngredients(command, userIngredients); + ui.printMessage("Ingredients successfully deleted!"); + } catch (IllegalArgumentException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("view_ingredients")) { + ui.printSeparator(); + ui.printUserIngredients(userIngredients); + ui.printSeparator(); } else if (command[0].equals("help")) { ui.printSeparator(); ui.printHelp(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 1d9a06f7e4..eccec3f557 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -22,7 +22,7 @@ public String combineWords(String[] input, int startIndex, int length) { return word.toString(); } - public HashMap parseIngredientName(String[] command){ + public HashMap parseIngredientName(String[] command) { HashMap ingredients = new HashMap<>(); int flag = 0; StringBuilder add = null; @@ -31,7 +31,7 @@ public HashMap parseIngredientName(String[] command){ int indexOfEqual; for (String s : command) { - try{ + try { indexOfEqual = s.indexOf("="); if (indexOfEqual == -1) { if (add != null) { @@ -69,7 +69,7 @@ public HashMap parseIngredientName(String[] command){ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { String recipeName = combineWords(input, 2, input.length); - if(recipeList.findByName(recipeName)!=null){ + if (recipeList.findByName(recipeName) != null) { return null; } HashMap ingredients = new HashMap<>(); @@ -131,7 +131,8 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { ingredientToRemove = ingredient; System.out.println("Ingredient to be changed:"); ui.printSeparator(); - String toPrint = String.format("%s(%d)", ingredient, recipeToEdit.getIngredients().get(ingredient)); + String toPrint = String.format("%s(%d)", ingredient, + recipeToEdit.getIngredients().get(ingredient)); System.out.println(ui.formatMessage(toPrint)); ui.printSeparator(); break; @@ -142,8 +143,8 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String line = userInput.nextLine(); String command = line.replaceAll("\\s+", " "); int indexOfEqual = command.indexOf("="); - String newIngredientName = command.substring(0,indexOfEqual); - int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual+1)); + String newIngredientName = command.substring(0, indexOfEqual); + int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual + 1)); recipeToEdit.getIngredients().remove(ingredientToRemove); recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); @@ -270,11 +271,11 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) { recipe = recipeList.findByName(recipeName); isUnableToFindTheRecipe = recipe == null; if (isUnableToFindTheRecipe) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + - "successfully added from the tag."; - throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully added from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } recipeList.addRecipeToTag(tag, recipe); } @@ -297,31 +298,32 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) { tag = args[0].trim(); isUnableToFindTag = !recipeList.tags.containsKey(tag); if (isUnableToFindTag) { - throw new IndexOutOfBoundsException("There is no \"" + tag + "\" tag found. Please make sure you have " + - "entered the correct tag."); + throw new IndexOutOfBoundsException( + "There is no \"" + tag + "\" tag found. Please make sure you have " + + "entered the correct tag."); } recipesToRemove = args[1].split("&&"); for (String recipeName : recipesToRemove) { recipeName = recipeName.trim(); recipe = recipeList.findByName(recipeName); - isNoRecipeInTheList = recipe == null; + isNoRecipeInTheList = recipe == null; if (isNoRecipeInTheList) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } try { recipeList.removeRecipeFromTag(tag, recipe); } catch (IndexOutOfBoundsException e) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } } return tag; @@ -519,4 +521,66 @@ public LocalDate parseDate(String input) { throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy"); } } + + public void parseAddUserIngredients(String[] command, IngredientList ingredientList) { + String ingredientName = null; + Integer ingredientCount = null; + String expiryDate = null; + + try { + for (int i = 1; i < command.length; i++) { + switch (command[i]) { + case "/n": + ingredientName = command[++i]; + break; + case "/c": + ingredientCount = Integer.parseInt(command[++i]); + break; + case "/d": + expiryDate = command[++i]; + break; + default: + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name, count, and expiry date."); + } + } + } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { + throw new IllegalArgumentException("Invalid command format. Please check your input."); + } + + if (ingredientName == null || ingredientCount == null || expiryDate == null) { + throw new IllegalArgumentException("Missing required information. Please use /n, /c, and /d."); + } + + ingredientList.addIngredient(new Ingredient(ingredientName, ingredientCount, expiryDate)); + } + + public void parseDeleteUserIngredients(String[] command, IngredientList userIngredients) { + String ingredientName = null; + Integer ingredientCount = null; + + try { + for (int i = 1; i < command.length; i++) { + switch (command[i]) { + case "/n": + ingredientName = command[++i]; + break; + case "/c": + ingredientCount = Integer.parseInt(command[++i]); + break; + default: + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name and count."); + } + } + } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { + throw new IllegalArgumentException("Invalid command format. Please check your input."); + } + + if (ingredientName == null || ingredientCount == null) { + throw new IllegalArgumentException("Missing required information. Please use /n and /c."); + } + + userIngredients.deleteIngredient(ingredientName, ingredientCount); + } } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index fd7ca7de98..26fd26488a 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -1,5 +1,7 @@ package seedu.meal360; +import java.time.format.DateTimeFormatter; + public class Ui { private static final int BOXWIDTH = 100; @@ -102,4 +104,19 @@ public void printHelp() { printMessage("10. View Weekly Plan: weeklyplan"); printMessage("11. Exit: bye"); } + + public void printUserIngredients(IngredientList userIngredients) { + if (userIngredients.isEmpty()) { + printMessage("Your ingredient list is empty!"); + } else { + printMessage("Here is your ingredient list:"); + userIngredients.forEach((name, ingredient) -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + String formattedDate = ingredient.expiryDate.format(formatter); + String outputMessage = String.format("%s (%d) [by:%s]", name, ingredient.ingredientCount, + formattedDate); + System.out.println(formatMessage(outputMessage)); + }); + } + } } From 4f1862cf4ece4b19795097fe006b41eb6bacaa17 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 30 Mar 2023 05:00:29 +0800 Subject: [PATCH 132/252] Fix JUnit test --- src/main/java/seedu/meal360/Parser.java | 9 +++++++-- .../exceptions/IngredientNotFoundException.java | 7 +++++++ src/test/java/seedu/meal360/Meal360Test.java | 11 ++++++----- text-ui-test/EXPECTED.TXT | 16 ++++++++++++---- text-ui-test/database/recipesDatabase.json | 1 + .../database/userIngredientsDatabase.json | 1 + text-ui-test/database/weeklyPlanDatabase.json | 1 + 7 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java create mode 100644 text-ui-test/database/recipesDatabase.json create mode 100644 text-ui-test/database/userIngredientsDatabase.json create mode 100644 text-ui-test/database/weeklyPlanDatabase.json diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index eccec3f557..ddc52ec87f 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -478,6 +478,11 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes throw new IllegalArgumentException("Please ensure the number of recipes and quantities match."); } + if (startIndices.size() == 0) { + throw new IllegalArgumentException( + "Please ensure that the command is entered in the correct format."); + } + // Building the recipe names for (int i = 0; i < startIndices.size(); i++) { int nameStartIndex = startIndices.get(i) + 1; @@ -569,8 +574,8 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr ingredientCount = Integer.parseInt(command[++i]); break; default: - throw new IllegalArgumentException("Missing required information. Please provide " - + "ingredient name and count."); + throw new IllegalArgumentException( + "Missing required information. Please provide " + "ingredient name and count."); } } } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { diff --git a/src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java b/src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java new file mode 100644 index 0000000000..718367d593 --- /dev/null +++ b/src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java @@ -0,0 +1,7 @@ +package seedu.meal360.exceptions; + +public class IngredientNotFoundException extends Exception { + public IngredientNotFoundException(String message) { + super(message); + } +} diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 6e285d8583..0395d00d39 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -208,7 +208,7 @@ public void testDeleteWeeklyPlan() { int newWeeklyPlanSize = weeklyPlan.size(); assertEquals(oldWeeklyPlanSize, newWeeklyPlanSize); toDelete.clear(); - toDelete.put("salad", 0); + toDelete.put("salad", 1); weeklyPlan.deletePlans(toDelete); newWeeklyPlanSize = weeklyPlan.size(); assertEquals(oldWeeklyPlanSize - 1, newWeeklyPlanSize); @@ -223,20 +223,21 @@ public void testDeleteMultiWeeklyPlan() throws InvalidRecipeNameException, Inval // Testing delete recipe from weekly plan WeeklyPlan recipeMap = parser.parseWeeklyPlan( - new String[]{"weekly", "/multidelete", "/r", "burger", "/r", "pizza"}, recipes); + new String[]{"weekly", "/multidelete", "/r", "burger", "/q", "1", "/r", "pizza", "/q", "1"}, + recipes); weeklyPlan.deletePlans(recipeMap); - assertEquals(1, weeklyPlan.size()); + assertEquals(3, weeklyPlan.size()); // Testing exceptions weeklyPlan.put("pizza", 3); weeklyPlan.put("burger", 100); assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multidelete", "/r", "burgers", "/r", "pizza"}, recipes)); + new String[]{"weekly", "/multidelete", "/r", "burgers", "/q", "2"}, recipes)); assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( new String[]{"weekly", "/multidelete", "burger", "pizza", "salad"}, recipes)); - assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( + assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( new String[]{"weekly", "/multidelete", "/r", "burger", "/q", "1", "/r", "pizza"}, recipes)); } diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 06829dde54..f6979dcc05 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -6,8 +6,12 @@ Welcome to Meal360, your ultimate Recipe Manager! |_| |_\___\__,_|_|___/\___/\__/ ---------------------------------------------------------------------------------------------------- -| Loading database... | -| Database loaded successfully. | +| Loading recipes... | +| Recipes loaded successfully. | +| Loading weekly plan... | +| Weekly plan loaded successfully. | +| Loading ingredients... | +| Ingredients loaded successfully. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | These are the recipes you have (10 recipes): | @@ -121,13 +125,17 @@ Welcome to Meal360, your ultimate Recipe Manager! | Your weekly plan is empty! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please indicate a valid recipe name. | +| Please enter a valid number as the last argument. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Your weekly plan is empty! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Saving database... | +| Saving recipes... | | Database saved successfully. | +| Saving weekly plan... | +| Weekly plan saved successfully. | +| Saving ingredients... | +| Ingredients saved successfully. | | Bye. Hope to see you again soon! | ---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/database/recipesDatabase.json b/text-ui-test/database/recipesDatabase.json new file mode 100644 index 0000000000..0beacc58a3 --- /dev/null +++ b/text-ui-test/database/recipesDatabase.json @@ -0,0 +1 @@ +[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file diff --git a/text-ui-test/database/userIngredientsDatabase.json b/text-ui-test/database/userIngredientsDatabase.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/text-ui-test/database/userIngredientsDatabase.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/text-ui-test/database/weeklyPlanDatabase.json b/text-ui-test/database/weeklyPlanDatabase.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/text-ui-test/database/weeklyPlanDatabase.json @@ -0,0 +1 @@ +{} \ No newline at end of file From a042fec2c49c1ce62019b2d5332b12767516953d Mon Sep 17 00:00:00 2001 From: notbingsu Date: Thu, 30 Mar 2023 11:23:05 +0800 Subject: [PATCH 133/252] added function to check available recipes and print available recipes --- .vscode/settings.json | 3 ++ src/main/java/seedu/meal360/Meal360.java | 52 ++++++++++++--------- src/main/java/seedu/meal360/Recipe.java | 16 +++++++ src/main/java/seedu/meal360/RecipeList.java | 19 ++++++-- src/main/java/seedu/meal360/Ui.java | 19 +++++--- 5 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..385f27a27c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive" +} diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 73dc07a291..8f84dfb40f 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -51,14 +51,14 @@ public static void receiveInput(String input) { ui.printMessage(deletedRecipe); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = - "Please enter a valid recipe number or name. You did not enter a recipe number or " - + "name."; + String errorMessage = "Please enter a valid recipe number or name. You did not enter a recipe number or " + + "name."; ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( "Please enter a valid recipe number or name. You entered %s, " - + "which is in invalid.", command[1]); + + "which is in invalid.", + command[1]); ui.printMessage(errorMessage); } ui.printSeparator(); @@ -142,29 +142,35 @@ public static void receiveInput(String input) { WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); switch (command[1]) { - case "/add": - case "/multiadd": - weeklyPlan.addPlans(recipeMap); - ui.printMessage("I've added the recipes to your weekly plan!"); - break; - case "/delete": - case "/multidelete": - weeklyPlan.deletePlans(recipeMap); - ui.printMessage("I've deleted the recipes from your weekly plan!"); - break; - case "/clear": - weeklyPlan.clearPlan(); - ui.printMessage("I've cleared your entire weekly plan!"); - break; - default: - ui.printMessage("Please enter a valid command."); - break; + case "/add": + case "/multiadd": + weeklyPlan.addPlans(recipeMap); + ui.printMessage("I've added the recipes to your weekly plan!"); + break; + case "/delete": + case "/multidelete": + weeklyPlan.deletePlans(recipeMap); + ui.printMessage("I've deleted the recipes from your weekly plan!"); + break; + case "/clear": + weeklyPlan.clearPlan(); + ui.printMessage("I've cleared your entire weekly plan!"); + break; + default: + ui.printMessage("Please enter a valid command."); + break; } - } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException | - ArrayIndexOutOfBoundsException e) { + } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException + | ArrayIndexOutOfBoundsException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); + } else if (command[0].equals("available")) { + // list recipes with ingredients all in ingredient list + ui.printSeparator(); + RecipeList availableRecipes = recipeList.availableRecipes(); + ui.listAvailableRecipes(availableRecipes); + ui.printSeparator(); } else if (command[0].equals("weeklyingredients")) { ui.printSeparator(); ui.printWeeklyIngredients(weeklyPlan, recipeList); diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index f94e04da19..869e7dc4cc 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -7,6 +7,8 @@ public class Recipe { // changed ingredients to public to edit via editRecipe public HashMap ingredients; private String name; + private Boolean available; + private static IngredientList ingredientList = new IngredientList(); public Recipe(String name, HashMap ingredients) { this.name = name; @@ -24,4 +26,18 @@ public HashMap getIngredients() { public int getNumOfIngredients() { return ingredients.size(); } + + public boolean isAvailable() { + for (String ingredientName : ingredients.keySet()) { + if (ingredientList.containsKey(ingredientName)) { + Ingredient ingredient = ingredientList.get(ingredientName); + if (ingredient.ingredientCount < ingredients.get(ingredientName)) { + return false; + } + } else { + return false; + } + } + return true; + } } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 620f6e1d4f..9fd9bd13ac 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -6,6 +6,7 @@ public class RecipeList extends ArrayList { public HashMap> tags = new HashMap<>(); + private static IngredientList ingredientList = new IngredientList(); public Recipe findByName(String name) { for (Recipe recipe : this) { @@ -46,11 +47,11 @@ public void addRecipeToTag(String tag, Recipe recipe) { public void removeRecipeFromTag(String tag, Recipe recipe) { HashMap tagRecipeList = tags.get(tag); - boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); + boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); if (!isAbleToFindTheRecipe) { - String errorMessage1 = "Unable to find the recipe: \"" + recipe.getName() +"\" in the" + + String errorMessage1 = "Unable to find the recipe: \"" + recipe.getName() + "\" in the" + " tag."; - String errorMessage2 = "All the recipe before \"" + recipe.getName() +"\" (if any) are " + + String errorMessage2 = "All the recipe before \"" + recipe.getName() + "\" (if any) are " + "successfully removed from the tag."; throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } @@ -91,7 +92,7 @@ public RecipeList listTagRecipes(String[] filters) { boolean hasNoRecipeToReturn; boolean isNotFoundTag; - //add all recipe from first tag to the list + // add all recipe from first tag to the list isNotFoundTag = !this.tags.containsKey(filters[0].trim()); if (isNotFoundTag) { throw new NullPointerException("There is no \"" + filters[0] + "\" tag found. Please make sure you have " + @@ -120,6 +121,16 @@ public RecipeList listTagRecipes(String[] filters) { return filteredRecipeList; } + public RecipeList availableRecipes() { + RecipeList availableRecipeList = new RecipeList(); + for (Recipe recipe : this) { + if (recipe.isAvailable()) { + availableRecipeList.add(recipe); + } + } + return availableRecipeList; + } + public Recipe randomRecipe() { Random random = new Random(); Recipe randomRecipe = this.get(random.nextInt(this.size())); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 60236a4bd9..1b623f2bdb 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -52,7 +52,7 @@ public void printWeeklyPlan(WeeklyPlan weeklyPlan) { } } - + public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) { if (weeklyPlan.isEmpty()) { printMessage("Your weekly plan is empty!"); @@ -71,17 +71,24 @@ public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) } public void listRecipe(RecipeList recipeListToPrint) { + listRecipes(recipeListToPrint, "There is nothing to list.", "These are the recipes you have"); + } + + public void listAvailableRecipes(RecipeList recipeListToPrint) { + listRecipes(recipeListToPrint, "There are no available recipes.", "These are the recipes you can cook"); + } + + private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, String listHeaderMsg) { int numberOfRecipes = recipeListToPrint.size(); int order = 0; if (numberOfRecipes == 0) { - printMessage("There is nothing to list."); + printMessage(emptyListMsg); return; } - printMessage("These are the recipes you have (" + numberOfRecipes + " recipes):"); + printMessage(listHeaderMsg + " (" + numberOfRecipes + " recipes):"); for (Recipe recipe : recipeListToPrint) { - order = order + 1; - printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() - + " ingredients)"); + order++; + printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); } } From 34801c1c60cc0febecae2c420e952088cfa373c4 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Thu, 30 Mar 2023 11:32:10 +0800 Subject: [PATCH 134/252] coding standards edit --- src/main/java/seedu/meal360/Recipe.java | 3 ++- src/main/java/seedu/meal360/RecipeList.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 869e7dc4cc..8fd5a46c0d 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -5,10 +5,11 @@ public class Recipe { // changed ingredients to public to edit via editRecipe + private static IngredientList ingredientList = new IngredientList(); public HashMap ingredients; private String name; private Boolean available; - private static IngredientList ingredientList = new IngredientList(); + public Recipe(String name, HashMap ingredients) { this.name = name; diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 9fd9bd13ac..08f0cb5495 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -5,8 +5,8 @@ import java.util.Random; public class RecipeList extends ArrayList { - public HashMap> tags = new HashMap<>(); private static IngredientList ingredientList = new IngredientList(); + public HashMap> tags = new HashMap<>(); public Recipe findByName(String name) { for (Recipe recipe : this) { From c9c67a6ec63b1419ae7647d83676cf7e7d568d4f Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 30 Mar 2023 11:32:42 +0800 Subject: [PATCH 135/252] add JUnit Test for 'random', and tagging --- docs/DeveloperGuide.md | 2 + src/main/java/seedu/meal360/Parser.java | 2 +- src/main/java/seedu/meal360/RecipeList.java | 7 +- src/test/java/seedu/meal360/Meal360Test.java | 112 ++++++++++++++++++- 4 files changed, 113 insertions(+), 10 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 157739c80e..a2e17604e9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -261,6 +261,7 @@ It is implemented through the following step: `recipe` to `parseRandomRecipe()`. The sequence diagram below shows how this feature works: + ![](../docs/UML/Implementation/RandomFunction/RandomFunction.png) --- ## Appendix: Requirements @@ -297,6 +298,7 @@ driven app. | v2.0 | user | delete meals I plan to make for the week | remove some meals from the weekly plan if I change my mind | | v2.0 | user | categorise recipes using tags | group recipes with similar theme together | | v2.0 | user | list the recipes by tag | list recipes that are under the specific category | +| v2.0 | user | random a recipe | have a suggestion when do not know what to cook | ### Non-Functional Requirements diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index db108cc4a9..c12a1157f0 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -392,10 +392,10 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { } public Recipe parseRandomRecipe(RecipeList recipes) { - Recipe randomRecipe = recipes.randomRecipe(); if (recipes.size() == 0) { throw new NullPointerException("There is no recipe in the list to random"); } + Recipe randomRecipe = recipes.randomRecipe(); return randomRecipe; } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 620f6e1d4f..2c20bc9b86 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -111,9 +111,10 @@ public RecipeList listTagRecipes(String[] filters) { if (hasNoRecipeToReturn) { return filteredRecipeList; } - for (Recipe recipe : filteredRecipeList) { - if (!tagRecipes.containsKey(recipe)) { - filteredRecipeList.remove(recipe); + for (int index = filteredRecipeList.size() - 1; index >= 0; index--) { + Recipe currentRecipe = filteredRecipeList.get(index); + if (!tagRecipes.containsKey(currentRecipe)) { + filteredRecipeList.remove(currentRecipe); } } } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 37f61f61f5..832b34b172 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,11 +1,5 @@ package seedu.meal360; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.HashMap; @@ -15,6 +9,8 @@ import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; +import static org.junit.jupiter.api.Assertions.*; + class Meal360Test { @@ -312,6 +308,110 @@ public void testListRecipe() { assertEquals(0, recipeListToPrint.size()); } + @Test + public void testListTagAndAddTag() { + RecipeList recipeListToPrint; + String[] inputs; + // add tag for testing + String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; + parser.parseTagRecipe(addTagInputs, recipes); + + inputs = new String[]{"list", "/t", "breakfast"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 1); + assertEquals(recipeListToPrint.get(0).getName(), "salad"); + + // add tag for testing + addTagInputs = new String[]{"tag", "breakfast", "<<", "pizza"}; + parser.parseTagRecipe(addTagInputs, recipes); + addTagInputs = new String[]{"tag", "western", "<<", "burger"}; + parser.parseTagRecipe(addTagInputs, recipes); + + inputs = new String[]{"list", "/t", "breakfast"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 2); + assertEquals(recipeListToPrint.get(1).getName(), "pizza"); + + inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 0); + + // add tag for testing + addTagInputs = new String[]{"tag", "western", "<<", "pizza"}; + parser.parseTagRecipe(addTagInputs, recipes); + inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 1); + assertEquals(recipeListToPrint.get(0).getName(), "pizza"); + } + + @Test + public void testListTagException() { + String[] inputs; + + //check exception + String[] noArgInputs = new String[]{"list", "/t"}; + assertThrows(IllegalArgumentException.class, () -> parser.parseListRecipe(noArgInputs, recipes)); + + String[] notFoundTagInputs1 = new String[]{"list", "/t", "/t"}; + assertThrows(NullPointerException.class, () -> parser.parseListRecipe(notFoundTagInputs1, recipes)); + + String[] notFoundTagInputs2 = new String[]{"list", "/t", "phone", "&&", "computer"}; + assertThrows(NullPointerException.class, () -> parser.parseListRecipe(notFoundTagInputs2, recipes)); + + String[] beforeAddTagInputs = new String[]{"list", "/t", "breakfast"}; + assertThrows(NullPointerException.class, () -> parser.parseListRecipe(beforeAddTagInputs, recipes)); + + // add tag for testing + inputs = new String[]{"tag", "breakfast", "<<", "salad"}; + parser.parseTagRecipe(inputs, recipes); + inputs = new String[]{"tag", "breakfast", ">>", "salad"}; + parser.parseTagRecipe(inputs, recipes); + + String[] nothingInTagInputs = new String[]{"list", "/t", "breakfast"}; + ui.listRecipe(parser.parseListRecipe(nothingInTagInputs, recipes)); + assertEquals(ui.formatMessage("There is nothing to list."), outContent.toString().trim()); + } + + @Test + public void testRemoveTagAndAddTag() { + String[] inputs; + Recipe invalidRecipe = new Recipe("invalid Recipe", new HashMap<>(1,1)); + + inputs = new String[]{"tag", "western", "<<", "burger"}; + parser.parseTagRecipe(inputs, recipes); + inputs = new String[]{"tag", "western", "<<", "pizza"}; + parser.parseTagRecipe(inputs, recipes); + + //exception + assertThrows(IndexOutOfBoundsException.class, () + -> recipes.removeRecipeFromTag("western", invalidRecipe)); + String[] invalidTagInputs = new String[]{"tag", "random", "tag", ">>", "burger"}; + assertThrows(IndexOutOfBoundsException.class, () + -> parser.parseTagRecipe(invalidTagInputs, recipes)); + + String[] noRecipeInTagInputs = new String[]{"tag", "breakfast", ">>", "pizza"}; + assertThrows(IndexOutOfBoundsException.class, () + -> parser.parseTagRecipe(noRecipeInTagInputs, recipes)); + + inputs = new String[]{"tag", "western", ">>", "pizza"}; + parser.parseTagRecipe(inputs, recipes); + assertEquals(recipes.tags.get("western").size(), 1); + } + + @Test + public void testRandomRecipe() { + // no recipe in the lists + RecipeList blankRecipeList = new RecipeList(); + assertThrows(NullPointerException.class, () -> parser.parseRandomRecipe(blankRecipeList)); + + + // general case + Recipe randomRecipe1 = parser.parseRandomRecipe(recipes); + assertNotNull(randomRecipe1); + assertNotNull(recipes.randomRecipe()); + } + @Test public void testLoadDatabase() { assertDoesNotThrow(database::loadDatabase); From b3e23b9acb19b7bbafabcac460e0c4da8c669bf6 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 30 Mar 2023 11:36:06 +0800 Subject: [PATCH 136/252] update format --- src/test/java/seedu/meal360/Meal360Test.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 832b34b172..e8aeda5305 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -9,8 +9,12 @@ import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; -import static org.junit.jupiter.api.Assertions.*; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; class Meal360Test { From d38279bd33c71244df36c225450752af79392f5a Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 30 Mar 2023 17:03:58 +0800 Subject: [PATCH 137/252] fix delete syntax bug --- docs/UserGuide.md | 6 +++--- src/main/java/seedu/meal360/Parser.java | 26 +++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index f67671b65c..8dc0764668 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -96,7 +96,7 @@ Example of usage: Deletes one, a range, or all recipes currently in list. -Format: `delete INDEX/RANGE` or `delete r/NAME` +Format: `delete INDEX/RANGE` or `delete r/ NAME` * Deletes the recipe(s) specified by the user either through the recipe index or name. * The index refers to the index number shown in the displayed person list. @@ -106,8 +106,8 @@ Example of usage: `delete 1` `delete 1-3` -`delete r/pizza` -`delete r/all` +`delete r/ pizza` +`delete r/ all` ### Tagging/Categorising recipes: `tag` diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index ddc52ec87f..168c6f6800 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -174,20 +174,22 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } public String parseDeleteRecipe(String[] input, RecipeList recipeList) { - assert input[0].equals("delete"); // user inputted recipe name if (input[1].contains("r/")) { // skip over /r in recipe name - String recipeToDelete = input[1].substring(2); + String recipeToDelete = ""; + for (int i = 2; i < input.length; i++) { + recipeToDelete += input[i] + " "; + } + recipeToDelete = recipeToDelete.trim(); if (recipeToDelete.equals("all")) { - StringBuilder allRecipes = new StringBuilder(); - System.out.println("recipeList size: " + recipeList.size()); + String allRecipes = ""; int index = 0; while (recipeList.size() != 0) { - allRecipes.append(recipeList.deleteRecipe(index).getName()).append(", "); + allRecipes += recipeList.deleteRecipe(index).getName() + ", "; } - allRecipes = new StringBuilder(allRecipes.substring(0, allRecipes.length() - 2)); - return allRecipes.toString(); + allRecipes = allRecipes.substring(0, allRecipes.length() - 2); + return allRecipes; } else { int recipeIndex = 0; for (Recipe recipe : recipeList) { @@ -201,19 +203,19 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } // user inputted index of recipe in list } else { - // check if deleting a range of recipes + // deleting a range of recipes if (input[1].length() >= 3) { - StringBuilder rangeRecipes = new StringBuilder(); + String rangeRecipes = ""; int startIndex = Integer.parseInt(input[1].charAt(0) + ""); int endIndex = Integer.parseInt(input[1].charAt(2) + ""); startIndex -= 1; endIndex -= 1; int newSize = recipeList.size() - ((endIndex - startIndex) + 1); while (recipeList.size() != newSize) { - rangeRecipes.append(recipeList.deleteRecipe(startIndex).getName()).append(", "); + rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; } - rangeRecipes = new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2)); - return rangeRecipes.toString(); + rangeRecipes = rangeRecipes.substring(0, rangeRecipes.length() - 2); + return rangeRecipes; } else { int recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based From a8a7ac279e4d7489b1ff1f3c23d8b013e9c7a65f Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 30 Mar 2023 18:12:02 +0800 Subject: [PATCH 138/252] add sequence diagram for delete function --- docs/DeveloperGuide.md | 3 +-- .../DeleteFunction/DeleteFunction.jpg | Bin 0 -> 46986 bytes 2 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 157739c80e..506079997f 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -214,8 +214,7 @@ It is implemented through the following step: 3. In `RecipeList`, `deleteRecipe()` is executed to delete the recipe at whatever index is passed as a parameter, and return the `Recipe` object at that index/the one just deleted. -The sequence diagram below shows how this feature works: -{UML will be added here.} +![](../docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg) ### Add Recipes Feature diff --git a/docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg b/docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b03bccbb96635db1ac03d7ebba1184b4ee000ed3 GIT binary patch literal 46986 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 literal 0 HcmV?d00001 From 1dfbfbdf9f0c0ca4c8e2169e35b7be65c21c4582 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Thu, 30 Mar 2023 22:58:04 +0800 Subject: [PATCH 139/252] no message --- src/main/java/seedu/meal360/Database.java | 361 +++--- src/main/java/seedu/meal360/Exceptions.java | 11 +- src/main/java/seedu/meal360/Ingredient.java | 42 +- .../java/seedu/meal360/IngredientList.java | 169 +-- src/main/java/seedu/meal360/Meal360.java | 405 +++---- src/main/java/seedu/meal360/Parser.java | 1046 +++++++++-------- src/main/java/seedu/meal360/Recipe.java | 70 +- src/main/java/seedu/meal360/RecipeList.java | 237 ++-- src/main/java/seedu/meal360/Ui.java | 181 +-- src/main/java/seedu/meal360/WeeklyPlan.java | 42 +- 10 files changed, 1292 insertions(+), 1272 deletions(-) diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index a9ece4bbc0..40c7205f23 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -11,192 +11,193 @@ public class Database { - private static final String recipesDatabaseFilepath = - "." + System.getProperty("file.separator") + "src" + System.getProperty("file.separator") + "main" - + System.getProperty("file.separator") + "resources" + System.getProperty( - "file.separator") + "recipesDatabase.json"; - - public RecipeList loadDatabase() throws IOException { - RecipeList database; - Gson gson = new Gson(); - - // Check if the JSON file exists and create one if it does not - File file = new File(recipesDatabaseFilepath); - if (!file.exists()) { - try { - // Create the parent directory if it does not exist - File parentDir = file.getParentFile(); - if (!parentDir.exists()) { - parentDir.mkdirs(); - } - file.createNewFile(); - } catch (IOException e) { - throw new IOException("Error creating database file."); - } - - // Return a default recipe list if database file does not exist - return defaultRecipeList(); + private static final String recipesDatabaseFilepath = + "." + System.getProperty("file.separator") + "src" + System.getProperty("file.separator") + + "main" + + System.getProperty("file.separator") + "resources" + System.getProperty( + "file.separator") + "recipesDatabase.json"; + + public RecipeList loadDatabase() throws IOException { + RecipeList database; + Gson gson = new Gson(); + + // Check if the JSON file exists and create one if it does not + File file = new File(recipesDatabaseFilepath); + if (!file.exists()) { + try { + // Create the parent directory if it does not exist + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); } + file.createNewFile(); + } catch (IOException e) { + throw new IOException("Error creating database file."); + } - // Read the JSON data from the file if it already exists - try { - // Read the JSON data from the file - BufferedReader reader = new BufferedReader(new FileReader(recipesDatabaseFilepath)); - database = gson.fromJson(reader, RecipeList.class); - reader.close(); - } catch (FileNotFoundException e) { - throw new FileNotFoundException("Unable to find database file."); - } catch (IOException e) { - throw new IOException("Error reading from database file."); - } - - // Ensure non empty recipeList is returned - if (database == null) { - return defaultRecipeList(); - } else { - return database; - } + // Return a default recipe list if database file does not exist + return defaultRecipeList(); } - public void saveDatabase(RecipeList recipeList) throws IOException { - Gson gson = new Gson(); - // Write the data object to the JSON file - FileWriter writer; - writer = new FileWriter(recipesDatabaseFilepath); - gson.toJson(recipeList, writer); - writer.close(); + // Read the JSON data from the file if it already exists + try { + // Read the JSON data from the file + BufferedReader reader = new BufferedReader(new FileReader(recipesDatabaseFilepath)); + database = gson.fromJson(reader, RecipeList.class); + reader.close(); + } catch (FileNotFoundException e) { + throw new FileNotFoundException("Unable to find database file."); + } catch (IOException e) { + throw new IOException("Error reading from database file."); } - public RecipeList defaultRecipeList() { - RecipeList defaultRecipeList = new RecipeList(); - defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap<>() { - { - put("Chicken", 1); - put("Rice", 1); - put("Salt", 1); - put("Pepper", 1); - } - })); - - defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap<>() { - { - put("Ripe mixed-colour cherry tomatoes ", 250); - put("Flat-leaf parsley", 15); - put("Garlic cloves", 2); - put("Plain flour", 2); - put("Eggs", 2); - put("Breadcrumbs", 100); - put("Vegetable oil", 2); - put("Feta cheese", 30); - } - })); - - defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap<>() { - { - put("Chicken breast fillets", 2); - put("Mushrooms", 250); - put("Onion", 1); - put("Plain flour", 2); - put("Butter", 2); - put("Milk", 2); - put("Puff pastry", 1); - } - })); - - defaultRecipeList.add(new Recipe("Seafood paella", new HashMap<>() { - { - put("Prawns", 500); - put("Mussels", 500); - put("Chorizo", 100); - put("Onion", 1); - put("Garlic cloves", 2); - put("Rice", 1); - put("Cherry tomatoes", 250); - put("Vegetable oil", 2); - put("Chicken stock", 1); - put("Saffron", 1); - } - })); - - defaultRecipeList.add(new Recipe("Avocado toast", new HashMap<>() { - { - put("Avocado", 1); - put("Bread", 2); - put("Lemon", 1); - put("Salt", 1); - put("Pepper", 1); - } - })); - - defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap<>() { - { - put("Italian sausage", 1); - put("Onion", 1); - put("Garlic cloves", 2); - put("Carrot", 1); - put("Celery", 1); - put("Dried oregano", 1); - put("Dried basil", 1); - put("Dried thyme", 1); - put("Dried parsley", 1); - put("Dried rosemary", 1); - put("Chicken stock", 1); - put("Orzo", 1); - put("Parmesan cheese", 1); - } - })); - - defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap<>() { - { - put("Chicken breast fillets", 2); - put("Mushrooms", 250); - put("Onion", 1); - put("Garlic cloves", 2); - put("Plain flour", 2); - put("Butter", 2); - put("Milk", 2); - put("Pasta", 1); - } - })); - - defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap<>() { - { - put("Pasta", 1); - put("Hummus", 1); - put("Garlic cloves", 2); - put("Lemon", 1); - put("Salt", 1); - put("Pepper", 1); - } - })); - - defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap<>() { - { - put("Ground beef", 1); - put("Potato", 1); - put("Onion", 1); - put("Garlic cloves", 2); - put("Tomato paste", 1); - put("Tomato sauce", 1); - put("Beef stock", 1); - put("Cheddar cheese", 1); - } - })); - - defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap<>() { - { - put("Chicken breast fillets", 2); - put("Macaroni", 1); - put("Butter", 2); - put("Flour", 2); - put("Milk", 2); - put("Cheddar cheese", 1); - put("Blue cheese", 1); - put("Hot sauce", 1); - } - })); - - return defaultRecipeList; + // Ensure non empty recipeList is returned + if (database == null) { + return defaultRecipeList(); + } else { + return database; } + } + + public void saveDatabase(RecipeList recipeList) throws IOException { + Gson gson = new Gson(); + // Write the data object to the JSON file + FileWriter writer; + writer = new FileWriter(recipesDatabaseFilepath); + gson.toJson(recipeList, writer); + writer.close(); + } + + public RecipeList defaultRecipeList() { + RecipeList defaultRecipeList = new RecipeList(); + defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap<>() { + { + put("Chicken", 1); + put("Rice", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap<>() { + { + put("Ripe mixed-colour cherry tomatoes ", 250); + put("Flat-leaf parsley", 15); + put("Garlic cloves", 2); + put("Plain flour", 2); + put("Eggs", 2); + put("Breadcrumbs", 100); + put("Vegetable oil", 2); + put("Feta cheese", 30); + } + })); + + defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap<>() { + { + put("Chicken breast fillets", 2); + put("Mushrooms", 250); + put("Onion", 1); + put("Plain flour", 2); + put("Butter", 2); + put("Milk", 2); + put("Puff pastry", 1); + } + })); + + defaultRecipeList.add(new Recipe("Seafood paella", new HashMap<>() { + { + put("Prawns", 500); + put("Mussels", 500); + put("Chorizo", 100); + put("Onion", 1); + put("Garlic cloves", 2); + put("Rice", 1); + put("Cherry tomatoes", 250); + put("Vegetable oil", 2); + put("Chicken stock", 1); + put("Saffron", 1); + } + })); + + defaultRecipeList.add(new Recipe("Avocado toast", new HashMap<>() { + { + put("Avocado", 1); + put("Bread", 2); + put("Lemon", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap<>() { + { + put("Italian sausage", 1); + put("Onion", 1); + put("Garlic cloves", 2); + put("Carrot", 1); + put("Celery", 1); + put("Dried oregano", 1); + put("Dried basil", 1); + put("Dried thyme", 1); + put("Dried parsley", 1); + put("Dried rosemary", 1); + put("Chicken stock", 1); + put("Orzo", 1); + put("Parmesan cheese", 1); + } + })); + + defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap<>() { + { + put("Chicken breast fillets", 2); + put("Mushrooms", 250); + put("Onion", 1); + put("Garlic cloves", 2); + put("Plain flour", 2); + put("Butter", 2); + put("Milk", 2); + put("Pasta", 1); + } + })); + + defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap<>() { + { + put("Pasta", 1); + put("Hummus", 1); + put("Garlic cloves", 2); + put("Lemon", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap<>() { + { + put("Ground beef", 1); + put("Potato", 1); + put("Onion", 1); + put("Garlic cloves", 2); + put("Tomato paste", 1); + put("Tomato sauce", 1); + put("Beef stock", 1); + put("Cheddar cheese", 1); + } + })); + + defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap<>() { + { + put("Chicken breast fillets", 2); + put("Macaroni", 1); + put("Butter", 2); + put("Flour", 2); + put("Milk", 2); + put("Cheddar cheese", 1); + put("Blue cheese", 1); + put("Hot sauce", 1); + } + })); + + return defaultRecipeList; + } } diff --git a/src/main/java/seedu/meal360/Exceptions.java b/src/main/java/seedu/meal360/Exceptions.java index 2c96cbcd2d..d64ecf571e 100644 --- a/src/main/java/seedu/meal360/Exceptions.java +++ b/src/main/java/seedu/meal360/Exceptions.java @@ -2,11 +2,12 @@ public class Exceptions { - // ingredient not found exception - public static class IngredientNotFoundException extends Exception { - public IngredientNotFoundException() { - super("Ingredient not found"); - } + // ingredient not found exception + public static class IngredientNotFoundException extends Exception { + + public IngredientNotFoundException() { + super("Ingredient not found"); } + } } diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java index bead660e93..aa7c1026ba 100644 --- a/src/main/java/seedu/meal360/Ingredient.java +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -3,27 +3,29 @@ import java.time.LocalDate; public class Ingredient { - private static final Parser parser = new Parser(); - public String ingredientName; - public Integer ingredientCount; - public LocalDate expiryDate; - public Boolean expired; - private String unit; - public Ingredient(String ingredientName, Integer ingredientCount, String unit, String expiryDate) { - this.ingredientName = ingredientName; - this.ingredientCount = ingredientCount; - this.unit = unit; - // parse expiry date using parseDate method - this.expiryDate = parser.parseDate(expiryDate); - this.updateExpired(); - } + private static final Parser parser = new Parser(); + public String ingredientName; + public Integer ingredientCount; + public LocalDate expiryDate; + public Boolean expired; + private String unit; + + public Ingredient(String ingredientName, Integer ingredientCount, String unit, + String expiryDate) { + this.ingredientName = ingredientName; + this.ingredientCount = ingredientCount; + this.unit = unit; + // parse expiry date using parseDate method + this.expiryDate = parser.parseDate(expiryDate); + this.updateExpired(); + } - public void updateExpired() { - if (expiryDate.isBefore(LocalDate.now())) { - expired = true; - } else { - expired = false; - } + public void updateExpired() { + if (expiryDate.isBefore(LocalDate.now())) { + expired = true; + } else { + expired = false; } + } } diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index 5929999708..40fbc71fa7 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -4,106 +4,107 @@ import java.time.LocalDate; public class IngredientList extends HashMap { - private static final Parser parser = new Parser(); - // public method to find count of ingredient - public Integer findIngredientCount(String ingredientName) { - try { - if (this.containsKey(ingredientName)) { - return this.get(ingredientName).ingredientCount; - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - return null; - } + private static final Parser parser = new Parser(); + + // public method to find count of ingredient + public Integer findIngredientCount(String ingredientName) { + try { + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).ingredientCount; + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + return null; } + } - // public method to find expiry date of ingredient - public LocalDate findExpiryDate(String ingredientName) { - try { - if (this.containsKey(ingredientName)) { - return this.get(ingredientName).expiryDate; - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - return null; - } + // public method to find expiry date of ingredient + public LocalDate findExpiryDate(String ingredientName) { + try { + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).expiryDate; + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + return null; } + } + + public void addIngredient(Ingredient ingredient) { + super.put(ingredient.ingredientName, ingredient); + } - public void addIngredient(Ingredient ingredient) { + public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) { + try { + if (this.containsKey(ingredient.ingredientName)) { + ingredient.ingredientCount = ingredientCount; + ingredient.expiryDate = parser.parseDate(expiryDate); + ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); super.put(ingredient.ingredientName, ingredient); + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + System.out.println("Ingredient not found"); } + } - public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) { - try { - if (this.containsKey(ingredient.ingredientName)) { - ingredient.ingredientCount = ingredientCount; - ingredient.expiryDate = parser.parseDate(expiryDate); - ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); - super.put(ingredient.ingredientName, ingredient); - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - System.out.println("Ingredient not found"); - } + public void deleteIngredient(String ingredient) { + try { + if (this.containsKey(ingredient)) { + this.remove(ingredient); + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + System.out.println("Ingredient not found"); } + } - public void deleteIngredient(String ingredient) { - try { - if (this.containsKey(ingredient)) { - this.remove(ingredient); - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - System.out.println("Ingredient not found"); - } + // private indexed list of ingredients, count and expiry date + private String listIngredients() { + String ingredientList = ""; + int index = 1; + for (Ingredient ingredient : this.values()) { + ingredientList += String.format("%d. %s (count: %d, expires on %s)", index, + ingredient.ingredientName, ingredient.ingredientCount, ingredient.expiryDate); } + return ingredientList; + } - // private indexed list of ingredients, count and expiry date - private String listIngredients() { - String ingredientList = ""; - int index = 1; - for (Ingredient ingredient : this.values()) { - ingredientList += String.format("%d. %s (count: %d, expires on %s)", index, - ingredient.ingredientName, ingredient.ingredientCount, ingredient.expiryDate); - } - return ingredientList; - } + // public method to print ingredients in list with indexing + public void printIngredients() { + System.out.println(listIngredients()); + } - // public method to print ingredients in list with indexing - public void printIngredients() { - System.out.println(listIngredients()); + // public method to print expired ingredients and expiry date + // if no expired ingredients, print "No expired ingredients" + public void printExpiredIngredients() { + String expiredIngredients = ""; + int index = 1; + for (Ingredient ingredient : this.values()) { + if (ingredient.expired) { + expiredIngredients += String.format("%d. %s (expires on %s)", index, + ingredient.ingredientName, ingredient.expiryDate); + } } - - // public method to print expired ingredients and expiry date - // if no expired ingredients, print "No expired ingredients" - public void printExpiredIngredients() { - String expiredIngredients = ""; - int index = 1; - for (Ingredient ingredient : this.values()) { - if (ingredient.expired) { - expiredIngredients += String.format("%d. %s (expires on %s)", index, - ingredient.ingredientName, ingredient.expiryDate); - } - } - if (expiredIngredients.equals("")) { - System.out.println("No expired ingredients"); - } else { - System.out.println(expiredIngredients); - } + if (expiredIngredients.equals("")) { + System.out.println("No expired ingredients"); + } else { + System.out.println(expiredIngredients); } + } - // public method to clear all ingredients - public void clearIngredients() { - this.clear(); - } + // public method to clear all ingredients + public void clearIngredients() { + this.clear(); + } - // public method to clear expired ingredients - public void clearExpiredIngredients() { - for (Ingredient ingredient : this.values()) { - if (ingredient.expired) { - this.remove(ingredient.ingredientName); - } - } + // public method to clear expired ingredients + public void clearExpiredIngredients() { + for (Ingredient ingredient : this.values()) { + if (ingredient.expired) { + this.remove(ingredient.ingredientName); + } } + } } diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 8f84dfb40f..57f10416cd 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -7,217 +7,218 @@ public class Meal360 { - /** - * Main entry-point for the java.duke.Meal360 application. - */ - - private static Boolean canExit = false; - private static final Ui ui = new Ui(); - private static final Parser parser = new Parser(); - private static final Database database = new Database(); - private static RecipeList recipeList = new RecipeList(); - private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); - - public static void startApp() { + /** + * Main entry-point for the java.duke.Meal360 application. + */ + + private static Boolean canExit = false; + private static final Ui ui = new Ui(); + private static final Parser parser = new Parser(); + private static final Database database = new Database(); + private static RecipeList recipeList = new RecipeList(); + private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); + + public static void startApp() { + ui.printSeparator(); + ui.printWelcomeMessage(); + ui.printSeparator(); + + // Load database + ui.printMessage("Loading database..."); + try { + recipeList = database.loadDatabase(); + ui.printMessage("Database loaded successfully."); + } catch (Exception e) { + ui.printMessage("Error loading database, loading default database instead."); + ui.printMessage("Overwriting database with new default database..."); + recipeList = database.defaultRecipeList(); + } + + ui.printSeparator(); + } + + public static void receiveInput(String input) { + input = input.replaceAll("\\s+", " "); + String[] command = input.trim().split(" "); + + if (input.equalsIgnoreCase("bye")) { + canExit = true; + } else if (command[0].equals("delete")) { + ui.printSeparator(); + try { + String deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + ui.printMessage("Noted. I've removed this recipe:"); + ui.printMessage(deletedRecipe); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = + "Please enter a valid recipe number or name. You did not enter a recipe number or " + + "name."; + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number or name. You entered %s, " + + "which is in invalid.", + command[1]); + ui.printMessage(errorMessage); + } + ui.printSeparator(); + } else if (command[0].equals("view")) { + ui.printSeparator(); + try { + Recipe recipe = parser.parseViewRecipe(command, recipeList); + ui.printRecipe(recipe); + } catch (NumberFormatException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("list")) { + try { ui.printSeparator(); - ui.printWelcomeMessage(); + RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); + ui.listRecipe(recipeListToPrint); + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("add")) { + ui.printSeparator(); + try { + Recipe newRecipe = parser.parseAddRecipe(command, recipeList); + ui.printMessage("I've added this new recipe:" + newRecipe.getName()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = "Please enter a valid recipe name."; + ui.printMessage(errorMessage); + } catch (NullPointerException e) { + String errorMessage = "Recipe already exists. Add a new recipe."; + ui.printMessage(errorMessage); + } + ui.printSeparator(); + } else if (command[0].equals("edit")) { + ui.printSeparator(); + try { + Recipe recipeToEdit = parser.parseEditRecipe(command, recipeList); ui.printSeparator(); - - // Load database - ui.printMessage("Loading database..."); - try { - recipeList = database.loadDatabase(); - ui.printMessage("Database loaded successfully."); - } catch (Exception e) { - ui.printMessage("Error loading database, loading default database instead."); - ui.printMessage("Overwriting database with new default database..."); - recipeList = database.defaultRecipeList(); - } - + ui.printMessage("I've edited this recipe:" + recipeToEdit.getName()); + } catch (NumberFormatException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is not a number.", + command[1]); + ui.printMessage(errorMessage); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = "Please enter a valid recipe name."; + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", + command[1]); + ui.printMessage(errorMessage); + } catch (NullPointerException e) { + String errorMessage = "Recipe doesn't exist for editing."; + ui.printMessage(errorMessage); + } + ui.printSeparator(); + } else if (command[0].equals("tag")) { + try { ui.printSeparator(); - } - - public static void receiveInput(String input) { - input = input.replaceAll("\\s+", " "); - String[] command = input.trim().split(" "); - - if (input.equalsIgnoreCase("bye")) { - canExit = true; - } else if (command[0].equals("delete")) { - ui.printSeparator(); - try { - String deletedRecipe = parser.parseDeleteRecipe(command, recipeList); - ui.printMessage("Noted. I've removed this recipe:"); - ui.printMessage(deletedRecipe); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = "Please enter a valid recipe number or name. You did not enter a recipe number or " - + "name."; - ui.printMessage(errorMessage); - } catch (IndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number or name. You entered %s, " - + "which is in invalid.", - command[1]); - ui.printMessage(errorMessage); - } - ui.printSeparator(); - } else if (command[0].equals("view")) { - ui.printSeparator(); - try { - Recipe recipe = parser.parseViewRecipe(command, recipeList); - ui.printRecipe(recipe); - } catch (NumberFormatException | IndexOutOfBoundsException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("list")) { - try { - ui.printSeparator(); - RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); - ui.listRecipe(recipeListToPrint); - } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("add")) { - ui.printSeparator(); - try { - Recipe newRecipe = parser.parseAddRecipe(command, recipeList); - ui.printMessage("I've added this new recipe:" + newRecipe.getName()); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = "Please enter a valid recipe name."; - ui.printMessage(errorMessage); - } catch (NullPointerException e) { - String errorMessage = "Recipe already exists. Add a new recipe."; - ui.printMessage(errorMessage); - } - ui.printSeparator(); - } else if (command[0].equals("edit")) { - ui.printSeparator(); - try { - Recipe recipeToEdit = parser.parseEditRecipe(command, recipeList); - ui.printSeparator(); - ui.printMessage("I've edited this recipe:" + recipeToEdit.getName()); - } catch (NumberFormatException e) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is not a number.", - command[1]); - ui.printMessage(errorMessage); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = "Please enter a valid recipe name."; - ui.printMessage(errorMessage); - } catch (IndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", - command[1]); - ui.printMessage(errorMessage); - } catch (NullPointerException e) { - String errorMessage = "Recipe doesn't exist for editing."; - ui.printMessage(errorMessage); - } - ui.printSeparator(); - } else if (command[0].equals("tag")) { - try { - ui.printSeparator(); - String tag = parser.parseTagRecipe(command, recipeList); - ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); - } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("random")) { - ui.printSeparator(); - try { - Recipe randomRecipe = parser.parseRandomRecipe(recipeList); - ui.printRecipe(randomRecipe); - } catch (NumberFormatException | IndexOutOfBoundsException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("weekly")) { - try { - ui.printSeparator(); - WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); - - switch (command[1]) { - case "/add": - case "/multiadd": - weeklyPlan.addPlans(recipeMap); - ui.printMessage("I've added the recipes to your weekly plan!"); - break; - case "/delete": - case "/multidelete": - weeklyPlan.deletePlans(recipeMap); - ui.printMessage("I've deleted the recipes from your weekly plan!"); - break; - case "/clear": - weeklyPlan.clearPlan(); - ui.printMessage("I've cleared your entire weekly plan!"); - break; - default: - ui.printMessage("Please enter a valid command."); - break; - } - } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException - | ArrayIndexOutOfBoundsException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("available")) { - // list recipes with ingredients all in ingredient list - ui.printSeparator(); - RecipeList availableRecipes = recipeList.availableRecipes(); - ui.listAvailableRecipes(availableRecipes); - ui.printSeparator(); - } else if (command[0].equals("weeklyingredients")) { - ui.printSeparator(); - ui.printWeeklyIngredients(weeklyPlan, recipeList); - ui.printSeparator(); - } else if (command[0].equals("weeklyplan")) { - ui.printSeparator(); - ui.printWeeklyPlan(weeklyPlan); - ui.printSeparator(); - } else if (command[0].equals("help")) { - ui.printSeparator(); - ui.printHelp(); - ui.printSeparator(); - } else { - ui.printSeparator(); - ui.printMessage("I'm sorry, but I don't know what that means :-("); - ui.printSeparator(); - } - } - - public static void exitApp() { + String tag = parser.parseTagRecipe(command, recipeList); + ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("random")) { + ui.printSeparator(); + try { + Recipe randomRecipe = parser.parseRandomRecipe(recipeList); + ui.printRecipe(randomRecipe); + } catch (NumberFormatException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("weekly")) { + try { ui.printSeparator(); - - // Save database - ui.printMessage("Saving database..."); - try { - database.saveDatabase(recipeList); - ui.printMessage("Database saved successfully."); - } catch (IOException error) { - ui.printMessage("Error saving database."); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); + + switch (command[1]) { + case "/add": + case "/multiadd": + weeklyPlan.addPlans(recipeMap); + ui.printMessage("I've added the recipes to your weekly plan!"); + break; + case "/delete": + case "/multidelete": + weeklyPlan.deletePlans(recipeMap); + ui.printMessage("I've deleted the recipes from your weekly plan!"); + break; + case "/clear": + weeklyPlan.clearPlan(); + ui.printMessage("I've cleared your entire weekly plan!"); + break; + default: + ui.printMessage("Please enter a valid command."); + break; } - - ui.printGoodbyeMessage(); - ui.printSeparator(); + } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException + | ArrayIndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("available")) { + // list recipes with ingredients all in ingredient list + ui.printSeparator(); + RecipeList availableRecipes = recipeList.availableRecipes(); + ui.listAvailableRecipes(availableRecipes); + ui.printSeparator(); + } else if (command[0].equals("weeklyingredients")) { + ui.printSeparator(); + ui.printWeeklyIngredients(weeklyPlan, recipeList); + ui.printSeparator(); + } else if (command[0].equals("weeklyplan")) { + ui.printSeparator(); + ui.printWeeklyPlan(weeklyPlan); + ui.printSeparator(); + } else if (command[0].equals("help")) { + ui.printSeparator(); + ui.printHelp(); + ui.printSeparator(); + } else { + ui.printSeparator(); + ui.printMessage("I'm sorry, but I don't know what that means :-("); + ui.printSeparator(); + } + } + + public static void exitApp() { + ui.printSeparator(); + + // Save database + ui.printMessage("Saving database..."); + try { + database.saveDatabase(recipeList); + ui.printMessage("Database saved successfully."); + } catch (IOException error) { + ui.printMessage("Error saving database."); } - public static void main(String[] args) { + ui.printGoodbyeMessage(); + ui.printSeparator(); + } - startApp(); + public static void main(String[] args) { - String line; - Scanner userInput = new Scanner(System.in); + startApp(); - do { - line = userInput.nextLine(); - receiveInput(line); - } while (!canExit); + String line; + Scanner userInput = new Scanner(System.in); - exitApp(); - } + do { + line = userInput.nextLine(); + receiveInput(line); + } while (!canExit); + + exitApp(); + } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index db108cc4a9..d3e36c5b86 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -11,571 +11,579 @@ public class Parser { - Ui ui = new Ui(); + Ui ui = new Ui(); - public String combineWords(String[] input, int startIndex, int length) { - StringBuilder word = new StringBuilder(input[startIndex]); - for (int i = startIndex + 1; i < length; i++) { - word.append(" ").append(input[i]); - } - - return word.toString(); - } - - public HashMap parseIngredientName(String[] command){ - HashMap ingredients = new HashMap<>(); - int flag = 0; - StringBuilder add = null; - String ingredientName; - int ingredientQuantity; - int indexOfEqual; - - for (String s : command) { - try{ - indexOfEqual = s.indexOf("="); - if (indexOfEqual == -1) { - if (add != null) { - add.append(" ").append(s); - } else { - add = new StringBuilder(s); - } - flag++; - - } else { - if (flag > 0) { - indexOfEqual = s.indexOf("="); - ingredientName = (s.substring(0, indexOfEqual)); - ingredientName = add + " " + ingredientName; - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); - flag = 0; - add = null; - } else { - ingredientName = s.substring(0, indexOfEqual); - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); - } - - ingredients.put(ingredientName, ingredientQuantity); - - } - } catch (NumberFormatException e) { - ui.printSeparator(); - String errorMessage = "Please enter ingredients properly![eg: chicken=100]"; - ui.printMessage(errorMessage); - ui.printSeparator(); - } - } - return ingredients; + public String combineWords(String[] input, int startIndex, int length) { + StringBuilder word = new StringBuilder(input[startIndex]); + for (int i = startIndex + 1; i < length; i++) { + word.append(" ").append(input[i]); } - public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { - String recipeName = combineWords(input, 2, input.length); - if(recipeList.findByName(recipeName)!=null){ - return null; - } - HashMap ingredients = new HashMap<>(); - Scanner userInput = new Scanner(System.in); - System.out.println("Please Enter The Ingredients & Quantity: "); - while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - ui.printSeparator(); - break; - } else { - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - } - } - Recipe newRecipe = new Recipe(recipeName, ingredients); - recipeList.addRecipe(newRecipe); - return newRecipe; - } - - public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { - String recipeName = combineWords(input, 2, input.length); - Recipe recipeToEdit; - HashMap ingredients; - Scanner userInput = new Scanner(System.in); - if (recipeList.findByName(recipeName) == null) { - return null; - } - recipeToEdit = recipeList.findByName(recipeName); - System.out.println("Do you want to edit recipe fully or partially?"); - System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); - - Scanner getInput = new Scanner(System.in); - int index = getInput.nextInt(); - if (index == 1) { - System.out.println("Please Enter New Ingredients & Quantity: "); - while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - break; - } - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - recipeList.editRecipe(recipeToEdit, ingredients); - } - } else if (index == 2) { - System.out.println("These are the ingredients for the recipe:"); - ui.printSeparator(); - Recipe recipe = parseViewRecipe(recipeName, recipeList); - ui.printRecipe(recipe); - ui.printSeparator(); - System.out.println("Which ingredient do you want to change?"); - int ingredientIndex = getInput.nextInt(); - ingredientIndex -= 1; - int count = 0; - String ingredientToRemove = null; - for (String ingredient : recipeToEdit.getIngredients().keySet()) { - if (ingredientIndex == count) { - ingredientToRemove = ingredient; - System.out.println("Ingredient to be changed:"); - ui.printSeparator(); - String toPrint = String.format("%s(%d)", ingredient, recipeToEdit.getIngredients().get(ingredient)); - System.out.println(ui.formatMessage(toPrint)); - ui.printSeparator(); - break; - } - count++; - } - System.out.println("Please enter the new ingredient:"); - String line = userInput.nextLine(); - String command = line.replaceAll("\\s+", " "); - int indexOfEqual = command.indexOf("="); - String newIngredientName = command.substring(0,indexOfEqual); - int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual+1)); - recipeToEdit.getIngredients().remove(ingredientToRemove); - recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); - recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); - } else if (index == 3) { - HashMap newIngredientList = recipeToEdit.getIngredients(); - System.out.println("These are the current ingredients:"); - ui.printSeparator(); - Recipe recipe = parseViewRecipe(recipeName, recipeList); - ui.printRecipe(recipe); - ui.printSeparator(); - System.out.println("Please Enter Additional Ingredients & Quantity (Enter done when complete): "); - while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - ui.printSeparator(); - break; - } else { - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - newIngredientList.putAll(ingredients); - } - } - recipeList.editRecipe(recipeToEdit, newIngredientList); - } + return word.toString(); + } + + public HashMap parseIngredientName(String[] command) { + HashMap ingredients = new HashMap<>(); + int flag = 0; + StringBuilder add = null; + String ingredientName; + int ingredientQuantity; + int indexOfEqual; + + for (String s : command) { + try { + indexOfEqual = s.indexOf("="); + if (indexOfEqual == -1) { + if (add != null) { + add.append(" ").append(s); + } else { + add = new StringBuilder(s); + } + flag++; - return recipeToEdit; - } - - public String parseDeleteRecipe(String[] input, RecipeList recipeList) { - assert input[0].equals("delete"); - // user inputted recipe name - if (input[1].contains("r/")) { - // skip over /r in recipe name - String recipeToDelete = input[1].substring(2); - if (recipeToDelete.equals("all")) { - StringBuilder allRecipes = new StringBuilder(); - System.out.println("recipeList size: " + recipeList.size()); - int index = 0; - while (recipeList.size() != 0) { - allRecipes.append(recipeList.deleteRecipe(index).getName()).append(", "); - } - allRecipes = new StringBuilder(allRecipes.substring(0, allRecipes.length() - 2)); - return allRecipes.toString(); - } else { - int recipeIndex = 0; - for (Recipe recipe : recipeList) { - // find index of recipe we want to delete - if (recipe.getName().equals(recipeToDelete)) { - break; - } - recipeIndex++; - } - return recipeList.deleteRecipe(recipeIndex).getName(); - } - // user inputted index of recipe in list } else { - // check if deleting a range of recipes - if (input[1].length() >= 3) { - StringBuilder rangeRecipes = new StringBuilder(); - int startIndex = Integer.parseInt(input[1].charAt(0) + ""); - int endIndex = Integer.parseInt(input[1].charAt(2) + ""); - startIndex -= 1; - endIndex -= 1; - int newSize = recipeList.size() - ((endIndex - startIndex) + 1); - while (recipeList.size() != newSize) { - rangeRecipes.append(recipeList.deleteRecipe(startIndex).getName()).append(", "); - } - rangeRecipes = new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2)); - return rangeRecipes.toString(); - } else { - int recipeIndex = Integer.parseInt(input[1]); - // need to subtract 1 since list is 1-based - return recipeList.deleteRecipe(recipeIndex - 1).getName(); - } - } + if (flag > 0) { + indexOfEqual = s.indexOf("="); + ingredientName = (s.substring(0, indexOfEqual)); + ingredientName = add + " " + ingredientName; + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + flag = 0; + add = null; + } else { + ingredientName = s.substring(0, indexOfEqual); + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + } + + ingredients.put(ingredientName, ingredientQuantity); + + } + } catch (NumberFormatException e) { + ui.printSeparator(); + String errorMessage = "Please enter ingredients properly![eg: chicken=100]"; + ui.printMessage(errorMessage); + ui.printSeparator(); + } } + return ingredients; + } - public String parseTagRecipe(String[] inputs, RecipeList recipeList) { - String tag; - boolean isOnlyTagWordInCommand = inputs.length == 1; - boolean isAddTag; - boolean isRemoveTag; - - if (isOnlyTagWordInCommand) { - throw new IllegalArgumentException("Please indicate at least a tag and a recipe."); - } - - StringBuilder commandString = new StringBuilder(inputs[1]); - for (int i = 2; i < inputs.length; i++) { - commandString.append(" ").append(inputs[i]); - } - - isAddTag = commandString.indexOf(">>") == -1 && commandString.indexOf("<<") != -1; - isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; - - if (!(isAddTag || isRemoveTag)) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } else if (isAddTag) { - tag = parseAddRecipeTag(commandString.toString(), recipeList); - } else if (isRemoveTag) { - tag = parseRemoveRecipeTag(commandString.toString(), recipeList); + public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { + String recipeName = combineWords(input, 2, input.length); + if (recipeList.findByName(recipeName) != null) { + return null; + } + HashMap ingredients = new HashMap<>(); + Scanner userInput = new Scanner(System.in); + System.out.println("Please Enter The Ingredients & Quantity: "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + break; + } else { + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + } + } + Recipe newRecipe = new Recipe(recipeName, ingredients); + recipeList.addRecipe(newRecipe); + return newRecipe; + } + + public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { + String recipeName = combineWords(input, 2, input.length); + Recipe recipeToEdit; + HashMap ingredients; + Scanner userInput = new Scanner(System.in); + if (recipeList.findByName(recipeName) == null) { + return null; + } + recipeToEdit = recipeList.findByName(recipeName); + System.out.println("Do you want to edit recipe fully or partially?"); + System.out.println( + "Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); + + Scanner getInput = new Scanner(System.in); + int index = getInput.nextInt(); + if (index == 1) { + System.out.println("Please Enter New Ingredients & Quantity: "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + break; + } + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + recipeList.editRecipe(recipeToEdit, ingredients); + } + } else if (index == 2) { + System.out.println("These are the ingredients for the recipe:"); + ui.printSeparator(); + Recipe recipe = parseViewRecipe(recipeName, recipeList); + ui.printRecipe(recipe); + ui.printSeparator(); + System.out.println("Which ingredient do you want to change?"); + int ingredientIndex = getInput.nextInt(); + ingredientIndex -= 1; + int count = 0; + String ingredientToRemove = null; + for (String ingredient : recipeToEdit.getIngredients().keySet()) { + if (ingredientIndex == count) { + ingredientToRemove = ingredient; + System.out.println("Ingredient to be changed:"); + ui.printSeparator(); + String toPrint = String.format("%s(%d)", ingredient, + recipeToEdit.getIngredients().get(ingredient)); + System.out.println(ui.formatMessage(toPrint)); + ui.printSeparator(); + break; + } + count++; + } + System.out.println("Please enter the new ingredient:"); + String line = userInput.nextLine(); + String command = line.replaceAll("\\s+", " "); + int indexOfEqual = command.indexOf("="); + String newIngredientName = command.substring(0, indexOfEqual); + int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual + 1)); + recipeToEdit.getIngredients().remove(ingredientToRemove); + recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); + recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); + } else if (index == 3) { + HashMap newIngredientList = recipeToEdit.getIngredients(); + System.out.println("These are the current ingredients:"); + ui.printSeparator(); + Recipe recipe = parseViewRecipe(recipeName, recipeList); + ui.printRecipe(recipe); + ui.printSeparator(); + System.out.println( + "Please Enter Additional Ingredients & Quantity (Enter done when complete): "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + break; } else { - throw new IllegalArgumentException("Invalid command."); + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + newIngredientList.putAll(ingredients); } - return tag; + } + recipeList.editRecipe(recipeToEdit, newIngredientList); } - public String parseAddRecipeTag(String command, RecipeList recipeList) { - String tag; - Recipe recipe; - String[] recipesToTag; - boolean isUnableToFindTheRecipe; - String[] args = command.trim().split("<<"); - boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); + return recipeToEdit; + } + + public String parseDeleteRecipe(String[] input, RecipeList recipeList) { + assert input[0].equals("delete"); + // user inputted recipe name + if (input[1].contains("r/")) { + // skip over /r in recipe name + String recipeToDelete = input[1].substring(2); + if (recipeToDelete.equals("all")) { + StringBuilder allRecipes = new StringBuilder(); + System.out.println("recipeList size: " + recipeList.size()); + int index = 0; + while (recipeList.size() != 0) { + allRecipes.append(recipeList.deleteRecipe(index).getName()).append(", "); + } + allRecipes = new StringBuilder(allRecipes.substring(0, allRecipes.length() - 2)); + return allRecipes.toString(); + } else { + int recipeIndex = 0; + for (Recipe recipe : recipeList) { + // find index of recipe we want to delete + if (recipe.getName().equals(recipeToDelete)) { + break; + } + recipeIndex++; + } + return recipeList.deleteRecipe(recipeIndex).getName(); + } + // user inputted index of recipe in list + } else { + // check if deleting a range of recipes + if (input[1].length() >= 3) { + StringBuilder rangeRecipes = new StringBuilder(); + int startIndex = Integer.parseInt(input[1].charAt(0) + ""); + int endIndex = Integer.parseInt(input[1].charAt(2) + ""); + startIndex -= 1; + endIndex -= 1; + int newSize = recipeList.size() - ((endIndex - startIndex) + 1); + while (recipeList.size() != newSize) { + rangeRecipes.append(recipeList.deleteRecipe(startIndex).getName()).append(", "); + } + rangeRecipes = new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2)); + return rangeRecipes.toString(); + } else { + int recipeIndex = Integer.parseInt(input[1]); + // need to subtract 1 since list is 1-based + return recipeList.deleteRecipe(recipeIndex - 1).getName(); + } + } + } - if (isNotEnoughArgs) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } + public String parseTagRecipe(String[] inputs, RecipeList recipeList) { + String tag; + boolean isOnlyTagWordInCommand = inputs.length == 1; + boolean isAddTag; + boolean isRemoveTag; - tag = args[0].trim(); - recipesToTag = args[1].split("&&"); - for (String recipeName : recipesToTag) { - recipeName = recipeName.trim(); - recipe = recipeList.findByName(recipeName); - isUnableToFindTheRecipe = recipe == null; - if (isUnableToFindTheRecipe) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + - "successfully added from the tag."; - throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); - } - recipeList.addRecipeToTag(tag, recipe); - } - return tag; + if (isOnlyTagWordInCommand) { + throw new IllegalArgumentException("Please indicate at least a tag and a recipe."); } - public String parseRemoveRecipeTag(String command, RecipeList recipeList) { - String tag; - Recipe recipe; - String[] recipesToRemove; - boolean isUnableToFindTag; - boolean isNoRecipeInTheList; - String[] args = command.trim().split(">>"); - boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); - - if (isNotEnoughArgs) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } + StringBuilder commandString = new StringBuilder(inputs[1]); + for (int i = 2; i < inputs.length; i++) { + commandString.append(" ").append(inputs[i]); + } - tag = args[0].trim(); - isUnableToFindTag = !recipeList.tags.containsKey(tag); - if (isUnableToFindTag) { - throw new IndexOutOfBoundsException("There is no \"" + tag + "\" tag found. Please make sure you have " + - "entered the correct tag."); - } + isAddTag = commandString.indexOf(">>") == -1 && commandString.indexOf("<<") != -1; + isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; + + if (!(isAddTag || isRemoveTag)) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } else if (isAddTag) { + tag = parseAddRecipeTag(commandString.toString(), recipeList); + } else if (isRemoveTag) { + tag = parseRemoveRecipeTag(commandString.toString(), recipeList); + } else { + throw new IllegalArgumentException("Invalid command."); + } + return tag; + } + + public String parseAddRecipeTag(String command, RecipeList recipeList) { + String tag; + Recipe recipe; + String[] recipesToTag; + boolean isUnableToFindTheRecipe; + String[] args = command.trim().split("<<"); + boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); + + if (isNotEnoughArgs) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } - recipesToRemove = args[1].split("&&"); - for (String recipeName : recipesToRemove) { - recipeName = recipeName.trim(); - recipe = recipeList.findByName(recipeName); - isNoRecipeInTheList = recipe == null; - if (isNoRecipeInTheList) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); - } - - try { - recipeList.removeRecipeFromTag(tag, recipe); - } catch (IndexOutOfBoundsException e) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName +"\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName +"\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); - } - } - return tag; + tag = args[0].trim(); + recipesToTag = args[1].split("&&"); + for (String recipeName : recipesToTag) { + recipeName = recipeName.trim(); + recipe = recipeList.findByName(recipeName); + isUnableToFindTheRecipe = recipe == null; + if (isUnableToFindTheRecipe) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully added from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } + recipeList.addRecipeToTag(tag, recipe); + } + return tag; + } + + public String parseRemoveRecipeTag(String command, RecipeList recipeList) { + String tag; + Recipe recipe; + String[] recipesToRemove; + boolean isUnableToFindTag; + boolean isNoRecipeInTheList; + String[] args = command.trim().split(">>"); + boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); + + if (isNotEnoughArgs) { + throw new IllegalArgumentException("Please enter the command in the correct format."); } - public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { - String[] filters; - RecipeList recipeListToPrint; - boolean hasTagArgs = inputs.length > 2; - boolean isOnlyListWordInCommand = inputs.length == 1; - boolean isTag = false; - int firstArgsIndex = 1; + tag = args[0].trim(); + isUnableToFindTag = !recipeList.tags.containsKey(tag); + if (isUnableToFindTag) { + throw new IndexOutOfBoundsException( + "There is no \"" + tag + "\" tag found. Please make sure you have " + + "entered the correct tag."); + } - if (isOnlyListWordInCommand) { - filters = null; - } else { - isTag = inputs[1].equals("/t"); - if (isTag && !hasTagArgs) { - throw new IllegalArgumentException("Please include at least a tag."); - } else if (isTag) { - firstArgsIndex = 2; - } - - StringBuilder filterString = new StringBuilder(inputs[firstArgsIndex]); - for (int i = firstArgsIndex + 1; i < inputs.length; i++) { - filterString.append(" ").append(inputs[i]); - } - - filters = filterString.toString().split("&&"); - } - recipeListToPrint = recipeList.listRecipes(filters, isTag); - return recipeListToPrint; + recipesToRemove = args[1].split("&&"); + for (String recipeName : recipesToRemove) { + recipeName = recipeName.trim(); + recipe = recipeList.findByName(recipeName); + isNoRecipeInTheList = recipe == null; + if (isNoRecipeInTheList) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } + + try { + recipeList.removeRecipeFromTag(tag, recipe); + } catch (IndexOutOfBoundsException e) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } + } + return tag; + } + + public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { + String[] filters; + RecipeList recipeListToPrint; + boolean hasTagArgs = inputs.length > 2; + boolean isOnlyListWordInCommand = inputs.length == 1; + boolean isTag = false; + int firstArgsIndex = 1; + + if (isOnlyListWordInCommand) { + filters = null; + } else { + isTag = inputs[1].equals("/t"); + if (isTag && !hasTagArgs) { + throw new IllegalArgumentException("Please include at least a tag."); + } else if (isTag) { + firstArgsIndex = 2; + } + + StringBuilder filterString = new StringBuilder(inputs[firstArgsIndex]); + for (int i = firstArgsIndex + 1; i < inputs.length; i++) { + filterString.append(" ").append(inputs[i]); + } + + filters = filterString.toString().split("&&"); + } + recipeListToPrint = recipeList.listRecipes(filters, isTag); + return recipeListToPrint; + } + + public Recipe parseViewRecipe(String[] command, RecipeList recipes) { + assert command[0].equals("view"); + Recipe requestedRecipe; + int recipeIndex = 0; + try { + recipeIndex = Integer.parseInt(command[1]); + requestedRecipe = recipes.get(recipeIndex - 1); + } catch (NumberFormatException error) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is not a number.", + command[1]); + throw new NumberFormatException(errorMessage); + } catch (ArrayIndexOutOfBoundsException error) { + String errorMessage = "Please enter a valid recipe number. You did not enter a recipe number."; + throw new ArrayIndexOutOfBoundsException(errorMessage); + } catch (IndexOutOfBoundsException error) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %d, " + "which is out of bounds.", + recipeIndex); + throw new IndexOutOfBoundsException(errorMessage); } + return requestedRecipe; + } + + public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { + int recipeIndex = 1; + for (Recipe recipe : recipes) { + if (recipe.getName().equals(recipeName)) { + break; + } + recipeIndex++; + } + return recipes.get(recipeIndex - 1); + } - public Recipe parseViewRecipe(String[] command, RecipeList recipes) { - assert command[0].equals("view"); - Recipe requestedRecipe; - int recipeIndex = 0; - try { - recipeIndex = Integer.parseInt(command[1]); - requestedRecipe = recipes.get(recipeIndex - 1); - } catch (NumberFormatException error) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is not a number.", - command[1]); - throw new NumberFormatException(errorMessage); - } catch (ArrayIndexOutOfBoundsException error) { - String errorMessage = "Please enter a valid recipe number. You did not enter a recipe number."; - throw new ArrayIndexOutOfBoundsException(errorMessage); - } catch (IndexOutOfBoundsException error) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %d, " + "which is out of bounds.", - recipeIndex); - throw new IndexOutOfBoundsException(errorMessage); - } - return requestedRecipe; + public Recipe parseRandomRecipe(RecipeList recipes) { + Recipe randomRecipe = recipes.randomRecipe(); + if (recipes.size() == 0) { + throw new NullPointerException("There is no recipe in the list to random"); } + return randomRecipe; + } + + public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException, InvalidNegativeValueException { + WeeklyPlan updatedWeeklyPlan; + try { + switch (command[1]) { + case "/add": + updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); + break; + case "/delete": + updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); + break; + case "/multidelete": + updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); + break; + default: + throw new IllegalArgumentException( + "Please indicate if you would want to add or delete the recipe from your weekly " + + "plan."); + } + + return updatedWeeklyPlan; + } catch (ArrayIndexOutOfBoundsException error) { + throw new ArrayIndexOutOfBoundsException("Insufficient number of arguments provided."); + } catch (NumberFormatException error) { + throw new NumberFormatException("Please enter a valid number as the last argument."); + } + } - public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { - int recipeIndex = 1; - for (Recipe recipe : recipes) { - if (recipe.getName().equals(recipeName)) { - break; - } - recipeIndex++; - } - return recipes.get(recipeIndex - 1); + private WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidNegativeValueException, InvalidRecipeNameException { + int numDays = Integer.parseInt(command[command.length - 1]); + if (numDays < 1) { + throw new InvalidNegativeValueException("Number of days needs to be at least 1."); } - public Recipe parseRandomRecipe(RecipeList recipes) { - Recipe randomRecipe = recipes.randomRecipe(); - if (recipes.size() == 0) { - throw new NullPointerException("There is no recipe in the list to random"); - } - return randomRecipe; - } - - public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException, InvalidNegativeValueException { - WeeklyPlan updatedWeeklyPlan; - try { - switch (command[1]) { - case "/add": - updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); - break; - case "/delete": - updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); - break; - case "/multiadd": - updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); - break; - case "/multidelete": - updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); - break; - default: - throw new IllegalArgumentException( - "Please indicate if you would want to add or delete the recipe from your weekly " - + "plan."); - } - - return updatedWeeklyPlan; - } catch (ArrayIndexOutOfBoundsException error) { - throw new ArrayIndexOutOfBoundsException("Insufficient number of arguments provided."); - } catch (NumberFormatException error) { - throw new NumberFormatException("Please enter a valid number as the last argument."); - } + int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; + WeeklyPlan thisWeekPlan = new WeeklyPlan(); + StringBuilder recipeName = new StringBuilder(command[2]); + for (int i = 3; i < nameLastIndex; i++) { + recipeName.append(" ").append(command[i]); } - private WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { - int numDays = Integer.parseInt(command[command.length - 1]); - if (numDays < 1) { - throw new InvalidNegativeValueException("Number of days needs to be at least 1."); - } + if (recipes.findByName(recipeName.toString().trim()) != null) { + thisWeekPlan.put(recipeName.toString(), numDays); + return thisWeekPlan; + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } + } + + private WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException { + int nameLastIndex = command.length; + WeeklyPlan thisWeekPlan = new WeeklyPlan(); + StringBuilder recipeName = new StringBuilder(command[2]); + for (int i = 3; i < nameLastIndex; i++) { + recipeName.append(" ").append(command[i].toLowerCase().trim()); + } - int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; - WeeklyPlan thisWeekPlan = new WeeklyPlan(); - StringBuilder recipeName = new StringBuilder(command[2]); - for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i]); - } + if (recipes.findByName(recipeName.toString().trim()) != null) { + thisWeekPlan.put(recipeName.toString(), 0); + return thisWeekPlan; + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } + } + + private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidNegativeValueException, InvalidRecipeNameException { + WeeklyPlan recipesToAdd = new WeeklyPlan(); + ArrayList quantities = new ArrayList<>(); + ArrayList recipeNames = new ArrayList<>(); + ArrayList startIndices = new ArrayList<>(); + ArrayList endIndices = new ArrayList<>(); + StringBuilder recipeName = new StringBuilder(); + + for (int i = 0; i < command.length; i++) { + if (command[i].equals("/r")) { + startIndices.add(i); + } else if (command[i].equals("/q")) { + endIndices.add(i); + int quantity = Integer.parseInt(command[i + 1]); + if (quantity < 1) { + throw new InvalidNegativeValueException( + "Please enter a positive number for the quantity."); + } + quantities.add(quantity); + } + } - if (recipes.findByName(recipeName.toString().trim()) != null) { - thisWeekPlan.put(recipeName.toString(), numDays); - return thisWeekPlan; - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } + // Checks that command is entered in the correct + if (startIndices.size() != endIndices.size()) { + throw new IllegalArgumentException( + "Please ensure the number of recipes and quantities match."); } - private WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - int nameLastIndex = command.length; - WeeklyPlan thisWeekPlan = new WeeklyPlan(); - StringBuilder recipeName = new StringBuilder(command[2]); - for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i].toLowerCase().trim()); - } + // Building the recipe names + for (int i = 0; i < startIndices.size(); i++) { + int nameStartIndex = startIndices.get(i) + 1; + int nameEndIndex = endIndices.get(i) - 1; + recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); + } - if (recipes.findByName(recipeName.toString().trim()) != null) { - thisWeekPlan.put(recipeName.toString(), 0); - return thisWeekPlan; + // Add each recipe to the weekly plan + try { + for (int i = 0; i < recipeNames.size(); i++) { + if (recipes.findByName(recipeNames.get(i)) != null) { + recipesToAdd.put(recipeNames.get(i), quantities.get(i)); } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); } + } + } catch (NumberFormatException error) { + throw new NumberFormatException("Please enter a positive number for the quantity."); } - private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { - WeeklyPlan recipesToAdd = new WeeklyPlan(); - ArrayList quantities = new ArrayList<>(); - ArrayList recipeNames = new ArrayList<>(); - ArrayList startIndices = new ArrayList<>(); - ArrayList endIndices = new ArrayList<>(); - StringBuilder recipeName = new StringBuilder(); - - for (int i = 0; i < command.length; i++) { - if (command[i].equals("/r")) { - startIndices.add(i); - } else if (command[i].equals("/q")) { - endIndices.add(i); - int quantity = Integer.parseInt(command[i + 1]); - if (quantity < 1) { - throw new InvalidNegativeValueException( - "Please enter a positive number for the quantity."); - } - quantities.add(quantity); - } - } + return recipesToAdd; + } - // Checks that command is entered in the correct - if (startIndices.size() != endIndices.size()) { - throw new IllegalArgumentException("Please ensure the number of recipes and quantities match."); - } + private WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException { + WeeklyPlan recipesToDelete = new WeeklyPlan(); + ArrayList recipeNames = new ArrayList<>(); + ArrayList startIndices = new ArrayList<>(); + StringBuilder recipeName = new StringBuilder(); - // Building the recipe names - for (int i = 0; i < startIndices.size(); i++) { - int nameStartIndex = startIndices.get(i) + 1; - int nameEndIndex = endIndices.get(i) - 1; - recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); - } - - // Add each recipe to the weekly plan - try { - for (int i = 0; i < recipeNames.size(); i++) { - if (recipes.findByName(recipeNames.get(i)) != null) { - recipesToAdd.put(recipeNames.get(i), quantities.get(i)); - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } - } catch (NumberFormatException error) { - throw new NumberFormatException("Please enter a positive number for the quantity."); - } - - return recipesToAdd; + for (int i = 0; i < command.length; i++) { + if (command[i].equals("/r")) { + startIndices.add(i); + } } - private WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - WeeklyPlan recipesToDelete = new WeeklyPlan(); - ArrayList recipeNames = new ArrayList<>(); - ArrayList startIndices = new ArrayList<>(); - StringBuilder recipeName = new StringBuilder(); + if (startIndices.size() == 0) { + throw new IllegalArgumentException("Please use /r to indicate the recipe to be deleted."); + } - for (int i = 0; i < command.length; i++) { - if (command[i].equals("/r")) { - startIndices.add(i); - } - } + // Building the recipe names + for (int i = 0; i < startIndices.size(); i++) { + int nameStartIndex = startIndices.get(i) + 1; + int nameEndIndex = + (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; - if (startIndices.size() == 0) { - throw new IllegalArgumentException("Please use /r to indicate the recipe to be deleted."); - } - - // Building the recipe names - for (int i = 0; i < startIndices.size(); i++) { - int nameStartIndex = startIndices.get(i) + 1; - int nameEndIndex = - (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; + recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); + } - recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); - } + // Add each recipe to the weekly plan + for (String name : recipeNames) { + if (recipes.findByName(name) != null) { + recipesToDelete.put(name, 0); + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } + } - // Add each recipe to the weekly plan - for (String name : recipeNames) { - if (recipes.findByName(name) != null) { - recipesToDelete.put(name, 0); - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } + return recipesToDelete; + } - return recipesToDelete; + private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, + StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { + recipeName.append(command[nameStartIndex].toLowerCase().trim()); + for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { + recipeName.append(" ").append(command[j].toLowerCase().trim()); } - - private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, - StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { - recipeName.append(command[nameStartIndex].toLowerCase().trim()); - for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { - recipeName.append(" ").append(command[j].toLowerCase().trim()); - } - recipeNames.add(recipeName.toString()); - recipeName = new StringBuilder(); - return recipeName; - } - - // parser to read dd/mm/yyyy format as local date catching invalid date format - public LocalDate parseDate(String input) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); - try { - return LocalDate.parse(input, formatter); - } catch (DateTimeParseException e) { - throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy"); - } + recipeNames.add(recipeName.toString()); + recipeName = new StringBuilder(); + return recipeName; + } + + // parser to read dd/mm/yyyy format as local date catching invalid date format + public LocalDate parseDate(String input) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + try { + return LocalDate.parse(input, formatter); + } catch (DateTimeParseException e) { + throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy"); } + } } diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 8fd5a46c0d..389755f55a 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -4,41 +4,41 @@ public class Recipe { - // changed ingredients to public to edit via editRecipe - private static IngredientList ingredientList = new IngredientList(); - public HashMap ingredients; - private String name; - private Boolean available; - - - public Recipe(String name, HashMap ingredients) { - this.name = name; - this.ingredients = ingredients; - } - - public String getName() { - return name; - } - - public HashMap getIngredients() { - return ingredients; - } - - public int getNumOfIngredients() { - return ingredients.size(); - } - - public boolean isAvailable() { - for (String ingredientName : ingredients.keySet()) { - if (ingredientList.containsKey(ingredientName)) { - Ingredient ingredient = ingredientList.get(ingredientName); - if (ingredient.ingredientCount < ingredients.get(ingredientName)) { - return false; - } - } else { - return false; - } + // changed ingredients to public to edit via editRecipe + private static IngredientList ingredientList = new IngredientList(); + public HashMap ingredients; + private String name; + private Boolean available; + + + public Recipe(String name, HashMap ingredients) { + this.name = name; + this.ingredients = ingredients; + } + + public String getName() { + return name; + } + + public HashMap getIngredients() { + return ingredients; + } + + public int getNumOfIngredients() { + return ingredients.size(); + } + + public boolean isAvailable() { + for (String ingredientName : ingredients.keySet()) { + if (ingredientList.containsKey(ingredientName)) { + Ingredient ingredient = ingredientList.get(ingredientName); + if (ingredient.ingredientCount < ingredients.get(ingredientName)) { + return false; } - return true; + } else { + return false; + } } + return true; + } } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 08f0cb5495..2fa7cee1cb 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -5,135 +5,138 @@ import java.util.Random; public class RecipeList extends ArrayList { - private static IngredientList ingredientList = new IngredientList(); - public HashMap> tags = new HashMap<>(); - - public Recipe findByName(String name) { - for (Recipe recipe : this) { - if (recipe.getName().equalsIgnoreCase(name)) { - return recipe; - } - } - return null; - } - public void addRecipe(Recipe recipe) { - super.add(recipe); - } + private static IngredientList ingredientList = new IngredientList(); + public HashMap> tags = new HashMap<>(); - public void editRecipe(Recipe recipe, HashMap ingredients) { - recipe.ingredients = ingredients; + public Recipe findByName(String name) { + for (Recipe recipe : this) { + if (recipe.getName().equalsIgnoreCase(name)) { + return recipe; + } } - - public Recipe deleteRecipe(int recipeNum) { - Recipe recipeToDelete = super.get(recipeNum); - super.remove(recipeToDelete); - return recipeToDelete; + return null; + } + + public void addRecipe(Recipe recipe) { + super.add(recipe); + } + + public void editRecipe(Recipe recipe, HashMap ingredients) { + recipe.ingredients = ingredients; + } + + public Recipe deleteRecipe(int recipeNum) { + Recipe recipeToDelete = super.get(recipeNum); + super.remove(recipeToDelete); + return recipeToDelete; + } + + public void addRecipeToTag(String tag, Recipe recipe) { + boolean hasTag = tags.containsKey(tag); + int tagDummy = 0; + if (hasTag) { + tags.get(tag).put(recipe, tagDummy); + } else { + assert !tags.containsKey(tag); + HashMap tagRecipes = new HashMap<>(); + tagRecipes.put(recipe, tagDummy); + tags.put(tag, tagRecipes); + assert tags.size() > 0 : "tag's size is still 0."; } - - public void addRecipeToTag(String tag, Recipe recipe) { - boolean hasTag = tags.containsKey(tag); - int tagDummy = 0; - if (hasTag) { - tags.get(tag).put(recipe, tagDummy); - } else { - assert !tags.containsKey(tag); - HashMap tagRecipes = new HashMap<>(); - tagRecipes.put(recipe, tagDummy); - tags.put(tag, tagRecipes); - assert tags.size() > 0 : "tag's size is still 0."; - } + } + + public void removeRecipeFromTag(String tag, Recipe recipe) { + HashMap tagRecipeList = tags.get(tag); + boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); + if (!isAbleToFindTheRecipe) { + String errorMessage1 = "Unable to find the recipe: \"" + recipe.getName() + "\" in the" + + " tag."; + String errorMessage2 = "All the recipe before \"" + recipe.getName() + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } + tagRecipeList.remove(recipe); + } - public void removeRecipeFromTag(String tag, Recipe recipe) { - HashMap tagRecipeList = tags.get(tag); - boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); - if (!isAbleToFindTheRecipe) { - String errorMessage1 = "Unable to find the recipe: \"" + recipe.getName() + "\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipe.getName() + "\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); - } - tagRecipeList.remove(recipe); - } - - public RecipeList listRecipes(String[] filters, boolean isTag) { - RecipeList filteredRecipeList = new RecipeList(); - boolean isNoFilter = filters == null; - boolean isNotPassTheFilter; + public RecipeList listRecipes(String[] filters, boolean isTag) { + RecipeList filteredRecipeList = new RecipeList(); + boolean isNoFilter = filters == null; + boolean isNotPassTheFilter; - if (isTag) { - filteredRecipeList = this.listTagRecipes(filters); - } - if (!isTag && isNoFilter) { - return this; - } - if (!isTag) { - for (Recipe recipe : this) { - filteredRecipeList.add(recipe); - for (String filter : filters) { - filter = filter.trim(); - isNotPassTheFilter = !recipe.getName().contains(filter) && - !recipe.getIngredients().containsKey(filter); - if (isNotPassTheFilter) { - filteredRecipeList.remove(recipe); - } - } - } - } - return filteredRecipeList; + if (isTag) { + filteredRecipeList = this.listTagRecipes(filters); } - - public RecipeList listTagRecipes(String[] filters) { - RecipeList filteredRecipeList = new RecipeList(); - HashMap tagRecipes; - boolean hasNoRecipeInTheTag; - boolean hasNoRecipeToReturn; - boolean isNotFoundTag; - - // add all recipe from first tag to the list - isNotFoundTag = !this.tags.containsKey(filters[0].trim()); - if (isNotFoundTag) { - throw new NullPointerException("There is no \"" + filters[0] + "\" tag found. Please make sure you have " + - "entered the correct tag."); - } - this.tags.get(filters[0].trim()).forEach((recipe, dummy) -> filteredRecipeList.add(recipe)); - + if (!isTag && isNoFilter) { + return this; + } + if (!isTag) { + for (Recipe recipe : this) { + filteredRecipeList.add(recipe); for (String filter : filters) { - filter = filter.trim(); - tagRecipes = this.tags.get(filter); - hasNoRecipeInTheTag = tagRecipes == null; - hasNoRecipeToReturn = filteredRecipeList.size() == 0; - - if (hasNoRecipeInTheTag) { - throw new NullPointerException("There is nothing to list."); - } - if (hasNoRecipeToReturn) { - return filteredRecipeList; - } - for (Recipe recipe : filteredRecipeList) { - if (!tagRecipes.containsKey(recipe)) { - filteredRecipeList.remove(recipe); - } - } + filter = filter.trim(); + isNotPassTheFilter = !recipe.getName().contains(filter) && + !recipe.getIngredients().containsKey(filter); + if (isNotPassTheFilter) { + filteredRecipeList.remove(recipe); + } } - return filteredRecipeList; + } } - - public RecipeList availableRecipes() { - RecipeList availableRecipeList = new RecipeList(); - for (Recipe recipe : this) { - if (recipe.isAvailable()) { - availableRecipeList.add(recipe); - } + return filteredRecipeList; + } + + public RecipeList listTagRecipes(String[] filters) { + RecipeList filteredRecipeList = new RecipeList(); + HashMap tagRecipes; + boolean hasNoRecipeInTheTag; + boolean hasNoRecipeToReturn; + boolean isNotFoundTag; + + // add all recipe from first tag to the list + isNotFoundTag = !this.tags.containsKey(filters[0].trim()); + if (isNotFoundTag) { + throw new NullPointerException( + "There is no \"" + filters[0] + "\" tag found. Please make sure you have " + + "entered the correct tag."); + } + this.tags.get(filters[0].trim()).forEach((recipe, dummy) -> filteredRecipeList.add(recipe)); + + for (String filter : filters) { + filter = filter.trim(); + tagRecipes = this.tags.get(filter); + hasNoRecipeInTheTag = tagRecipes == null; + hasNoRecipeToReturn = filteredRecipeList.size() == 0; + + if (hasNoRecipeInTheTag) { + throw new NullPointerException("There is nothing to list."); + } + if (hasNoRecipeToReturn) { + return filteredRecipeList; + } + for (Recipe recipe : filteredRecipeList) { + if (!tagRecipes.containsKey(recipe)) { + filteredRecipeList.remove(recipe); } - return availableRecipeList; + } } - - public Recipe randomRecipe() { - Random random = new Random(); - Recipe randomRecipe = this.get(random.nextInt(this.size())); - return randomRecipe; + return filteredRecipeList; + } + + public RecipeList availableRecipes() { + RecipeList availableRecipeList = new RecipeList(); + for (Recipe recipe : this) { + if (recipe.isAvailable()) { + availableRecipeList.add(recipe); + } } + return availableRecipeList; + } + + public Recipe randomRecipe() { + Random random = new Random(); + Recipe randomRecipe = this.get(random.nextInt(this.size())); + return randomRecipe; + } } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 1b623f2bdb..f230589f1e 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -2,104 +2,107 @@ public class Ui { - private static final int BOXWIDTH = 100; - private static final String SEPARATORCHAR = "-"; - - public void printSeparator() { - String separatorLine = SEPARATORCHAR.repeat(BOXWIDTH); - System.out.println(separatorLine); - } - - public void printWelcomeMessage() { - String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" - + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; - System.out.println("Welcome to Meal360, your ultimate Recipe Manager!\n" + logo); - } - - public void printGoodbyeMessage() { - System.out.println(formatMessage("Bye. Hope to see you again soon!")); + private static final int BOXWIDTH = 100; + private static final String SEPARATORCHAR = "-"; + + public void printSeparator() { + String separatorLine = SEPARATORCHAR.repeat(BOXWIDTH); + System.out.println(separatorLine); + } + + public void printWelcomeMessage() { + String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + System.out.println("Welcome to Meal360, your ultimate Recipe Manager!\n" + logo); + } + + public void printGoodbyeMessage() { + System.out.println(formatMessage("Bye. Hope to see you again soon!")); + } + + public String formatMessage(String message) { + return String.format("| %-97s|", message); + } + + public void printMessage(String message) { + String outputMessage = formatMessage(message); + System.out.println(outputMessage); + } + + public void printRecipe(Recipe recipe) { + System.out.println(formatMessage("Name of recipe: " + recipe.getName())); + int index = 1; + for (String ingredient : recipe.getIngredients().keySet()) { + String outputMessage = String.format("%s(%d)", ingredient, + recipe.getIngredients().get(ingredient)); + System.out.println(formatMessage(index + ". " + outputMessage)); + index++; } - - public String formatMessage(String message) { - return String.format("| %-97s|", message); - } - - public void printMessage(String message) { - String outputMessage = formatMessage(message); - System.out.println(outputMessage); - } - - public void printRecipe(Recipe recipe) { - System.out.println(formatMessage("Name of recipe: " + recipe.getName())); - int index = 1; - for (String ingredient : recipe.getIngredients().keySet()) { - String outputMessage = String.format("%s(%d)", ingredient, - recipe.getIngredients().get(ingredient)); - System.out.println(formatMessage(index + ". " + outputMessage)); - index++; - } + } + + public void printWeeklyPlan(WeeklyPlan weeklyPlan) { + if (weeklyPlan.isEmpty()) { + printMessage("Your weekly plan is empty!"); + } else { + printMessage("Here is your weekly plan:"); + weeklyPlan.forEach((recipe, count) -> { + String outputMessage = String.format("%s x%d", recipe, count); + printMessage(outputMessage); + }); } - public void printWeeklyPlan(WeeklyPlan weeklyPlan) { - if (weeklyPlan.isEmpty()) { - printMessage("Your weekly plan is empty!"); - } else { - printMessage("Here is your weekly plan:"); - weeklyPlan.forEach((recipe, count) -> { - String outputMessage = String.format("%s x%d", recipe, count); - printMessage(outputMessage); - }); + } + + public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) { + if (weeklyPlan.isEmpty()) { + printMessage("Your weekly plan is empty!"); + } else { + printMessage("Here are your weekly ingredients:"); + weeklyPlan.forEach((recipe, count) -> { + Recipe currRecipe = recipeList.findByName(recipe.toString().trim()); + for (String ingredient : currRecipe.getIngredients().keySet()) { + String outputMessage = String.format("%s (%d)", ingredient, + currRecipe.getIngredients().get(ingredient) * count); + System.out.println(formatMessage(outputMessage)); } - + }); } - public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) { - if (weeklyPlan.isEmpty()) { - printMessage("Your weekly plan is empty!"); - } else { - printMessage("Here are your weekly ingredients:"); - weeklyPlan.forEach((recipe, count) -> { - Recipe currRecipe = recipeList.findByName(recipe.toString().trim()); - for (String ingredient : currRecipe.getIngredients().keySet()) { - String outputMessage = String.format("%s (%d)", ingredient, - currRecipe.getIngredients().get(ingredient) * count); - System.out.println(formatMessage(outputMessage)); - } - }); - } - - } + } - public void listRecipe(RecipeList recipeListToPrint) { - listRecipes(recipeListToPrint, "There is nothing to list.", "These are the recipes you have"); - } + public void listRecipe(RecipeList recipeListToPrint) { + listRecipes(recipeListToPrint, "There is nothing to list.", "These are the recipes you have"); + } - public void listAvailableRecipes(RecipeList recipeListToPrint) { - listRecipes(recipeListToPrint, "There are no available recipes.", "These are the recipes you can cook"); - } + public void listAvailableRecipes(RecipeList recipeListToPrint) { + listRecipes(recipeListToPrint, "There are no available recipes.", + "These are the recipes you can cook"); + } - private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, String listHeaderMsg) { - int numberOfRecipes = recipeListToPrint.size(); - int order = 0; - if (numberOfRecipes == 0) { - printMessage(emptyListMsg); - return; - } - printMessage(listHeaderMsg + " (" + numberOfRecipes + " recipes):"); - for (Recipe recipe : recipeListToPrint) { - order++; - printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + " ingredients)"); - } + private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, + String listHeaderMsg) { + int numberOfRecipes = recipeListToPrint.size(); + int order = 0; + if (numberOfRecipes == 0) { + printMessage(emptyListMsg); + return; } - - public void printHelp() { - printMessage("These are the operations you can do. Please follow the proper input" - + " formats while typing."); - printMessage("1. Add Recipe: add /r {recipe name}"); - printMessage("2. View Recipe: view {index number} or view /r {recipe name}"); - printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); - printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); - printMessage("5. List All Recipes: list"); - printMessage("6. Exit: bye"); + printMessage(listHeaderMsg + " (" + numberOfRecipes + " recipes):"); + for (Recipe recipe : recipeListToPrint) { + order++; + printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + + " ingredients)"); } + } + + public void printHelp() { + printMessage("These are the operations you can do. Please follow the proper input" + + " formats while typing."); + printMessage("1. Add Recipe: add /r {recipe name}"); + printMessage("2. View Recipe: view {index number} or view /r {recipe name}"); + printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); + printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); + printMessage("5. List All Recipes: list"); + printMessage("6. Exit: bye"); + } } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index 41e781a1b9..cb773aa97a 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -4,28 +4,28 @@ public class WeeklyPlan extends HashMap { - public void addPlans(WeeklyPlan recipeMap) { - recipeMap.forEach((recipe, count) -> { - if (this.containsKey(recipe)) { - this.put(recipe, this.get(recipe) + count); - } else { - this.put(recipe, count); - } - }); - } + public void addPlans(WeeklyPlan recipeMap) { + recipeMap.forEach((recipe, count) -> { + if (this.containsKey(recipe)) { + this.put(recipe, this.get(recipe) + count); + } else { + this.put(recipe, count); + } + }); + } - public void deletePlans(WeeklyPlan recipeMap) { - recipeMap.forEach((recipe, count) -> { - if (this.containsKey(recipe)) { - this.remove(recipe); - } else { - throw new IllegalArgumentException("Recipe does not exist in weekly plan!"); - } - }); - } + public void deletePlans(WeeklyPlan recipeMap) { + recipeMap.forEach((recipe, count) -> { + if (this.containsKey(recipe)) { + this.remove(recipe); + } else { + throw new IllegalArgumentException("Recipe does not exist in weekly plan!"); + } + }); + } - public void clearPlan() { - this.clear(); - } + public void clearPlan() { + this.clear(); + } } From 9e09df10dd645f892068b956a2e1f8cde97f5f9c Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 30 Mar 2023 23:27:02 +0800 Subject: [PATCH 140/252] add to help command --- src/main/java/seedu/meal360/Ui.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 26fd26488a..cb608a3179 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -93,16 +93,21 @@ public void printHelp() { printMessage("1. Add Recipe: add /r {recipe name}"); printMessage("2. View Recipe: view {index number} or view /r {recipe name}"); printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); - printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); + printMessage("4. Delete Recipe(s): delete {index number}, delete {range}, " + "delete r/ {recipe name}"); + printMessage(" delete r/ {all} or view /r {recipe name}"); printMessage("5. List All Recipes: list"); printMessage("6. Add Single Recipe to Weekly Plan: add {recipe name} {quantity}"); printMessage("7. Add Multiple Recipes to Weekly Plan: add /r {recipe name} /q {quantity}"); printMessage(" /r {recipe name} /q {quantity} ..."); - printMessage("8. Delete Single Recipe from Weekly Plan: delete {recipe name} {quantity}"); - printMessage("9. Delete Multiple Recipes from Weekly Plan: delete /r {recipe name} /q"); + printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name}"); + printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe name} /q"); printMessage(" {quantity} /r {recipe name} /q {quantity} ..."); - printMessage("10. View Weekly Plan: weeklyplan"); - printMessage("11. Exit: bye"); + printMessage("10. Clear Weekly Plan: weekly /clear"); + printMessage("11. Tag recipes to categorize: tag label << [recipe name && recipe name && ...]"); + printMessage("12. Randomly receive a recipe: random"); + printMessage("13. View Weekly Plan: weeklyplan"); + printMessage("14. View Weekly Ingredients: weeklyingredients"); + printMessage("15. Exit: bye"); } public void printUserIngredients(IngredientList userIngredients) { From 392e82dc719155b2b798c56a85fed033720808bc Mon Sep 17 00:00:00 2001 From: notbingsu Date: Thu, 30 Mar 2023 23:49:25 +0800 Subject: [PATCH 141/252] no message --- src/main/java/seedu/meal360/Database.java | 363 +++--- src/main/java/seedu/meal360/Exceptions.java | 10 +- src/main/java/seedu/meal360/Ingredient.java | 42 +- .../java/seedu/meal360/IngredientList.java | 169 ++- src/main/java/seedu/meal360/Meal360.java | 410 +++---- src/main/java/seedu/meal360/Parser.java | 1064 +++++++++-------- src/main/java/seedu/meal360/Recipe.java | 70 +- src/main/java/seedu/meal360/RecipeList.java | 242 ++-- src/main/java/seedu/meal360/Ui.java | 185 +-- src/main/java/seedu/meal360/WeeklyPlan.java | 42 +- 10 files changed, 1308 insertions(+), 1289 deletions(-) diff --git a/src/main/java/seedu/meal360/Database.java b/src/main/java/seedu/meal360/Database.java index 40c7205f23..c56dd758e2 100644 --- a/src/main/java/seedu/meal360/Database.java +++ b/src/main/java/seedu/meal360/Database.java @@ -1,6 +1,7 @@ package seedu.meal360; import com.google.gson.Gson; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -11,193 +12,193 @@ public class Database { - private static final String recipesDatabaseFilepath = - "." + System.getProperty("file.separator") + "src" + System.getProperty("file.separator") - + "main" - + System.getProperty("file.separator") + "resources" + System.getProperty( - "file.separator") + "recipesDatabase.json"; - - public RecipeList loadDatabase() throws IOException { - RecipeList database; - Gson gson = new Gson(); - - // Check if the JSON file exists and create one if it does not - File file = new File(recipesDatabaseFilepath); - if (!file.exists()) { - try { - // Create the parent directory if it does not exist - File parentDir = file.getParentFile(); - if (!parentDir.exists()) { - parentDir.mkdirs(); + private static final String recipesDatabaseFilepath = + "." + System.getProperty("file.separator") + "src" + System.getProperty("file.separator") + + "main" + + System.getProperty("file.separator") + "resources" + System.getProperty( + "file.separator") + "recipesDatabase.json"; + + public RecipeList loadDatabase() throws IOException { + RecipeList database; + Gson gson = new Gson(); + + // Check if the JSON file exists and create one if it does not + File file = new File(recipesDatabaseFilepath); + if (!file.exists()) { + try { + // Create the parent directory if it does not exist + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + file.createNewFile(); + } catch (IOException e) { + throw new IOException("Error creating database file."); + } + + // Return a default recipe list if database file does not exist + return defaultRecipeList(); + } + + // Read the JSON data from the file if it already exists + try { + // Read the JSON data from the file + BufferedReader reader = new BufferedReader(new FileReader(recipesDatabaseFilepath)); + database = gson.fromJson(reader, RecipeList.class); + reader.close(); + } catch (FileNotFoundException e) { + throw new FileNotFoundException("Unable to find database file."); + } catch (IOException e) { + throw new IOException("Error reading from database file."); } - file.createNewFile(); - } catch (IOException e) { - throw new IOException("Error creating database file."); - } - // Return a default recipe list if database file does not exist - return defaultRecipeList(); + // Ensure non empty recipeList is returned + if (database == null) { + return defaultRecipeList(); + } else { + return database; + } } - // Read the JSON data from the file if it already exists - try { - // Read the JSON data from the file - BufferedReader reader = new BufferedReader(new FileReader(recipesDatabaseFilepath)); - database = gson.fromJson(reader, RecipeList.class); - reader.close(); - } catch (FileNotFoundException e) { - throw new FileNotFoundException("Unable to find database file."); - } catch (IOException e) { - throw new IOException("Error reading from database file."); + public void saveDatabase(RecipeList recipeList) throws IOException { + Gson gson = new Gson(); + // Write the data object to the JSON file + FileWriter writer; + writer = new FileWriter(recipesDatabaseFilepath); + gson.toJson(recipeList, writer); + writer.close(); } - // Ensure non empty recipeList is returned - if (database == null) { - return defaultRecipeList(); - } else { - return database; + public RecipeList defaultRecipeList() { + RecipeList defaultRecipeList = new RecipeList(); + defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap<>() { + { + put("Chicken", 1); + put("Rice", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap<>() { + { + put("Ripe mixed-colour cherry tomatoes ", 250); + put("Flat-leaf parsley", 15); + put("Garlic cloves", 2); + put("Plain flour", 2); + put("Eggs", 2); + put("Breadcrumbs", 100); + put("Vegetable oil", 2); + put("Feta cheese", 30); + } + })); + + defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap<>() { + { + put("Chicken breast fillets", 2); + put("Mushrooms", 250); + put("Onion", 1); + put("Plain flour", 2); + put("Butter", 2); + put("Milk", 2); + put("Puff pastry", 1); + } + })); + + defaultRecipeList.add(new Recipe("Seafood paella", new HashMap<>() { + { + put("Prawns", 500); + put("Mussels", 500); + put("Chorizo", 100); + put("Onion", 1); + put("Garlic cloves", 2); + put("Rice", 1); + put("Cherry tomatoes", 250); + put("Vegetable oil", 2); + put("Chicken stock", 1); + put("Saffron", 1); + } + })); + + defaultRecipeList.add(new Recipe("Avocado toast", new HashMap<>() { + { + put("Avocado", 1); + put("Bread", 2); + put("Lemon", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap<>() { + { + put("Italian sausage", 1); + put("Onion", 1); + put("Garlic cloves", 2); + put("Carrot", 1); + put("Celery", 1); + put("Dried oregano", 1); + put("Dried basil", 1); + put("Dried thyme", 1); + put("Dried parsley", 1); + put("Dried rosemary", 1); + put("Chicken stock", 1); + put("Orzo", 1); + put("Parmesan cheese", 1); + } + })); + + defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap<>() { + { + put("Chicken breast fillets", 2); + put("Mushrooms", 250); + put("Onion", 1); + put("Garlic cloves", 2); + put("Plain flour", 2); + put("Butter", 2); + put("Milk", 2); + put("Pasta", 1); + } + })); + + defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap<>() { + { + put("Pasta", 1); + put("Hummus", 1); + put("Garlic cloves", 2); + put("Lemon", 1); + put("Salt", 1); + put("Pepper", 1); + } + })); + + defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap<>() { + { + put("Ground beef", 1); + put("Potato", 1); + put("Onion", 1); + put("Garlic cloves", 2); + put("Tomato paste", 1); + put("Tomato sauce", 1); + put("Beef stock", 1); + put("Cheddar cheese", 1); + } + })); + + defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap<>() { + { + put("Chicken breast fillets", 2); + put("Macaroni", 1); + put("Butter", 2); + put("Flour", 2); + put("Milk", 2); + put("Cheddar cheese", 1); + put("Blue cheese", 1); + put("Hot sauce", 1); + } + })); + + return defaultRecipeList; } - } - - public void saveDatabase(RecipeList recipeList) throws IOException { - Gson gson = new Gson(); - // Write the data object to the JSON file - FileWriter writer; - writer = new FileWriter(recipesDatabaseFilepath); - gson.toJson(recipeList, writer); - writer.close(); - } - - public RecipeList defaultRecipeList() { - RecipeList defaultRecipeList = new RecipeList(); - defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap<>() { - { - put("Chicken", 1); - put("Rice", 1); - put("Salt", 1); - put("Pepper", 1); - } - })); - - defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap<>() { - { - put("Ripe mixed-colour cherry tomatoes ", 250); - put("Flat-leaf parsley", 15); - put("Garlic cloves", 2); - put("Plain flour", 2); - put("Eggs", 2); - put("Breadcrumbs", 100); - put("Vegetable oil", 2); - put("Feta cheese", 30); - } - })); - - defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap<>() { - { - put("Chicken breast fillets", 2); - put("Mushrooms", 250); - put("Onion", 1); - put("Plain flour", 2); - put("Butter", 2); - put("Milk", 2); - put("Puff pastry", 1); - } - })); - - defaultRecipeList.add(new Recipe("Seafood paella", new HashMap<>() { - { - put("Prawns", 500); - put("Mussels", 500); - put("Chorizo", 100); - put("Onion", 1); - put("Garlic cloves", 2); - put("Rice", 1); - put("Cherry tomatoes", 250); - put("Vegetable oil", 2); - put("Chicken stock", 1); - put("Saffron", 1); - } - })); - - defaultRecipeList.add(new Recipe("Avocado toast", new HashMap<>() { - { - put("Avocado", 1); - put("Bread", 2); - put("Lemon", 1); - put("Salt", 1); - put("Pepper", 1); - } - })); - - defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap<>() { - { - put("Italian sausage", 1); - put("Onion", 1); - put("Garlic cloves", 2); - put("Carrot", 1); - put("Celery", 1); - put("Dried oregano", 1); - put("Dried basil", 1); - put("Dried thyme", 1); - put("Dried parsley", 1); - put("Dried rosemary", 1); - put("Chicken stock", 1); - put("Orzo", 1); - put("Parmesan cheese", 1); - } - })); - - defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap<>() { - { - put("Chicken breast fillets", 2); - put("Mushrooms", 250); - put("Onion", 1); - put("Garlic cloves", 2); - put("Plain flour", 2); - put("Butter", 2); - put("Milk", 2); - put("Pasta", 1); - } - })); - - defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap<>() { - { - put("Pasta", 1); - put("Hummus", 1); - put("Garlic cloves", 2); - put("Lemon", 1); - put("Salt", 1); - put("Pepper", 1); - } - })); - - defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap<>() { - { - put("Ground beef", 1); - put("Potato", 1); - put("Onion", 1); - put("Garlic cloves", 2); - put("Tomato paste", 1); - put("Tomato sauce", 1); - put("Beef stock", 1); - put("Cheddar cheese", 1); - } - })); - - defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap<>() { - { - put("Chicken breast fillets", 2); - put("Macaroni", 1); - put("Butter", 2); - put("Flour", 2); - put("Milk", 2); - put("Cheddar cheese", 1); - put("Blue cheese", 1); - put("Hot sauce", 1); - } - })); - - return defaultRecipeList; - } } diff --git a/src/main/java/seedu/meal360/Exceptions.java b/src/main/java/seedu/meal360/Exceptions.java index d64ecf571e..7d555a9c90 100644 --- a/src/main/java/seedu/meal360/Exceptions.java +++ b/src/main/java/seedu/meal360/Exceptions.java @@ -2,12 +2,12 @@ public class Exceptions { - // ingredient not found exception - public static class IngredientNotFoundException extends Exception { + // ingredient not found exception + public static class IngredientNotFoundException extends Exception { - public IngredientNotFoundException() { - super("Ingredient not found"); + public IngredientNotFoundException() { + super("Ingredient not found"); + } } - } } diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java index aa7c1026ba..643cf82084 100644 --- a/src/main/java/seedu/meal360/Ingredient.java +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -4,28 +4,28 @@ public class Ingredient { - private static final Parser parser = new Parser(); - public String ingredientName; - public Integer ingredientCount; - public LocalDate expiryDate; - public Boolean expired; - private String unit; + private static final Parser parser = new Parser(); + public String ingredientName; + public Integer ingredientCount; + public LocalDate expiryDate; + public Boolean expired; + private String unit; - public Ingredient(String ingredientName, Integer ingredientCount, String unit, - String expiryDate) { - this.ingredientName = ingredientName; - this.ingredientCount = ingredientCount; - this.unit = unit; - // parse expiry date using parseDate method - this.expiryDate = parser.parseDate(expiryDate); - this.updateExpired(); - } + public Ingredient(String ingredientName, Integer ingredientCount, String unit, + String expiryDate) { + this.ingredientName = ingredientName; + this.ingredientCount = ingredientCount; + this.unit = unit; + // parse expiry date using parseDate method + this.expiryDate = parser.parseDate(expiryDate); + this.updateExpired(); + } - public void updateExpired() { - if (expiryDate.isBefore(LocalDate.now())) { - expired = true; - } else { - expired = false; + public void updateExpired() { + if (expiryDate.isBefore(LocalDate.now())) { + expired = true; + } else { + expired = false; + } } - } } diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index 40fbc71fa7..5929999708 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -4,107 +4,106 @@ import java.time.LocalDate; public class IngredientList extends HashMap { + private static final Parser parser = new Parser(); - private static final Parser parser = new Parser(); - - // public method to find count of ingredient - public Integer findIngredientCount(String ingredientName) { - try { - if (this.containsKey(ingredientName)) { - return this.get(ingredientName).ingredientCount; - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - return null; + // public method to find count of ingredient + public Integer findIngredientCount(String ingredientName) { + try { + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).ingredientCount; + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + return null; + } } - } - // public method to find expiry date of ingredient - public LocalDate findExpiryDate(String ingredientName) { - try { - if (this.containsKey(ingredientName)) { - return this.get(ingredientName).expiryDate; - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - return null; + // public method to find expiry date of ingredient + public LocalDate findExpiryDate(String ingredientName) { + try { + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).expiryDate; + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + return null; + } } - } - - public void addIngredient(Ingredient ingredient) { - super.put(ingredient.ingredientName, ingredient); - } - public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) { - try { - if (this.containsKey(ingredient.ingredientName)) { - ingredient.ingredientCount = ingredientCount; - ingredient.expiryDate = parser.parseDate(expiryDate); - ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); + public void addIngredient(Ingredient ingredient) { super.put(ingredient.ingredientName, ingredient); - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - System.out.println("Ingredient not found"); } - } - public void deleteIngredient(String ingredient) { - try { - if (this.containsKey(ingredient)) { - this.remove(ingredient); - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - System.out.println("Ingredient not found"); + public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) { + try { + if (this.containsKey(ingredient.ingredientName)) { + ingredient.ingredientCount = ingredientCount; + ingredient.expiryDate = parser.parseDate(expiryDate); + ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); + super.put(ingredient.ingredientName, ingredient); + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + System.out.println("Ingredient not found"); + } } - } - // private indexed list of ingredients, count and expiry date - private String listIngredients() { - String ingredientList = ""; - int index = 1; - for (Ingredient ingredient : this.values()) { - ingredientList += String.format("%d. %s (count: %d, expires on %s)", index, - ingredient.ingredientName, ingredient.ingredientCount, ingredient.expiryDate); + public void deleteIngredient(String ingredient) { + try { + if (this.containsKey(ingredient)) { + this.remove(ingredient); + } + throw new Exceptions.IngredientNotFoundException(); + } catch (Exceptions.IngredientNotFoundException e) { + System.out.println("Ingredient not found"); + } } - return ingredientList; - } - // public method to print ingredients in list with indexing - public void printIngredients() { - System.out.println(listIngredients()); - } + // private indexed list of ingredients, count and expiry date + private String listIngredients() { + String ingredientList = ""; + int index = 1; + for (Ingredient ingredient : this.values()) { + ingredientList += String.format("%d. %s (count: %d, expires on %s)", index, + ingredient.ingredientName, ingredient.ingredientCount, ingredient.expiryDate); + } + return ingredientList; + } - // public method to print expired ingredients and expiry date - // if no expired ingredients, print "No expired ingredients" - public void printExpiredIngredients() { - String expiredIngredients = ""; - int index = 1; - for (Ingredient ingredient : this.values()) { - if (ingredient.expired) { - expiredIngredients += String.format("%d. %s (expires on %s)", index, - ingredient.ingredientName, ingredient.expiryDate); - } + // public method to print ingredients in list with indexing + public void printIngredients() { + System.out.println(listIngredients()); } - if (expiredIngredients.equals("")) { - System.out.println("No expired ingredients"); - } else { - System.out.println(expiredIngredients); + + // public method to print expired ingredients and expiry date + // if no expired ingredients, print "No expired ingredients" + public void printExpiredIngredients() { + String expiredIngredients = ""; + int index = 1; + for (Ingredient ingredient : this.values()) { + if (ingredient.expired) { + expiredIngredients += String.format("%d. %s (expires on %s)", index, + ingredient.ingredientName, ingredient.expiryDate); + } + } + if (expiredIngredients.equals("")) { + System.out.println("No expired ingredients"); + } else { + System.out.println(expiredIngredients); + } } - } - // public method to clear all ingredients - public void clearIngredients() { - this.clear(); - } + // public method to clear all ingredients + public void clearIngredients() { + this.clear(); + } - // public method to clear expired ingredients - public void clearExpiredIngredients() { - for (Ingredient ingredient : this.values()) { - if (ingredient.expired) { - this.remove(ingredient.ingredientName); - } + // public method to clear expired ingredients + public void clearExpiredIngredients() { + for (Ingredient ingredient : this.values()) { + if (ingredient.expired) { + this.remove(ingredient.ingredientName); + } + } } - } } diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 57f10416cd..9de2f14de0 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -2,223 +2,229 @@ import java.io.IOException; import java.util.Scanner; + import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; public class Meal360 { - /** - * Main entry-point for the java.duke.Meal360 application. - */ - - private static Boolean canExit = false; - private static final Ui ui = new Ui(); - private static final Parser parser = new Parser(); - private static final Database database = new Database(); - private static RecipeList recipeList = new RecipeList(); - private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); - - public static void startApp() { - ui.printSeparator(); - ui.printWelcomeMessage(); - ui.printSeparator(); - - // Load database - ui.printMessage("Loading database..."); - try { - recipeList = database.loadDatabase(); - ui.printMessage("Database loaded successfully."); - } catch (Exception e) { - ui.printMessage("Error loading database, loading default database instead."); - ui.printMessage("Overwriting database with new default database..."); - recipeList = database.defaultRecipeList(); - } + /** + * Main entry-point for the java.duke.Meal360 application. + */ - ui.printSeparator(); - } - - public static void receiveInput(String input) { - input = input.replaceAll("\\s+", " "); - String[] command = input.trim().split(" "); - - if (input.equalsIgnoreCase("bye")) { - canExit = true; - } else if (command[0].equals("delete")) { - ui.printSeparator(); - try { - String deletedRecipe = parser.parseDeleteRecipe(command, recipeList); - ui.printMessage("Noted. I've removed this recipe:"); - ui.printMessage(deletedRecipe); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = - "Please enter a valid recipe number or name. You did not enter a recipe number or " - + "name."; - ui.printMessage(errorMessage); - } catch (IndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number or name. You entered %s, " - + "which is in invalid.", - command[1]); - ui.printMessage(errorMessage); - } - ui.printSeparator(); - } else if (command[0].equals("view")) { - ui.printSeparator(); - try { - Recipe recipe = parser.parseViewRecipe(command, recipeList); - ui.printRecipe(recipe); - } catch (NumberFormatException | IndexOutOfBoundsException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("list")) { - try { - ui.printSeparator(); - RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); - ui.listRecipe(recipeListToPrint); - } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("add")) { - ui.printSeparator(); - try { - Recipe newRecipe = parser.parseAddRecipe(command, recipeList); - ui.printMessage("I've added this new recipe:" + newRecipe.getName()); - ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = "Please enter a valid recipe name."; - ui.printMessage(errorMessage); - } catch (NullPointerException e) { - String errorMessage = "Recipe already exists. Add a new recipe."; - ui.printMessage(errorMessage); - } - ui.printSeparator(); - } else if (command[0].equals("edit")) { - ui.printSeparator(); - try { - Recipe recipeToEdit = parser.parseEditRecipe(command, recipeList); - ui.printSeparator(); - ui.printMessage("I've edited this recipe:" + recipeToEdit.getName()); - } catch (NumberFormatException e) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is not a number.", - command[1]); - ui.printMessage(errorMessage); - } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = "Please enter a valid recipe name."; - ui.printMessage(errorMessage); - } catch (IndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is out of bounds.", - command[1]); - ui.printMessage(errorMessage); - } catch (NullPointerException e) { - String errorMessage = "Recipe doesn't exist for editing."; - ui.printMessage(errorMessage); - } - ui.printSeparator(); - } else if (command[0].equals("tag")) { - try { + private static Boolean canExit = false; + private static final Ui ui = new Ui(); + private static final Parser parser = new Parser(); + private static final Database database = new Database(); + private static RecipeList recipeList = new RecipeList(); + private static final WeeklyPlan weeklyPlan = new WeeklyPlan(); + + public static void startApp() { ui.printSeparator(); - String tag = parser.parseTagRecipe(command, recipeList); - ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); - } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("random")) { - ui.printSeparator(); - try { - Recipe randomRecipe = parser.parseRandomRecipe(recipeList); - ui.printRecipe(randomRecipe); - } catch (NumberFormatException | IndexOutOfBoundsException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("weekly")) { - try { + ui.printWelcomeMessage(); ui.printSeparator(); - WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); - - switch (command[1]) { - case "/add": - case "/multiadd": - weeklyPlan.addPlans(recipeMap); - ui.printMessage("I've added the recipes to your weekly plan!"); - break; - case "/delete": - case "/multidelete": - weeklyPlan.deletePlans(recipeMap); - ui.printMessage("I've deleted the recipes from your weekly plan!"); - break; - case "/clear": - weeklyPlan.clearPlan(); - ui.printMessage("I've cleared your entire weekly plan!"); - break; - default: - ui.printMessage("Please enter a valid command."); - break; + + // Load database + ui.printMessage("Loading database..."); + try { + recipeList = database.loadDatabase(); + ui.printMessage("Database loaded successfully."); + } catch (Exception e) { + ui.printMessage("Error loading database, loading default database instead."); + ui.printMessage("Overwriting database with new default database..."); + recipeList = database.defaultRecipeList(); } - } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException - | ArrayIndexOutOfBoundsException e) { - ui.printMessage(e.getMessage()); - } - ui.printSeparator(); - } else if (command[0].equals("available")) { - // list recipes with ingredients all in ingredient list - ui.printSeparator(); - RecipeList availableRecipes = recipeList.availableRecipes(); - ui.listAvailableRecipes(availableRecipes); - ui.printSeparator(); - } else if (command[0].equals("weeklyingredients")) { - ui.printSeparator(); - ui.printWeeklyIngredients(weeklyPlan, recipeList); - ui.printSeparator(); - } else if (command[0].equals("weeklyplan")) { - ui.printSeparator(); - ui.printWeeklyPlan(weeklyPlan); - ui.printSeparator(); - } else if (command[0].equals("help")) { - ui.printSeparator(); - ui.printHelp(); - ui.printSeparator(); - } else { - ui.printSeparator(); - ui.printMessage("I'm sorry, but I don't know what that means :-("); - ui.printSeparator(); + + ui.printSeparator(); } - } - - public static void exitApp() { - ui.printSeparator(); - - // Save database - ui.printMessage("Saving database..."); - try { - database.saveDatabase(recipeList); - ui.printMessage("Database saved successfully."); - } catch (IOException error) { - ui.printMessage("Error saving database."); + + public static void receiveInput(String input) { + input = input.replaceAll("\\s+", " "); + String[] command = input.trim().split(" "); + + if (input.equalsIgnoreCase("bye")) { + canExit = true; + } else if (command[0].equals("delete")) { + ui.printSeparator(); + try { + String deletedRecipe = parser.parseDeleteRecipe(command, recipeList); + ui.printMessage("Noted. I've removed this recipe:"); + ui.printMessage(deletedRecipe); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = + "Please enter a valid recipe number or name. You did not enter a recipe number or " + + "name."; + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number or name. You entered %s, " + + "which is in invalid.", + command[1]); + ui.printMessage(errorMessage); + } + ui.printSeparator(); + } else if (command[0].equals("view")) { + ui.printSeparator(); + try { + Recipe recipe = parser.parseViewRecipe(command, recipeList); + ui.printRecipe(recipe); + } catch (NumberFormatException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("list")) { + try { + ui.printSeparator(); + RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); + ui.listRecipe(recipeListToPrint); + } catch (IllegalArgumentException | IndexOutOfBoundsException | + NullPointerException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("add")) { + ui.printSeparator(); + try { + Recipe newRecipe = parser.parseAddRecipe(command, recipeList); + ui.printMessage("I've added this new recipe:" + newRecipe.getName()); + ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = "Please enter a valid recipe name."; + ui.printMessage(errorMessage); + } catch (NullPointerException e) { + String errorMessage = "Recipe already exists. Add a new recipe."; + ui.printMessage(errorMessage); + } + ui.printSeparator(); + } else if (command[0].equals("edit")) { + ui.printSeparator(); + try { + Recipe recipeToEdit = parser.parseEditRecipe(command, recipeList); + ui.printSeparator(); + ui.printMessage("I've edited this recipe:" + recipeToEdit.getName()); + } catch (NumberFormatException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + + "which is not a number.", + command[1]); + ui.printMessage(errorMessage); + } catch (ArrayIndexOutOfBoundsException e) { + String errorMessage = "Please enter a valid recipe name."; + ui.printMessage(errorMessage); + } catch (IndexOutOfBoundsException e) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + + "which is out of bounds.", + command[1]); + ui.printMessage(errorMessage); + } catch (NullPointerException e) { + String errorMessage = "Recipe doesn't exist for editing."; + ui.printMessage(errorMessage); + } + ui.printSeparator(); + } else if (command[0].equals("tag")) { + try { + ui.printSeparator(); + String tag = parser.parseTagRecipe(command, recipeList); + ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); + } catch (IllegalArgumentException | IndexOutOfBoundsException | + NullPointerException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("random")) { + ui.printSeparator(); + try { + Recipe randomRecipe = parser.parseRandomRecipe(recipeList); + ui.printRecipe(randomRecipe); + } catch (NumberFormatException | IndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("weekly")) { + try { + ui.printSeparator(); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipeList); + + switch (command[1]) { + case "/add": + case "/multiadd": + weeklyPlan.addPlans(recipeMap); + ui.printMessage("I've added the recipes to your weekly plan!"); + break; + case "/delete": + case "/multidelete": + weeklyPlan.deletePlans(recipeMap); + ui.printMessage("I've deleted the recipes from your weekly plan!"); + break; + case "/clear": + weeklyPlan.clearPlan(); + ui.printMessage("I've cleared your entire weekly plan!"); + break; + default: + ui.printMessage("Please enter a valid command."); + break; + } + } catch (IllegalArgumentException | InvalidNegativeValueException | + InvalidRecipeNameException + | ArrayIndexOutOfBoundsException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); + } else if (command[0].equals("available")) { + // list recipes with ingredients all in ingredient list + ui.printSeparator(); + RecipeList availableRecipes = recipeList.availableRecipes(); + ui.listAvailableRecipes(availableRecipes); + ui.printSeparator(); + } else if (command[0].equals("weeklyingredients")) { + ui.printSeparator(); + ui.printWeeklyIngredients(weeklyPlan, recipeList); + ui.printSeparator(); + } else if (command[0].equals("weeklyplan")) { + ui.printSeparator(); + ui.printWeeklyPlan(weeklyPlan); + ui.printSeparator(); + } else if (command[0].equals("help")) { + ui.printSeparator(); + ui.printHelp(); + ui.printSeparator(); + } else { + ui.printSeparator(); + ui.printMessage("I'm sorry, but I don't know what that means :-("); + ui.printSeparator(); + } } - ui.printGoodbyeMessage(); - ui.printSeparator(); - } + public static void exitApp() { + ui.printSeparator(); + + // Save database + ui.printMessage("Saving database..."); + try { + database.saveDatabase(recipeList); + ui.printMessage("Database saved successfully."); + } catch (IOException error) { + ui.printMessage("Error saving database."); + } + + ui.printGoodbyeMessage(); + ui.printSeparator(); + } - public static void main(String[] args) { + public static void main(String[] args) { - startApp(); + startApp(); - String line; - Scanner userInput = new Scanner(System.in); + String line; + Scanner userInput = new Scanner(System.in); - do { - line = userInput.nextLine(); - receiveInput(line); - } while (!canExit); + do { + line = userInput.nextLine(); + receiveInput(line); + } while (!canExit); - exitApp(); - } + exitApp(); + } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index d3e36c5b86..66ef4b56a1 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -3,587 +3,597 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; + import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; + import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.LocalDate; public class Parser { - Ui ui = new Ui(); + Ui ui = new Ui(); - public String combineWords(String[] input, int startIndex, int length) { - StringBuilder word = new StringBuilder(input[startIndex]); - for (int i = startIndex + 1; i < length; i++) { - word.append(" ").append(input[i]); + public String combineWords(String[] input, int startIndex, int length) { + StringBuilder word = new StringBuilder(input[startIndex]); + for (int i = startIndex + 1; i < length; i++) { + word.append(" ").append(input[i]); + } + + return word.toString(); + } + + public HashMap parseIngredientName(String[] command) { + HashMap ingredients = new HashMap<>(); + int flag = 0; + StringBuilder add = null; + String ingredientName; + int ingredientQuantity; + int indexOfEqual; + + for (String s : command) { + try { + indexOfEqual = s.indexOf("="); + if (indexOfEqual == -1) { + if (add != null) { + add.append(" ").append(s); + } else { + add = new StringBuilder(s); + } + flag++; + + } else { + if (flag > 0) { + indexOfEqual = s.indexOf("="); + ingredientName = (s.substring(0, indexOfEqual)); + ingredientName = add + " " + ingredientName; + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + flag = 0; + add = null; + } else { + ingredientName = s.substring(0, indexOfEqual); + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + } + + ingredients.put(ingredientName, ingredientQuantity); + + } + } catch (NumberFormatException e) { + ui.printSeparator(); + String errorMessage = "Please enter ingredients properly![eg: chicken=100]"; + ui.printMessage(errorMessage); + ui.printSeparator(); + } + } + return ingredients; } - return word.toString(); - } - - public HashMap parseIngredientName(String[] command) { - HashMap ingredients = new HashMap<>(); - int flag = 0; - StringBuilder add = null; - String ingredientName; - int ingredientQuantity; - int indexOfEqual; - - for (String s : command) { - try { - indexOfEqual = s.indexOf("="); - if (indexOfEqual == -1) { - if (add != null) { - add.append(" ").append(s); - } else { - add = new StringBuilder(s); - } - flag++; + public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { + String recipeName = combineWords(input, 2, input.length); + if (recipeList.findByName(recipeName) != null) { + return null; + } + HashMap ingredients = new HashMap<>(); + Scanner userInput = new Scanner(System.in); + System.out.println("Please Enter The Ingredients & Quantity: "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + break; + } else { + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + } + } + Recipe newRecipe = new Recipe(recipeName, ingredients); + recipeList.addRecipe(newRecipe); + return newRecipe; + } + + public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { + String recipeName = combineWords(input, 2, input.length); + Recipe recipeToEdit; + HashMap ingredients; + Scanner userInput = new Scanner(System.in); + if (recipeList.findByName(recipeName) == null) { + return null; + } + recipeToEdit = recipeList.findByName(recipeName); + System.out.println("Do you want to edit recipe fully or partially?"); + System.out.println( + "Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); + + Scanner getInput = new Scanner(System.in); + int index = getInput.nextInt(); + if (index == 1) { + System.out.println("Please Enter New Ingredients & Quantity: "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + break; + } + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + recipeList.editRecipe(recipeToEdit, ingredients); + } + } else if (index == 2) { + System.out.println("These are the ingredients for the recipe:"); + ui.printSeparator(); + Recipe recipe = parseViewRecipe(recipeName, recipeList); + ui.printRecipe(recipe); + ui.printSeparator(); + System.out.println("Which ingredient do you want to change?"); + int ingredientIndex = getInput.nextInt(); + ingredientIndex -= 1; + int count = 0; + String ingredientToRemove = null; + for (String ingredient : recipeToEdit.getIngredients().keySet()) { + if (ingredientIndex == count) { + ingredientToRemove = ingredient; + System.out.println("Ingredient to be changed:"); + ui.printSeparator(); + String toPrint = String.format("%s(%d)", ingredient, + recipeToEdit.getIngredients().get(ingredient)); + System.out.println(ui.formatMessage(toPrint)); + ui.printSeparator(); + break; + } + count++; + } + System.out.println("Please enter the new ingredient:"); + String line = userInput.nextLine(); + String command = line.replaceAll("\\s+", " "); + int indexOfEqual = command.indexOf("="); + String newIngredientName = command.substring(0, indexOfEqual); + int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual + 1)); + recipeToEdit.getIngredients().remove(ingredientToRemove); + recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); + recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); + } else if (index == 3) { + HashMap newIngredientList = recipeToEdit.getIngredients(); + System.out.println("These are the current ingredients:"); + ui.printSeparator(); + Recipe recipe = parseViewRecipe(recipeName, recipeList); + ui.printRecipe(recipe); + ui.printSeparator(); + System.out.println( + "Please Enter Additional Ingredients & Quantity (Enter done when complete): "); + while (true) { + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + break; + } else { + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + newIngredientList.putAll(ingredients); + } + } + recipeList.editRecipe(recipeToEdit, newIngredientList); + } + return recipeToEdit; + } + + public String parseDeleteRecipe(String[] input, RecipeList recipeList) { + assert input[0].equals("delete"); + // user inputted recipe name + if (input[1].contains("r/")) { + // skip over /r in recipe name + String recipeToDelete = input[1].substring(2); + if (recipeToDelete.equals("all")) { + StringBuilder allRecipes = new StringBuilder(); + System.out.println("recipeList size: " + recipeList.size()); + int index = 0; + while (recipeList.size() != 0) { + allRecipes.append(recipeList.deleteRecipe(index).getName()).append(", "); + } + allRecipes = new StringBuilder(allRecipes.substring(0, allRecipes.length() - 2)); + return allRecipes.toString(); + } else { + int recipeIndex = 0; + for (Recipe recipe : recipeList) { + // find index of recipe we want to delete + if (recipe.getName().equals(recipeToDelete)) { + break; + } + recipeIndex++; + } + return recipeList.deleteRecipe(recipeIndex).getName(); + } + // user inputted index of recipe in list } else { - if (flag > 0) { - indexOfEqual = s.indexOf("="); - ingredientName = (s.substring(0, indexOfEqual)); - ingredientName = add + " " + ingredientName; - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); - flag = 0; - add = null; - } else { - ingredientName = s.substring(0, indexOfEqual); - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); - } - - ingredients.put(ingredientName, ingredientQuantity); - - } - } catch (NumberFormatException e) { - ui.printSeparator(); - String errorMessage = "Please enter ingredients properly![eg: chicken=100]"; - ui.printMessage(errorMessage); - ui.printSeparator(); - } + // check if deleting a range of recipes + if (input[1].length() >= 3) { + StringBuilder rangeRecipes = new StringBuilder(); + int startIndex = Integer.parseInt(input[1].charAt(0) + ""); + int endIndex = Integer.parseInt(input[1].charAt(2) + ""); + startIndex -= 1; + endIndex -= 1; + int newSize = recipeList.size() - ((endIndex - startIndex) + 1); + while (recipeList.size() != newSize) { + rangeRecipes.append(recipeList.deleteRecipe(startIndex).getName()).append(", "); + } + rangeRecipes = new StringBuilder( + rangeRecipes.substring(0, rangeRecipes.length() - 2)); + return rangeRecipes.toString(); + } else { + int recipeIndex = Integer.parseInt(input[1]); + // need to subtract 1 since list is 1-based + return recipeList.deleteRecipe(recipeIndex - 1).getName(); + } + } } - return ingredients; - } - public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { - String recipeName = combineWords(input, 2, input.length); - if (recipeList.findByName(recipeName) != null) { - return null; - } - HashMap ingredients = new HashMap<>(); - Scanner userInput = new Scanner(System.in); - System.out.println("Please Enter The Ingredients & Quantity: "); - while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - ui.printSeparator(); - break; - } else { - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - } - } - Recipe newRecipe = new Recipe(recipeName, ingredients); - recipeList.addRecipe(newRecipe); - return newRecipe; - } - - public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { - String recipeName = combineWords(input, 2, input.length); - Recipe recipeToEdit; - HashMap ingredients; - Scanner userInput = new Scanner(System.in); - if (recipeList.findByName(recipeName) == null) { - return null; - } - recipeToEdit = recipeList.findByName(recipeName); - System.out.println("Do you want to edit recipe fully or partially?"); - System.out.println( - "Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); - - Scanner getInput = new Scanner(System.in); - int index = getInput.nextInt(); - if (index == 1) { - System.out.println("Please Enter New Ingredients & Quantity: "); - while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - break; - } - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - recipeList.editRecipe(recipeToEdit, ingredients); - } - } else if (index == 2) { - System.out.println("These are the ingredients for the recipe:"); - ui.printSeparator(); - Recipe recipe = parseViewRecipe(recipeName, recipeList); - ui.printRecipe(recipe); - ui.printSeparator(); - System.out.println("Which ingredient do you want to change?"); - int ingredientIndex = getInput.nextInt(); - ingredientIndex -= 1; - int count = 0; - String ingredientToRemove = null; - for (String ingredient : recipeToEdit.getIngredients().keySet()) { - if (ingredientIndex == count) { - ingredientToRemove = ingredient; - System.out.println("Ingredient to be changed:"); - ui.printSeparator(); - String toPrint = String.format("%s(%d)", ingredient, - recipeToEdit.getIngredients().get(ingredient)); - System.out.println(ui.formatMessage(toPrint)); - ui.printSeparator(); - break; - } - count++; - } - System.out.println("Please enter the new ingredient:"); - String line = userInput.nextLine(); - String command = line.replaceAll("\\s+", " "); - int indexOfEqual = command.indexOf("="); - String newIngredientName = command.substring(0, indexOfEqual); - int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual + 1)); - recipeToEdit.getIngredients().remove(ingredientToRemove); - recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); - recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); - } else if (index == 3) { - HashMap newIngredientList = recipeToEdit.getIngredients(); - System.out.println("These are the current ingredients:"); - ui.printSeparator(); - Recipe recipe = parseViewRecipe(recipeName, recipeList); - ui.printRecipe(recipe); - ui.printSeparator(); - System.out.println( - "Please Enter Additional Ingredients & Quantity (Enter done when complete): "); - while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - ui.printSeparator(); - break; + public String parseTagRecipe(String[] inputs, RecipeList recipeList) { + String tag; + boolean isOnlyTagWordInCommand = inputs.length == 1; + boolean isAddTag; + boolean isRemoveTag; + + if (isOnlyTagWordInCommand) { + throw new IllegalArgumentException("Please indicate at least a tag and a recipe."); + } + + StringBuilder commandString = new StringBuilder(inputs[1]); + for (int i = 2; i < inputs.length; i++) { + commandString.append(" ").append(inputs[i]); + } + + isAddTag = commandString.indexOf(">>") == -1 && commandString.indexOf("<<") != -1; + isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; + + if (!(isAddTag || isRemoveTag)) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } else if (isAddTag) { + tag = parseAddRecipeTag(commandString.toString(), recipeList); + } else if (isRemoveTag) { + tag = parseRemoveRecipeTag(commandString.toString(), recipeList); } else { - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - newIngredientList.putAll(ingredients); + throw new IllegalArgumentException("Invalid command."); } - } - recipeList.editRecipe(recipeToEdit, newIngredientList); + return tag; } - return recipeToEdit; - } - - public String parseDeleteRecipe(String[] input, RecipeList recipeList) { - assert input[0].equals("delete"); - // user inputted recipe name - if (input[1].contains("r/")) { - // skip over /r in recipe name - String recipeToDelete = input[1].substring(2); - if (recipeToDelete.equals("all")) { - StringBuilder allRecipes = new StringBuilder(); - System.out.println("recipeList size: " + recipeList.size()); - int index = 0; - while (recipeList.size() != 0) { - allRecipes.append(recipeList.deleteRecipe(index).getName()).append(", "); - } - allRecipes = new StringBuilder(allRecipes.substring(0, allRecipes.length() - 2)); - return allRecipes.toString(); - } else { - int recipeIndex = 0; - for (Recipe recipe : recipeList) { - // find index of recipe we want to delete - if (recipe.getName().equals(recipeToDelete)) { - break; - } - recipeIndex++; - } - return recipeList.deleteRecipe(recipeIndex).getName(); - } - // user inputted index of recipe in list - } else { - // check if deleting a range of recipes - if (input[1].length() >= 3) { - StringBuilder rangeRecipes = new StringBuilder(); - int startIndex = Integer.parseInt(input[1].charAt(0) + ""); - int endIndex = Integer.parseInt(input[1].charAt(2) + ""); - startIndex -= 1; - endIndex -= 1; - int newSize = recipeList.size() - ((endIndex - startIndex) + 1); - while (recipeList.size() != newSize) { - rangeRecipes.append(recipeList.deleteRecipe(startIndex).getName()).append(", "); - } - rangeRecipes = new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2)); - return rangeRecipes.toString(); - } else { - int recipeIndex = Integer.parseInt(input[1]); - // need to subtract 1 since list is 1-based - return recipeList.deleteRecipe(recipeIndex - 1).getName(); - } - } - } + public String parseAddRecipeTag(String command, RecipeList recipeList) { + String tag; + Recipe recipe; + String[] recipesToTag; + boolean isUnableToFindTheRecipe; + String[] args = command.trim().split("<<"); + boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); - public String parseTagRecipe(String[] inputs, RecipeList recipeList) { - String tag; - boolean isOnlyTagWordInCommand = inputs.length == 1; - boolean isAddTag; - boolean isRemoveTag; + if (isNotEnoughArgs) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } - if (isOnlyTagWordInCommand) { - throw new IllegalArgumentException("Please indicate at least a tag and a recipe."); + tag = args[0].trim(); + recipesToTag = args[1].split("&&"); + for (String recipeName : recipesToTag) { + recipeName = recipeName.trim(); + recipe = recipeList.findByName(recipeName); + isUnableToFindTheRecipe = recipe == null; + if (isUnableToFindTheRecipe) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + + " tag."; + String errorMessage2 = + "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully added from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } + recipeList.addRecipeToTag(tag, recipe); + } + return tag; } - StringBuilder commandString = new StringBuilder(inputs[1]); - for (int i = 2; i < inputs.length; i++) { - commandString.append(" ").append(inputs[i]); - } + public String parseRemoveRecipeTag(String command, RecipeList recipeList) { + String tag; + Recipe recipe; + String[] recipesToRemove; + boolean isUnableToFindTag; + boolean isNoRecipeInTheList; + String[] args = command.trim().split(">>"); + boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); - isAddTag = commandString.indexOf(">>") == -1 && commandString.indexOf("<<") != -1; - isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; - - if (!(isAddTag || isRemoveTag)) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } else if (isAddTag) { - tag = parseAddRecipeTag(commandString.toString(), recipeList); - } else if (isRemoveTag) { - tag = parseRemoveRecipeTag(commandString.toString(), recipeList); - } else { - throw new IllegalArgumentException("Invalid command."); - } - return tag; - } - - public String parseAddRecipeTag(String command, RecipeList recipeList) { - String tag; - Recipe recipe; - String[] recipesToTag; - boolean isUnableToFindTheRecipe; - String[] args = command.trim().split("<<"); - boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); - - if (isNotEnoughArgs) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } + if (isNotEnoughArgs) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } - tag = args[0].trim(); - recipesToTag = args[1].split("&&"); - for (String recipeName : recipesToTag) { - recipeName = recipeName.trim(); - recipe = recipeList.findByName(recipeName); - isUnableToFindTheRecipe = recipe == null; - if (isUnableToFindTheRecipe) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + - "successfully added from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); - } - recipeList.addRecipeToTag(tag, recipe); - } - return tag; - } - - public String parseRemoveRecipeTag(String command, RecipeList recipeList) { - String tag; - Recipe recipe; - String[] recipesToRemove; - boolean isUnableToFindTag; - boolean isNoRecipeInTheList; - String[] args = command.trim().split(">>"); - boolean isNotEnoughArgs = args.length < 2 || args[0].equals("") || args[1].equals(""); - - if (isNotEnoughArgs) { - throw new IllegalArgumentException("Please enter the command in the correct format."); - } + tag = args[0].trim(); + isUnableToFindTag = !recipeList.tags.containsKey(tag); + if (isUnableToFindTag) { + throw new IndexOutOfBoundsException( + "There is no \"" + tag + "\" tag found. Please make sure you have " + + "entered the correct tag."); + } - tag = args[0].trim(); - isUnableToFindTag = !recipeList.tags.containsKey(tag); - if (isUnableToFindTag) { - throw new IndexOutOfBoundsException( - "There is no \"" + tag + "\" tag found. Please make sure you have " + - "entered the correct tag."); + recipesToRemove = args[1].split("&&"); + for (String recipeName : recipesToRemove) { + recipeName = recipeName.trim(); + recipe = recipeList.findByName(recipeName); + isNoRecipeInTheList = recipe == null; + if (isNoRecipeInTheList) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + + " tag."; + String errorMessage2 = + "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } + + try { + recipeList.removeRecipeFromTag(tag, recipe); + } catch (IndexOutOfBoundsException e) { + String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + + " tag."; + String errorMessage2 = + "All the recipe before \"" + recipeName + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + } + } + return tag; } - recipesToRemove = args[1].split("&&"); - for (String recipeName : recipesToRemove) { - recipeName = recipeName.trim(); - recipe = recipeList.findByName(recipeName); - isNoRecipeInTheList = recipe == null; - if (isNoRecipeInTheList) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); - } - - try { - recipeList.removeRecipeFromTag(tag, recipe); - } catch (IndexOutOfBoundsException e) { - String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); - } - } - return tag; - } - - public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { - String[] filters; - RecipeList recipeListToPrint; - boolean hasTagArgs = inputs.length > 2; - boolean isOnlyListWordInCommand = inputs.length == 1; - boolean isTag = false; - int firstArgsIndex = 1; - - if (isOnlyListWordInCommand) { - filters = null; - } else { - isTag = inputs[1].equals("/t"); - if (isTag && !hasTagArgs) { - throw new IllegalArgumentException("Please include at least a tag."); - } else if (isTag) { - firstArgsIndex = 2; - } - - StringBuilder filterString = new StringBuilder(inputs[firstArgsIndex]); - for (int i = firstArgsIndex + 1; i < inputs.length; i++) { - filterString.append(" ").append(inputs[i]); - } - - filters = filterString.toString().split("&&"); - } - recipeListToPrint = recipeList.listRecipes(filters, isTag); - return recipeListToPrint; - } - - public Recipe parseViewRecipe(String[] command, RecipeList recipes) { - assert command[0].equals("view"); - Recipe requestedRecipe; - int recipeIndex = 0; - try { - recipeIndex = Integer.parseInt(command[1]); - requestedRecipe = recipes.get(recipeIndex - 1); - } catch (NumberFormatException error) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is not a number.", - command[1]); - throw new NumberFormatException(errorMessage); - } catch (ArrayIndexOutOfBoundsException error) { - String errorMessage = "Please enter a valid recipe number. You did not enter a recipe number."; - throw new ArrayIndexOutOfBoundsException(errorMessage); - } catch (IndexOutOfBoundsException error) { - String errorMessage = String.format( - "Please enter a valid recipe number. You entered %d, " + "which is out of bounds.", - recipeIndex); - throw new IndexOutOfBoundsException(errorMessage); - } - return requestedRecipe; - } - - public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { - int recipeIndex = 1; - for (Recipe recipe : recipes) { - if (recipe.getName().equals(recipeName)) { - break; - } - recipeIndex++; - } - return recipes.get(recipeIndex - 1); - } + public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { + String[] filters; + RecipeList recipeListToPrint; + boolean hasTagArgs = inputs.length > 2; + boolean isOnlyListWordInCommand = inputs.length == 1; + boolean isTag = false; + int firstArgsIndex = 1; - public Recipe parseRandomRecipe(RecipeList recipes) { - Recipe randomRecipe = recipes.randomRecipe(); - if (recipes.size() == 0) { - throw new NullPointerException("There is no recipe in the list to random"); - } - return randomRecipe; - } - - public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException, InvalidNegativeValueException { - WeeklyPlan updatedWeeklyPlan; - try { - switch (command[1]) { - case "/add": - updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); - break; - case "/delete": - updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); - break; - case "/multiadd": - updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); - break; - case "/multidelete": - updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); - break; - default: - throw new IllegalArgumentException( - "Please indicate if you would want to add or delete the recipe from your weekly " - + "plan."); - } - - return updatedWeeklyPlan; - } catch (ArrayIndexOutOfBoundsException error) { - throw new ArrayIndexOutOfBoundsException("Insufficient number of arguments provided."); - } catch (NumberFormatException error) { - throw new NumberFormatException("Please enter a valid number as the last argument."); + if (isOnlyListWordInCommand) { + filters = null; + } else { + isTag = inputs[1].equals("/t"); + if (isTag && !hasTagArgs) { + throw new IllegalArgumentException("Please include at least a tag."); + } else if (isTag) { + firstArgsIndex = 2; + } + + StringBuilder filterString = new StringBuilder(inputs[firstArgsIndex]); + for (int i = firstArgsIndex + 1; i < inputs.length; i++) { + filterString.append(" ").append(inputs[i]); + } + + filters = filterString.toString().split("&&"); + } + recipeListToPrint = recipeList.listRecipes(filters, isTag); + return recipeListToPrint; } - } - private WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { - int numDays = Integer.parseInt(command[command.length - 1]); - if (numDays < 1) { - throw new InvalidNegativeValueException("Number of days needs to be at least 1."); + public Recipe parseViewRecipe(String[] command, RecipeList recipes) { + assert command[0].equals("view"); + Recipe requestedRecipe; + int recipeIndex = 0; + try { + recipeIndex = Integer.parseInt(command[1]); + requestedRecipe = recipes.get(recipeIndex - 1); + } catch (NumberFormatException error) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %s, " + "which is not a number.", + command[1]); + throw new NumberFormatException(errorMessage); + } catch (ArrayIndexOutOfBoundsException error) { + String errorMessage = "Please enter a valid recipe number. You did not enter a recipe number."; + throw new ArrayIndexOutOfBoundsException(errorMessage); + } catch (IndexOutOfBoundsException error) { + String errorMessage = String.format( + "Please enter a valid recipe number. You entered %d, " + "which is out of bounds.", + recipeIndex); + throw new IndexOutOfBoundsException(errorMessage); + } + return requestedRecipe; } - int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; - WeeklyPlan thisWeekPlan = new WeeklyPlan(); - StringBuilder recipeName = new StringBuilder(command[2]); - for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i]); + public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { + int recipeIndex = 1; + for (Recipe recipe : recipes) { + if (recipe.getName().equals(recipeName)) { + break; + } + recipeIndex++; + } + return recipes.get(recipeIndex - 1); } - if (recipes.findByName(recipeName.toString().trim()) != null) { - thisWeekPlan.put(recipeName.toString(), numDays); - return thisWeekPlan; - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } - - private WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - int nameLastIndex = command.length; - WeeklyPlan thisWeekPlan = new WeeklyPlan(); - StringBuilder recipeName = new StringBuilder(command[2]); - for (int i = 3; i < nameLastIndex; i++) { - recipeName.append(" ").append(command[i].toLowerCase().trim()); + public Recipe parseRandomRecipe(RecipeList recipes) { + Recipe randomRecipe = recipes.randomRecipe(); + if (recipes.size() == 0) { + throw new NullPointerException("There is no recipe in the list to random"); + } + return randomRecipe; + } + + public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException, InvalidNegativeValueException { + WeeklyPlan updatedWeeklyPlan; + try { + switch (command[1]) { + case "/add": + updatedWeeklyPlan = parseAddSingleWeeklyPlan(command, recipes); + break; + case "/delete": + updatedWeeklyPlan = parseDeleteSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + updatedWeeklyPlan = parseAddMultiWeeklyPlan(command, recipes); + break; + case "/multidelete": + updatedWeeklyPlan = parseDeleteMultiWeeklyPlan(command, recipes); + break; + default: + throw new IllegalArgumentException( + "Please indicate if you would want to add or delete the recipe from your weekly " + + "plan."); + } + + return updatedWeeklyPlan; + } catch (ArrayIndexOutOfBoundsException error) { + throw new ArrayIndexOutOfBoundsException("Insufficient number of arguments provided."); + } catch (NumberFormatException error) { + throw new NumberFormatException("Please enter a valid number as the last argument."); + } } - if (recipes.findByName(recipeName.toString().trim()) != null) { - thisWeekPlan.put(recipeName.toString(), 0); - return thisWeekPlan; - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } - - private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { - WeeklyPlan recipesToAdd = new WeeklyPlan(); - ArrayList quantities = new ArrayList<>(); - ArrayList recipeNames = new ArrayList<>(); - ArrayList startIndices = new ArrayList<>(); - ArrayList endIndices = new ArrayList<>(); - StringBuilder recipeName = new StringBuilder(); - - for (int i = 0; i < command.length; i++) { - if (command[i].equals("/r")) { - startIndices.add(i); - } else if (command[i].equals("/q")) { - endIndices.add(i); - int quantity = Integer.parseInt(command[i + 1]); - if (quantity < 1) { - throw new InvalidNegativeValueException( - "Please enter a positive number for the quantity."); - } - quantities.add(quantity); - } - } + private WeeklyPlan parseAddSingleWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidNegativeValueException, InvalidRecipeNameException { + int numDays = Integer.parseInt(command[command.length - 1]); + if (numDays < 1) { + throw new InvalidNegativeValueException("Number of days needs to be at least 1."); + } - // Checks that command is entered in the correct - if (startIndices.size() != endIndices.size()) { - throw new IllegalArgumentException( - "Please ensure the number of recipes and quantities match."); - } + int nameLastIndex = (command[1].equals("/add")) ? command.length - 1 : command.length; + WeeklyPlan thisWeekPlan = new WeeklyPlan(); + StringBuilder recipeName = new StringBuilder(command[2]); + for (int i = 3; i < nameLastIndex; i++) { + recipeName.append(" ").append(command[i]); + } - // Building the recipe names - for (int i = 0; i < startIndices.size(); i++) { - int nameStartIndex = startIndices.get(i) + 1; - int nameEndIndex = endIndices.get(i) - 1; - recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); + if (recipes.findByName(recipeName.toString().trim()) != null) { + thisWeekPlan.put(recipeName.toString(), numDays); + return thisWeekPlan; + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } } - // Add each recipe to the weekly plan - try { - for (int i = 0; i < recipeNames.size(); i++) { - if (recipes.findByName(recipeNames.get(i)) != null) { - recipesToAdd.put(recipeNames.get(i), quantities.get(i)); + private WeeklyPlan parseDeleteSingleWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException { + int nameLastIndex = command.length; + WeeklyPlan thisWeekPlan = new WeeklyPlan(); + StringBuilder recipeName = new StringBuilder(command[2]); + for (int i = 3; i < nameLastIndex; i++) { + recipeName.append(" ").append(command[i].toLowerCase().trim()); + } + + if (recipes.findByName(recipeName.toString().trim()) != null) { + thisWeekPlan.put(recipeName.toString(), 0); + return thisWeekPlan; } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); } - } - } catch (NumberFormatException error) { - throw new NumberFormatException("Please enter a positive number for the quantity."); } - return recipesToAdd; - } + private WeeklyPlan parseAddMultiWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidNegativeValueException, InvalidRecipeNameException { + WeeklyPlan recipesToAdd = new WeeklyPlan(); + ArrayList quantities = new ArrayList<>(); + ArrayList recipeNames = new ArrayList<>(); + ArrayList startIndices = new ArrayList<>(); + ArrayList endIndices = new ArrayList<>(); + StringBuilder recipeName = new StringBuilder(); + + for (int i = 0; i < command.length; i++) { + if (command[i].equals("/r")) { + startIndices.add(i); + } else if (command[i].equals("/q")) { + endIndices.add(i); + int quantity = Integer.parseInt(command[i + 1]); + if (quantity < 1) { + throw new InvalidNegativeValueException( + "Please enter a positive number for the quantity."); + } + quantities.add(quantity); + } + } - private WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException { - WeeklyPlan recipesToDelete = new WeeklyPlan(); - ArrayList recipeNames = new ArrayList<>(); - ArrayList startIndices = new ArrayList<>(); - StringBuilder recipeName = new StringBuilder(); + // Checks that command is entered in the correct + if (startIndices.size() != endIndices.size()) { + throw new IllegalArgumentException( + "Please ensure the number of recipes and quantities match."); + } - for (int i = 0; i < command.length; i++) { - if (command[i].equals("/r")) { - startIndices.add(i); - } - } + // Building the recipe names + for (int i = 0; i < startIndices.size(); i++) { + int nameStartIndex = startIndices.get(i) + 1; + int nameEndIndex = endIndices.get(i) - 1; + recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, + nameEndIndex); + } - if (startIndices.size() == 0) { - throw new IllegalArgumentException("Please use /r to indicate the recipe to be deleted."); + // Add each recipe to the weekly plan + try { + for (int i = 0; i < recipeNames.size(); i++) { + if (recipes.findByName(recipeNames.get(i)) != null) { + recipesToAdd.put(recipeNames.get(i), quantities.get(i)); + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } + } + } catch (NumberFormatException error) { + throw new NumberFormatException("Please enter a positive number for the quantity."); + } + + return recipesToAdd; } - // Building the recipe names - for (int i = 0; i < startIndices.size(); i++) { - int nameStartIndex = startIndices.get(i) + 1; - int nameEndIndex = - (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; + private WeeklyPlan parseDeleteMultiWeeklyPlan(String[] command, RecipeList recipes) + throws InvalidRecipeNameException { + WeeklyPlan recipesToDelete = new WeeklyPlan(); + ArrayList recipeNames = new ArrayList<>(); + ArrayList startIndices = new ArrayList<>(); + StringBuilder recipeName = new StringBuilder(); - recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); - } + for (int i = 0; i < command.length; i++) { + if (command[i].equals("/r")) { + startIndices.add(i); + } + } - // Add each recipe to the weekly plan - for (String name : recipeNames) { - if (recipes.findByName(name) != null) { - recipesToDelete.put(name, 0); - } else { - throw new InvalidRecipeNameException("Please indicate a valid recipe name."); - } - } + if (startIndices.size() == 0) { + throw new IllegalArgumentException( + "Please use /r to indicate the recipe to be deleted."); + } + + // Building the recipe names + for (int i = 0; i < startIndices.size(); i++) { + int nameStartIndex = startIndices.get(i) + 1; + int nameEndIndex = + (i == startIndices.size() - 1) ? command.length - 1 : startIndices.get(i + 1) - 1; + + recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, + nameEndIndex); + } - return recipesToDelete; - } + // Add each recipe to the weekly plan + for (String name : recipeNames) { + if (recipes.findByName(name) != null) { + recipesToDelete.put(name, 0); + } else { + throw new InvalidRecipeNameException("Please indicate a valid recipe name."); + } + } - private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, - StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { - recipeName.append(command[nameStartIndex].toLowerCase().trim()); - for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { - recipeName.append(" ").append(command[j].toLowerCase().trim()); + return recipesToDelete; } - recipeNames.add(recipeName.toString()); - recipeName = new StringBuilder(); - return recipeName; - } - - // parser to read dd/mm/yyyy format as local date catching invalid date format - public LocalDate parseDate(String input) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); - try { - return LocalDate.parse(input, formatter); - } catch (DateTimeParseException e) { - throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy"); + + private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, + StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { + recipeName.append(command[nameStartIndex].toLowerCase().trim()); + for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { + recipeName.append(" ").append(command[j].toLowerCase().trim()); + } + recipeNames.add(recipeName.toString()); + recipeName = new StringBuilder(); + return recipeName; + } + + // parser to read dd/mm/yyyy format as local date catching invalid date format + public LocalDate parseDate(String input) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + try { + return LocalDate.parse(input, formatter); + } catch (DateTimeParseException e) { + throw new IllegalArgumentException( + "Please enter a valid date in the format dd/mm/yyyy"); + } } - } } diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 389755f55a..8fd5a46c0d 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -4,41 +4,41 @@ public class Recipe { - // changed ingredients to public to edit via editRecipe - private static IngredientList ingredientList = new IngredientList(); - public HashMap ingredients; - private String name; - private Boolean available; - - - public Recipe(String name, HashMap ingredients) { - this.name = name; - this.ingredients = ingredients; - } - - public String getName() { - return name; - } - - public HashMap getIngredients() { - return ingredients; - } - - public int getNumOfIngredients() { - return ingredients.size(); - } - - public boolean isAvailable() { - for (String ingredientName : ingredients.keySet()) { - if (ingredientList.containsKey(ingredientName)) { - Ingredient ingredient = ingredientList.get(ingredientName); - if (ingredient.ingredientCount < ingredients.get(ingredientName)) { - return false; + // changed ingredients to public to edit via editRecipe + private static IngredientList ingredientList = new IngredientList(); + public HashMap ingredients; + private String name; + private Boolean available; + + + public Recipe(String name, HashMap ingredients) { + this.name = name; + this.ingredients = ingredients; + } + + public String getName() { + return name; + } + + public HashMap getIngredients() { + return ingredients; + } + + public int getNumOfIngredients() { + return ingredients.size(); + } + + public boolean isAvailable() { + for (String ingredientName : ingredients.keySet()) { + if (ingredientList.containsKey(ingredientName)) { + Ingredient ingredient = ingredientList.get(ingredientName); + if (ingredient.ingredientCount < ingredients.get(ingredientName)) { + return false; + } + } else { + return false; + } } - } else { - return false; - } + return true; } - return true; - } } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 2fa7cee1cb..bb89078d37 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -6,137 +6,139 @@ public class RecipeList extends ArrayList { - private static IngredientList ingredientList = new IngredientList(); - public HashMap> tags = new HashMap<>(); - - public Recipe findByName(String name) { - for (Recipe recipe : this) { - if (recipe.getName().equalsIgnoreCase(name)) { - return recipe; - } - } - return null; - } - - public void addRecipe(Recipe recipe) { - super.add(recipe); - } - - public void editRecipe(Recipe recipe, HashMap ingredients) { - recipe.ingredients = ingredients; - } - - public Recipe deleteRecipe(int recipeNum) { - Recipe recipeToDelete = super.get(recipeNum); - super.remove(recipeToDelete); - return recipeToDelete; - } - - public void addRecipeToTag(String tag, Recipe recipe) { - boolean hasTag = tags.containsKey(tag); - int tagDummy = 0; - if (hasTag) { - tags.get(tag).put(recipe, tagDummy); - } else { - assert !tags.containsKey(tag); - HashMap tagRecipes = new HashMap<>(); - tagRecipes.put(recipe, tagDummy); - tags.put(tag, tagRecipes); - assert tags.size() > 0 : "tag's size is still 0."; + private static IngredientList ingredientList = new IngredientList(); + public HashMap> tags = new HashMap<>(); + + public Recipe findByName(String name) { + for (Recipe recipe : this) { + if (recipe.getName().equalsIgnoreCase(name)) { + return recipe; + } + } + return null; } - } - - public void removeRecipeFromTag(String tag, Recipe recipe) { - HashMap tagRecipeList = tags.get(tag); - boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); - if (!isAbleToFindTheRecipe) { - String errorMessage1 = "Unable to find the recipe: \"" + recipe.getName() + "\" in the" + - " tag."; - String errorMessage2 = "All the recipe before \"" + recipe.getName() + "\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + + public void addRecipe(Recipe recipe) { + super.add(recipe); } - tagRecipeList.remove(recipe); - } - public RecipeList listRecipes(String[] filters, boolean isTag) { - RecipeList filteredRecipeList = new RecipeList(); - boolean isNoFilter = filters == null; - boolean isNotPassTheFilter; + public void editRecipe(Recipe recipe, HashMap ingredients) { + recipe.ingredients = ingredients; + } - if (isTag) { - filteredRecipeList = this.listTagRecipes(filters); + public Recipe deleteRecipe(int recipeNum) { + Recipe recipeToDelete = super.get(recipeNum); + super.remove(recipeToDelete); + return recipeToDelete; } - if (!isTag && isNoFilter) { - return this; + + public void addRecipeToTag(String tag, Recipe recipe) { + boolean hasTag = tags.containsKey(tag); + int tagDummy = 0; + if (hasTag) { + tags.get(tag).put(recipe, tagDummy); + } else { + assert !tags.containsKey(tag); + HashMap tagRecipes = new HashMap<>(); + tagRecipes.put(recipe, tagDummy); + tags.put(tag, tagRecipes); + assert tags.size() > 0 : "tag's size is still 0."; + } } - if (!isTag) { - for (Recipe recipe : this) { - filteredRecipeList.add(recipe); - for (String filter : filters) { - filter = filter.trim(); - isNotPassTheFilter = !recipe.getName().contains(filter) && - !recipe.getIngredients().containsKey(filter); - if (isNotPassTheFilter) { - filteredRecipeList.remove(recipe); - } + + public void removeRecipeFromTag(String tag, Recipe recipe) { + HashMap tagRecipeList = tags.get(tag); + boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); + if (!isAbleToFindTheRecipe) { + String errorMessage1 = + "Unable to find the recipe: \"" + recipe.getName() + "\" in the" + + " tag."; + String errorMessage2 = + "All the recipe before \"" + recipe.getName() + "\" (if any) are " + + "successfully removed from the tag."; + throw new IndexOutOfBoundsException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } - } + tagRecipeList.remove(recipe); } - return filteredRecipeList; - } - - public RecipeList listTagRecipes(String[] filters) { - RecipeList filteredRecipeList = new RecipeList(); - HashMap tagRecipes; - boolean hasNoRecipeInTheTag; - boolean hasNoRecipeToReturn; - boolean isNotFoundTag; - - // add all recipe from first tag to the list - isNotFoundTag = !this.tags.containsKey(filters[0].trim()); - if (isNotFoundTag) { - throw new NullPointerException( - "There is no \"" + filters[0] + "\" tag found. Please make sure you have " + - "entered the correct tag."); + + public RecipeList listRecipes(String[] filters, boolean isTag) { + RecipeList filteredRecipeList = new RecipeList(); + boolean isNoFilter = filters == null; + boolean isNotPassTheFilter; + + if (isTag) { + filteredRecipeList = this.listTagRecipes(filters); + } + if (!isTag && isNoFilter) { + return this; + } + if (!isTag) { + for (Recipe recipe : this) { + filteredRecipeList.add(recipe); + for (String filter : filters) { + filter = filter.trim(); + isNotPassTheFilter = !recipe.getName().contains(filter) && + !recipe.getIngredients().containsKey(filter); + if (isNotPassTheFilter) { + filteredRecipeList.remove(recipe); + } + } + } + } + return filteredRecipeList; } - this.tags.get(filters[0].trim()).forEach((recipe, dummy) -> filteredRecipeList.add(recipe)); - - for (String filter : filters) { - filter = filter.trim(); - tagRecipes = this.tags.get(filter); - hasNoRecipeInTheTag = tagRecipes == null; - hasNoRecipeToReturn = filteredRecipeList.size() == 0; - - if (hasNoRecipeInTheTag) { - throw new NullPointerException("There is nothing to list."); - } - if (hasNoRecipeToReturn) { + + public RecipeList listTagRecipes(String[] filters) { + RecipeList filteredRecipeList = new RecipeList(); + HashMap tagRecipes; + boolean hasNoRecipeInTheTag; + boolean hasNoRecipeToReturn; + boolean isNotFoundTag; + + // add all recipe from first tag to the list + isNotFoundTag = !this.tags.containsKey(filters[0].trim()); + if (isNotFoundTag) { + throw new NullPointerException( + "There is no \"" + filters[0] + "\" tag found. Please make sure you have " + + "entered the correct tag."); + } + this.tags.get(filters[0].trim()).forEach((recipe, dummy) -> filteredRecipeList.add(recipe)); + + for (String filter : filters) { + filter = filter.trim(); + tagRecipes = this.tags.get(filter); + hasNoRecipeInTheTag = tagRecipes == null; + hasNoRecipeToReturn = filteredRecipeList.size() == 0; + + if (hasNoRecipeInTheTag) { + throw new NullPointerException("There is nothing to list."); + } + if (hasNoRecipeToReturn) { + return filteredRecipeList; + } + for (Recipe recipe : filteredRecipeList) { + if (!tagRecipes.containsKey(recipe)) { + filteredRecipeList.remove(recipe); + } + } + } return filteredRecipeList; - } - for (Recipe recipe : filteredRecipeList) { - if (!tagRecipes.containsKey(recipe)) { - filteredRecipeList.remove(recipe); + } + + public RecipeList availableRecipes() { + RecipeList availableRecipeList = new RecipeList(); + for (Recipe recipe : this) { + if (recipe.isAvailable()) { + availableRecipeList.add(recipe); + } } - } + return availableRecipeList; } - return filteredRecipeList; - } - - public RecipeList availableRecipes() { - RecipeList availableRecipeList = new RecipeList(); - for (Recipe recipe : this) { - if (recipe.isAvailable()) { - availableRecipeList.add(recipe); - } + + public Recipe randomRecipe() { + Random random = new Random(); + Recipe randomRecipe = this.get(random.nextInt(this.size())); + return randomRecipe; } - return availableRecipeList; - } - - public Recipe randomRecipe() { - Random random = new Random(); - Recipe randomRecipe = this.get(random.nextInt(this.size())); - return randomRecipe; - } } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index f230589f1e..340172e44f 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -2,107 +2,108 @@ public class Ui { - private static final int BOXWIDTH = 100; - private static final String SEPARATORCHAR = "-"; - - public void printSeparator() { - String separatorLine = SEPARATORCHAR.repeat(BOXWIDTH); - System.out.println(separatorLine); - } - - public void printWelcomeMessage() { - String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" - + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; - System.out.println("Welcome to Meal360, your ultimate Recipe Manager!\n" + logo); - } - - public void printGoodbyeMessage() { - System.out.println(formatMessage("Bye. Hope to see you again soon!")); - } - - public String formatMessage(String message) { - return String.format("| %-97s|", message); - } - - public void printMessage(String message) { - String outputMessage = formatMessage(message); - System.out.println(outputMessage); - } - - public void printRecipe(Recipe recipe) { - System.out.println(formatMessage("Name of recipe: " + recipe.getName())); - int index = 1; - for (String ingredient : recipe.getIngredients().keySet()) { - String outputMessage = String.format("%s(%d)", ingredient, - recipe.getIngredients().get(ingredient)); - System.out.println(formatMessage(index + ". " + outputMessage)); - index++; + private static final int BOXWIDTH = 100; + private static final String SEPARATORCHAR = "-"; + + public void printSeparator() { + String separatorLine = SEPARATORCHAR.repeat(BOXWIDTH); + System.out.println(separatorLine); + } + + public void printWelcomeMessage() { + String logo = " __ __ _ ____ __ __\n" + "| \\/ |___ __ _| |__ / / / / \\\n" + + "| |\\/| / -_) _` | ||_ \\/ _ \\ () |\n" + "|_| |_\\___\\__,_|_|___/\\___/\\__/\n"; + System.out.println("Welcome to Meal360, your ultimate Recipe Manager!\n" + logo); + } + + public void printGoodbyeMessage() { + System.out.println(formatMessage("Bye. Hope to see you again soon!")); } - } - - public void printWeeklyPlan(WeeklyPlan weeklyPlan) { - if (weeklyPlan.isEmpty()) { - printMessage("Your weekly plan is empty!"); - } else { - printMessage("Here is your weekly plan:"); - weeklyPlan.forEach((recipe, count) -> { - String outputMessage = String.format("%s x%d", recipe, count); - printMessage(outputMessage); - }); + + public String formatMessage(String message) { + return String.format("| %-97s|", message); + } + + public void printMessage(String message) { + String outputMessage = formatMessage(message); + System.out.println(outputMessage); + } + + public void printRecipe(Recipe recipe) { + System.out.println(formatMessage("Name of recipe: " + recipe.getName())); + int index = 1; + for (String ingredient : recipe.getIngredients().keySet()) { + String outputMessage = String.format("%s(%d)", ingredient, + recipe.getIngredients().get(ingredient)); + System.out.println(formatMessage(index + ". " + outputMessage)); + index++; + } } - } - - public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) { - if (weeklyPlan.isEmpty()) { - printMessage("Your weekly plan is empty!"); - } else { - printMessage("Here are your weekly ingredients:"); - weeklyPlan.forEach((recipe, count) -> { - Recipe currRecipe = recipeList.findByName(recipe.toString().trim()); - for (String ingredient : currRecipe.getIngredients().keySet()) { - String outputMessage = String.format("%s (%d)", ingredient, - currRecipe.getIngredients().get(ingredient) * count); - System.out.println(formatMessage(outputMessage)); + public void printWeeklyPlan(WeeklyPlan weeklyPlan) { + if (weeklyPlan.isEmpty()) { + printMessage("Your weekly plan is empty!"); + } else { + printMessage("Here is your weekly plan:"); + weeklyPlan.forEach((recipe, count) -> { + String outputMessage = String.format("%s x%d", recipe, count); + printMessage(outputMessage); + }); } - }); + } - } + public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) { + if (weeklyPlan.isEmpty()) { + printMessage("Your weekly plan is empty!"); + } else { + printMessage("Here are your weekly ingredients:"); + weeklyPlan.forEach((recipe, count) -> { + Recipe currRecipe = recipeList.findByName(recipe.toString().trim()); + for (String ingredient : currRecipe.getIngredients().keySet()) { + String outputMessage = String.format("%s (%d)", ingredient, + currRecipe.getIngredients().get(ingredient) * count); + System.out.println(formatMessage(outputMessage)); + } + }); + } + + } - public void listRecipe(RecipeList recipeListToPrint) { - listRecipes(recipeListToPrint, "There is nothing to list.", "These are the recipes you have"); - } + public void listRecipe(RecipeList recipeListToPrint) { + listRecipes(recipeListToPrint, "There is nothing to list.", + "These are the recipes you have"); + } - public void listAvailableRecipes(RecipeList recipeListToPrint) { - listRecipes(recipeListToPrint, "There are no available recipes.", - "These are the recipes you can cook"); - } + public void listAvailableRecipes(RecipeList recipeListToPrint) { + listRecipes(recipeListToPrint, "There are no available recipes.", + "These are the recipes you can cook"); + } - private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, - String listHeaderMsg) { - int numberOfRecipes = recipeListToPrint.size(); - int order = 0; - if (numberOfRecipes == 0) { - printMessage(emptyListMsg); - return; + private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, + String listHeaderMsg) { + int numberOfRecipes = recipeListToPrint.size(); + int order = 0; + if (numberOfRecipes == 0) { + printMessage(emptyListMsg); + return; + } + printMessage(listHeaderMsg + " (" + numberOfRecipes + " recipes):"); + for (Recipe recipe : recipeListToPrint) { + order++; + printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() + + " ingredients)"); + } } - printMessage(listHeaderMsg + " (" + numberOfRecipes + " recipes):"); - for (Recipe recipe : recipeListToPrint) { - order++; - printMessage(order + ". " + recipe.getName() + " (" + recipe.getNumOfIngredients() - + " ingredients)"); + + public void printHelp() { + printMessage("These are the operations you can do. Please follow the proper input" + + " formats while typing."); + printMessage("1. Add Recipe: add /r {recipe name}"); + printMessage("2. View Recipe: view {index number} or view /r {recipe name}"); + printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); + printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); + printMessage("5. List All Recipes: list"); + printMessage("6. Exit: bye"); } - } - - public void printHelp() { - printMessage("These are the operations you can do. Please follow the proper input" - + " formats while typing."); - printMessage("1. Add Recipe: add /r {recipe name}"); - printMessage("2. View Recipe: view {index number} or view /r {recipe name}"); - printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); - printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); - printMessage("5. List All Recipes: list"); - printMessage("6. Exit: bye"); - } } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index cb773aa97a..41e781a1b9 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -4,28 +4,28 @@ public class WeeklyPlan extends HashMap { - public void addPlans(WeeklyPlan recipeMap) { - recipeMap.forEach((recipe, count) -> { - if (this.containsKey(recipe)) { - this.put(recipe, this.get(recipe) + count); - } else { - this.put(recipe, count); - } - }); - } + public void addPlans(WeeklyPlan recipeMap) { + recipeMap.forEach((recipe, count) -> { + if (this.containsKey(recipe)) { + this.put(recipe, this.get(recipe) + count); + } else { + this.put(recipe, count); + } + }); + } - public void deletePlans(WeeklyPlan recipeMap) { - recipeMap.forEach((recipe, count) -> { - if (this.containsKey(recipe)) { - this.remove(recipe); - } else { - throw new IllegalArgumentException("Recipe does not exist in weekly plan!"); - } - }); - } + public void deletePlans(WeeklyPlan recipeMap) { + recipeMap.forEach((recipe, count) -> { + if (this.containsKey(recipe)) { + this.remove(recipe); + } else { + throw new IllegalArgumentException("Recipe does not exist in weekly plan!"); + } + }); + } - public void clearPlan() { - this.clear(); - } + public void clearPlan() { + this.clear(); + } } From 1d6064bb1e8f25a6383a59cab192a1a1212abb57 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Thu, 30 Mar 2023 23:55:23 +0800 Subject: [PATCH 142/252] fix spacing error with delete command --- docs/UserGuide.md | 6 +++--- src/main/java/seedu/meal360/Parser.java | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 8dc0764668..79fb4efeac 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -96,7 +96,7 @@ Example of usage: Deletes one, a range, or all recipes currently in list. -Format: `delete INDEX/RANGE` or `delete r/ NAME` +Format: `delete INDEX/RANGE` or `delete /r NAME` * Deletes the recipe(s) specified by the user either through the recipe index or name. * The index refers to the index number shown in the displayed person list. @@ -106,8 +106,8 @@ Example of usage: `delete 1` `delete 1-3` -`delete r/ pizza` -`delete r/ all` +`delete /r pizza` +`delete /r all` ### Tagging/Categorising recipes: `tag` diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 168c6f6800..8721315f23 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -175,13 +175,14 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { public String parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name - if (input[1].contains("r/")) { + if (input[1].contains("/r")) { // skip over /r in recipe name String recipeToDelete = ""; for (int i = 2; i < input.length; i++) { recipeToDelete += input[i] + " "; } recipeToDelete = recipeToDelete.trim(); + System.out.println("recipeToDelete: " + recipeToDelete); if (recipeToDelete.equals("all")) { String allRecipes = ""; int index = 0; From 2426662fd1441f8d3345aca886a41a2ac0c15f3a Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 31 Mar 2023 00:07:44 +0800 Subject: [PATCH 143/252] Edited the help commands. Updated user guide. --- docs/UserGuide.md | 17 +++++++++++++++-- src/main/java/seedu/meal360/Ui.java | 28 ++++++++++++++++++---------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index f67671b65c..c5d66b93ef 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -27,6 +27,17 @@ ___ * [View weekly plan](#view-this-weeks-plan--weeklyplan) * [Random a recipe](#random-a-recipe--random) + +### HOW TO ADD INGREDIENTS TO A RECIPE: + +* Please follow the below-mentioned format. + +Format: `ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ...` + +* Examples: `chicken=100 oil and sauce=200 vegetables=300` + `meat=200 salt and spices=400` +* Type the ingredient name followed by equal sign and quantity in positive integer values. + ### Adding recipes: `add` Add new recipes to your list. @@ -43,12 +54,14 @@ Example of usage: ### Editing recipes: `edit` -Edit recipes in your list either partially or fully. +Edit recipes in your list partially, fully or add new ingredients to already existing recipe. Format: `edit /r [recipe_name]` * `recipe_name` is basically a string. * Type the recipe name after typing `/r `. +* If you want to edit fully: press 1, edit partially: press 2, or add new ingredients: press 3. +* Follow the proper format while editing/adding ingredients. Example of usage: @@ -129,7 +142,7 @@ Example of usage: * `tag breakfast << milk && boiled egg && bread` adds milk, boiled egg and bread into 'breakfast' tag. -__Removing recipes form a tag__ +__Removing recipes from a tag__ Remove recipes from a specific tag. diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 26fd26488a..350e0ce29d 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -91,18 +91,26 @@ public void printHelp() { printMessage("These are the operations you can do. Please follow the proper input" + " formats while typing."); printMessage("1. Add Recipe: add /r {recipe name}"); - printMessage("2. View Recipe: view {index number} or view /r {recipe name}"); - printMessage("3. Edit Recipe: edit {index number} or view /r {recipe name}"); - printMessage("4. Delete Recipe: delete {index number} or view /r {recipe name}"); + printMessage("2. View Recipe: view {index number}"); + printMessage("3. Edit Recipe: edit {recipe name}"); + printMessage("4. Delete Recipe: delete {index number} or delete {index range} or"); + printMessage("delete /r {recipe name}or delete /r all"); printMessage("5. List All Recipes: list"); - printMessage("6. Add Single Recipe to Weekly Plan: add {recipe name} {quantity}"); - printMessage("7. Add Multiple Recipes to Weekly Plan: add /r {recipe name} /q {quantity}"); - printMessage(" /r {recipe name} /q {quantity} ..."); - printMessage("8. Delete Single Recipe from Weekly Plan: delete {recipe name} {quantity}"); - printMessage("9. Delete Multiple Recipes from Weekly Plan: delete /r {recipe name} /q"); - printMessage(" {quantity} /r {recipe name} /q {quantity} ..."); + printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); + printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); + printMessage("/r {recipe2 name} /q {quantity2}"); + printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); + printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name} /q {quantity1}"); + printMessage("/r {recipe2 name} /q {quantity2}"); printMessage("10. View Weekly Plan: weeklyplan"); - printMessage("11. Exit: bye"); + printMessage("11. Clearing weekly plan: weekly /clear"); + printMessage("12. View Weekly Ingredients: weeklyingredients"); + printMessage("13. Give a random recipe: random"); + printMessage("14. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && ...}"); + printMessage("15. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ...}"); + printMessage("16. Exit: bye"); + printMessage("HOW TO ADD INGREDIENTS?"); + printMessage("ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ..."); } public void printUserIngredients(IngredientList userIngredients) { From e0dab7bd6e70e0f0132015526c4e49c8c3af3d66 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 31 Mar 2023 00:14:00 +0800 Subject: [PATCH 144/252] . --- src/main/java/seedu/meal360/Ui.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 350e0ce29d..080b955bd1 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -100,8 +100,8 @@ public void printHelp() { printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); printMessage("/r {recipe2 name} /q {quantity2}"); printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); - printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name} /q {quantity1}"); - printMessage("/r {recipe2 name} /q {quantity2}"); + printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); + printMessage("/q {quantity1} /r {recipe2 name} /q {quantity2}"); printMessage("10. View Weekly Plan: weeklyplan"); printMessage("11. Clearing weekly plan: weekly /clear"); printMessage("12. View Weekly Ingredients: weeklyingredients"); From 6006182973d4d8fcd413d2f5994934ec85d8ea9d Mon Sep 17 00:00:00 2001 From: notbingsu Date: Fri, 31 Mar 2023 00:29:42 +0800 Subject: [PATCH 145/252] no message --- src/main/java/seedu/meal360/Meal360.java | 15 +++--- src/main/java/seedu/meal360/Parser.java | 68 ++++++++++++------------ src/main/java/seedu/meal360/Ui.java | 2 +- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 449b3ef176..61b512e2a2 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -76,9 +76,9 @@ public static void receiveInput(String input) { ui.printMessage(deletedRecipe); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = - "Please enter a valid recipe number or name. You did not enter a recipe number or " - + "name."; + String errorMessage = "Please enter a valid recipe number or name. You did not enter a recipe number " + + "or " + + "name."; ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( @@ -102,8 +102,7 @@ public static void receiveInput(String input) { ui.printSeparator(); RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); ui.listRecipe(recipeListToPrint); - } catch (IllegalArgumentException | IndexOutOfBoundsException | - NullPointerException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -152,8 +151,7 @@ public static void receiveInput(String input) { ui.printSeparator(); String tag = parser.parseTagRecipe(command, recipeList); ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); - } catch (IllegalArgumentException | IndexOutOfBoundsException | - NullPointerException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -190,8 +188,7 @@ public static void receiveInput(String input) { ui.printMessage("Please enter a valid command."); break; } - } catch (IllegalArgumentException | InvalidNegativeValueException | - InvalidRecipeNameException + } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException | ArrayIndexOutOfBoundsException e) { ui.printMessage(e.getMessage()); } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index d6ae2bdb2f..7a3de495d7 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -411,18 +411,18 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) WeeklyPlan updatedWeeklyPlan; try { switch (command[1]) { - case "/add": - case "/delete": - updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); - break; - case "/multiadd": - case "/multidelete": - updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); - break; - default: - throw new IllegalArgumentException( - "Please indicate if you would want to add or delete the recipe from your weekly " - + "plan."); + case "/add": + case "/delete": + updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + case "/multidelete": + updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); + break; + default: + throw new IllegalArgumentException( + "Please indicate if you would want to add or delete the recipe from your weekly " + + "plan."); } return updatedWeeklyPlan; @@ -518,7 +518,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, - StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { + StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { recipeName.append(command[nameStartIndex].toLowerCase().trim()); for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { recipeName.append(" ").append(command[j].toLowerCase().trim()); @@ -547,18 +547,18 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL try { for (int i = 1; i < command.length; i++) { switch (command[i]) { - case "/n": - ingredientName = command[++i]; - break; - case "/c": - ingredientCount = Integer.parseInt(command[++i]); - break; - case "/d": - expiryDate = command[++i]; - break; - default: - throw new IllegalArgumentException("Missing required information. Please provide " - + "ingredient name, count, and expiry date."); + case "/n": + ingredientName = command[++i]; + break; + case "/c": + ingredientCount = Integer.parseInt(command[++i]); + break; + case "/d": + expiryDate = command[++i]; + break; + default: + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name, count, and expiry date."); } } } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { @@ -579,15 +579,15 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr try { for (int i = 1; i < command.length; i++) { switch (command[i]) { - case "/n": - ingredientName = command[++i]; - break; - case "/c": - ingredientCount = Integer.parseInt(command[++i]); - break; - default: - throw new IllegalArgumentException( - "Missing required information. Please provide " + "ingredient name and count."); + case "/n": + ingredientName = command[++i]; + break; + case "/c": + ingredientCount = Integer.parseInt(command[++i]); + break; + default: + throw new IllegalArgumentException( + "Missing required information. Please provide " + "ingredient name and count."); } } } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 64267eebc5..6deb7b8a94 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -83,7 +83,7 @@ public void listAvailableRecipes(RecipeList recipeListToPrint) { } private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, - String listHeaderMsg) { + String listHeaderMsg) { int numberOfRecipes = recipeListToPrint.size(); int order = 0; if (numberOfRecipes == 0) { From 4a6f6bf58e5536a65485d3bd49dd0d29e45423b0 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 31 Mar 2023 03:00:29 +0800 Subject: [PATCH 146/252] Add functionality improve user experience User can mark recipes in the weekly plan as done, and the amount of ingredients are automatically reduced --- database/userIngredientsDatabase.json | 2 +- docs/UserGuide.md | 47 ++++++++++-- src/main/java/seedu/meal360/Exceptions.java | 12 ---- src/main/java/seedu/meal360/Ingredient.java | 7 ++ .../java/seedu/meal360/IngredientList.java | 72 +++++++++---------- src/main/java/seedu/meal360/Meal360.java | 14 +++- src/main/java/seedu/meal360/Parser.java | 50 ++++++++++++- 7 files changed, 143 insertions(+), 61 deletions(-) delete mode 100644 src/main/java/seedu/meal360/Exceptions.java diff --git a/database/userIngredientsDatabase.json b/database/userIngredientsDatabase.json index 9e26dfeeb6..867ea63f4d 100644 --- a/database/userIngredientsDatabase.json +++ b/database/userIngredientsDatabase.json @@ -1 +1 @@ -{} \ No newline at end of file +{"Salt":{"ingredientName":"Salt","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false},"Pepper":{"ingredientName":"Pepper","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false},"Chicken":{"ingredientName":"Chicken","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false},"Rice":{"ingredientName":"Rice","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false}} \ No newline at end of file diff --git a/docs/UserGuide.md b/docs/UserGuide.md index f67671b65c..ef112ac1c6 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -11,7 +11,8 @@ ___ ## Quick Start 1. Ensure that you have Java 11 or above installed. -2. Down the latest version of `Duke` from [here](http://link.to/duke). +2. Down the latest version of `Meal360` + from [here](https://github.com/AY2223S2-CS2113-F10-3/tp/releases). ___ @@ -231,6 +232,12 @@ View this week's ingredients. Format: `weeklyingredients` +### View user total list of ingredients: `view_ingredients` + +View list of all ingredients that users have. + +Format: `view_ingredients` + ### Random a recipe: `random` Random a recipe from all the recipes that user have, and show the list of @@ -244,11 +251,38 @@ Exits the program. Format: `bye` -## FAQ +### Add user ingredient: `add_i` + +Add user's ingredients into the ingredient list. +Format : `add_i /n INGREDIENT_NAME /c QUANTITY /d DATE` + +* This function is **case sensitive**. +* The quantity **must be a positive + integer** 1,2,3, ... +* The date **must be in the format of DD/MM/YYYY** + +Example of usage: + +* `add_i /n chicken /c 1 /d 01/01/2020` adds chicken with quantity 1 and expiry date 01/01/2020 + +### Delete user ingredient: `del_i` + +Delete user's ingredients from the ingredient list. +Format : `del_i /n INGREDIENT_NAME /c QUANTITY` + +* This function is **case sensitive**. +* The quantity has to be **less than or equal** to the quantity of the ingredient in the list. +* The quantity **must be a positive + integer** 1,2,3, ... + +Example of usage: + +* `del_i /n chicken /c 1` deletes chicken with quantity 1 -**Q**: How do I transfer my data to another computer? +### View user ingredients: `view_ingredients` -**A**: {your answer here} +View user's ingredients from the ingredient list. +Format : `view_ingredients` ## Command Summary @@ -265,3 +299,8 @@ Format: `bye` | Delete from weekly plan | `weekly /delete RECIPE NAME`
e.g `weekly /delete pizza` | | Delete multiple from weekly plan | `weekly /multidelete [/r RECIPE NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 4` | | View weekly plan | `weeklyplan` | +| View weekly ingredients | `weeklyingredients` | +| View user ingredients | `view_ingredients` | +| Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Rice /c 100 /d 04/09/2023` | +| Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Rice /c 50` | +| Mark plan as completed | `weeklydone NAME`
e.g `weeklydone chicken rice` | diff --git a/src/main/java/seedu/meal360/Exceptions.java b/src/main/java/seedu/meal360/Exceptions.java deleted file mode 100644 index 2c96cbcd2d..0000000000 --- a/src/main/java/seedu/meal360/Exceptions.java +++ /dev/null @@ -1,12 +0,0 @@ -package seedu.meal360; - -public class Exceptions { - - // ingredient not found exception - public static class IngredientNotFoundException extends Exception { - public IngredientNotFoundException() { - super("Ingredient not found"); - } - } - -} diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java index cab254a5c1..48c51fe7e2 100644 --- a/src/main/java/seedu/meal360/Ingredient.java +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -17,6 +17,13 @@ public Ingredient(String ingredientName, Integer ingredientCount, String expiryD this.updateExpired(); } + public Ingredient(String ingredient, int newCount, LocalDate expiryDate) { + this.ingredientName = ingredient; + this.ingredientCount = newCount; + this.expiryDate = expiryDate; + this.updateExpired(); + } + public void updateExpired() { if (expiryDate.isBefore(LocalDate.now())) { expired = true; diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index f635881298..afb31ca96c 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -2,66 +2,58 @@ import java.util.HashMap; import java.time.LocalDate; +import seedu.meal360.exceptions.IngredientNotFoundException; public class IngredientList extends HashMap { + private static final Parser parser = new Parser(); // public method to find count of ingredient - public Integer findIngredientCount(String ingredientName) { - try { - if (this.containsKey(ingredientName)) { - return this.get(ingredientName).ingredientCount; - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - return null; + public Integer findIngredientCount(String ingredientName) throws IngredientNotFoundException { + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).ingredientCount; } + throw new IngredientNotFoundException("Ingredient not found"); } // public method to find expiry date of ingredient - public LocalDate findExpiryDate(String ingredientName) { - try { - if (this.containsKey(ingredientName)) { - return this.get(ingredientName).expiryDate; - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - return null; + public LocalDate findExpiryDate(String ingredientName) throws IngredientNotFoundException { + if (this.containsKey(ingredientName)) { + return this.get(ingredientName).expiryDate; } + throw new IngredientNotFoundException("Ingredient not found"); } public void addIngredient(Ingredient ingredient) { super.put(ingredient.ingredientName, ingredient); } - public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) { - try { - if (this.containsKey(ingredient.ingredientName)) { - ingredient.ingredientCount = ingredientCount; - ingredient.expiryDate = parser.parseDate(expiryDate); - ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); - super.put(ingredient.ingredientName, ingredient); - } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - System.out.println("Ingredient not found"); + public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) + throws IngredientNotFoundException { + if (this.containsKey(ingredient.ingredientName)) { + ingredient.ingredientCount = ingredientCount; + ingredient.expiryDate = parser.parseDate(expiryDate); + ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); + super.put(ingredient.ingredientName, ingredient); } + throw new IngredientNotFoundException("Ingredient not found"); } - public void deleteIngredient(String ingredient, Integer ingredientCount) { - try { - if (this.containsKey(ingredient)) { - int currentCount = this.get(ingredient).ingredientCount; - int newCount = currentCount - ingredientCount; - if (newCount > 0) { - this.get(ingredient).ingredientCount = newCount; - } else { - this.remove(ingredient); - } + public void deleteIngredient(String ingredient, Integer ingredientCount) + throws IngredientNotFoundException { + if (this.containsKey(ingredient)) { + int currentCount = this.get(ingredient).ingredientCount; + int newCount = currentCount - ingredientCount; + if (newCount > 0) { + this.put(ingredient, new Ingredient(ingredient, newCount, this.get(ingredient).expiryDate)); + } else if (newCount == 0) { + this.remove(ingredient); + } else { + throw new IllegalArgumentException( + "Number of ingredients to delete exceeds the number " + "of ingredients available!"); } - throw new Exceptions.IngredientNotFoundException(); - } catch (Exceptions.IngredientNotFoundException e) { - System.out.println("Ingredient not found"); + } else { + throw new IngredientNotFoundException("Ingredient not found"); } } diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 1a7d784c45..0fb57081b6 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.util.Scanner; +import seedu.meal360.exceptions.IngredientNotFoundException; import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; import seedu.meal360.storage.Database; @@ -189,6 +190,17 @@ public static void receiveInput(String input) { ui.printMessage(e.getMessage()); } ui.printSeparator(); + } else if (command[0].equals("weeklydone")) { + ui.printSeparator(); + try { + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipeList); + ui.printMessage("I've recorded that you've done this recipe!"); + ui.printMessage("Ingredients list has been updated accordingly!"); + } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException | + IngredientNotFoundException e) { + ui.printMessage(e.getMessage()); + } + ui.printSeparator(); } else if (command[0].equals("weeklyingredients")) { ui.printSeparator(); ui.printWeeklyIngredients(weeklyPlan, recipeList); @@ -211,7 +223,7 @@ public static void receiveInput(String input) { try { parser.parseDeleteUserIngredients(command, userIngredients); ui.printMessage("Ingredients successfully deleted!"); - } catch (IllegalArgumentException | IndexOutOfBoundsException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | IngredientNotFoundException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index ddc52ec87f..0bc28addda 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; +import seedu.meal360.exceptions.IngredientNotFoundException; import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; import java.time.format.DateTimeFormatter; @@ -14,9 +15,9 @@ public class Parser { Ui ui = new Ui(); public String combineWords(String[] input, int startIndex, int length) { - StringBuilder word = new StringBuilder(input[startIndex]); + StringBuilder word = new StringBuilder(input[startIndex].trim()); for (int i = startIndex + 1; i < length; i++) { - word.append(" ").append(input[i]); + word.append(" ").append(input[i].trim()); } return word.toString(); @@ -540,6 +541,10 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL break; case "/c": ingredientCount = Integer.parseInt(command[++i]); + if (ingredientCount < 0) { + throw new IllegalArgumentException( + "Please enter a positive number for the quantity."); + } break; case "/d": expiryDate = command[++i]; @@ -560,7 +565,8 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL ingredientList.addIngredient(new Ingredient(ingredientName, ingredientCount, expiryDate)); } - public void parseDeleteUserIngredients(String[] command, IngredientList userIngredients) { + public void parseDeleteUserIngredients(String[] command, IngredientList userIngredients) + throws IngredientNotFoundException { String ingredientName = null; Integer ingredientCount = null; @@ -572,6 +578,10 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr break; case "/c": ingredientCount = Integer.parseInt(command[++i]); + if (ingredientCount < 0) { + throw new IllegalArgumentException( + "Please enter a positive number for the quantity."); + } break; default: throw new IllegalArgumentException( @@ -588,4 +598,38 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr userIngredients.deleteIngredient(ingredientName, ingredientCount); } + + public void parseMarkDone(String[] command, IngredientList userIngredients, WeeklyPlan weeklyPlan, + RecipeList recipes) throws IngredientNotFoundException { + if (command.length == 1) { + throw new IllegalArgumentException("Please enter a recipe name."); + } + String recipeName = combineWords(command, 1, command.length); + if (recipes.findByName(recipeName) == null) { + throw new IllegalArgumentException("Please enter a valid recipe name."); + } + + if (weeklyPlan.get(recipeName) == null) { + throw new IllegalArgumentException("Recipe does not exist in weekly plan."); + } + + HashMap ingredients = recipes.findByName(recipeName).getIngredients(); + try { + for (String ingredient : ingredients.keySet()) { + int currentCount = userIngredients.findIngredientCount(ingredient); + if (currentCount < ingredients.get(ingredient)) { + throw new IllegalArgumentException( + "You do not have enough ingredients to mark this recipe as done."); + } + } + } catch (IngredientNotFoundException e) { + throw new IllegalArgumentException( + "You do not have enough ingredients to mark this recipe as done."); + } + + // If all ingredients are present, mark recipe as done + for (String ingredient : ingredients.keySet()) { + userIngredients.deleteIngredient(ingredient, ingredients.get(ingredient)); + } + } } From 668d2724ebe9512a580229999e16c5135dd63998 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 31 Mar 2023 10:40:34 +0800 Subject: [PATCH 147/252] fix formatting of returned string from parseDeleteRecipe --- src/main/java/seedu/meal360/Parser.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 8721315f23..6b03e399d4 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -182,7 +182,6 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { recipeToDelete += input[i] + " "; } recipeToDelete = recipeToDelete.trim(); - System.out.println("recipeToDelete: " + recipeToDelete); if (recipeToDelete.equals("all")) { String allRecipes = ""; int index = 0; @@ -215,8 +214,8 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { while (recipeList.size() != newSize) { rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; } - rangeRecipes = rangeRecipes.substring(0, rangeRecipes.length() - 2); - return rangeRecipes; + rangeRecipes = String.valueOf(new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2))); + return rangeRecipes.toString(); } else { int recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based From c9418c24213e3ba74af615c888ab01ea96b56609 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sat, 1 Apr 2023 19:45:05 +0800 Subject: [PATCH 148/252] Update parsing of user input Allow all commands to be case insensitive instead. Edit parsing of `weekly /clear` command to ensure it gets executed. * Closes #114 * Closes #98 --- .gitignore | 1 + database/recipesDatabase.json | 1 - database/userIngredientsDatabase.json | 1 - database/weeklyPlanDatabase.json | 1 - src/main/java/seedu/meal360/Meal360.java | 1 + src/main/java/seedu/meal360/Parser.java | 59 +++--- src/main/java/seedu/meal360/Ui.java | 6 +- .../java/seedu/meal360/storage/Database.java | 174 +++++++++--------- 8 files changed, 119 insertions(+), 125 deletions(-) delete mode 100644 database/recipesDatabase.json delete mode 100644 database/userIngredientsDatabase.json delete mode 100644 database/weeklyPlanDatabase.json diff --git a/.gitignore b/.gitignore index 54416cba09..8077059475 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ *.iml bin/ +/database/ /text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT diff --git a/database/recipesDatabase.json b/database/recipesDatabase.json deleted file mode 100644 index 0beacc58a3..0000000000 --- a/database/recipesDatabase.json +++ /dev/null @@ -1 +0,0 @@ -[{"ingredients":{"Salt":1,"Pepper":1,"Chicken":1,"Rice":1},"name":"Chicken Rice"},{"ingredients":{"Plain flour":2,"Breadcrumbs":100,"Vegetable oil":2,"Ripe mixed-colour cherry tomatoes ":250,"Flat-leaf parsley":15,"Garlic cloves":2,"Feta cheese":30,"Eggs":2},"name":"Tomato fritters"},{"ingredients":{"Puff pastry":1,"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Milk":2},"name":"Chicken and mushroom pie"},{"ingredients":{"Prawns":500,"Mussels":500,"Onion":1,"Chicken stock":1,"Cherry tomatoes":250,"Vegetable oil":2,"Saffron":1,"Chorizo":100,"Garlic cloves":2,"Rice":1},"name":"Seafood paella"},{"ingredients":{"Salt":1,"Pepper":1,"Avocado":1,"Lemon":1,"Bread":2},"name":"Avocado toast"},{"ingredients":{"Dried rosemary":1,"Carrot":1,"Onion":1,"Dried parsley":1,"Chicken stock":1,"Dried basil":1,"Garlic cloves":2,"Dried thyme":1,"Parmesan cheese":1,"Celery":1,"Dried oregano":1,"Italian sausage":1,"Orzo":1},"name":"Italian sausage orzo soup"},{"ingredients":{"Mushrooms":250,"Onion":1,"Plain flour":2,"Butter":2,"Chicken breast fillets":2,"Pasta":1,"Garlic cloves":2,"Milk":2},"name":"Chicken and mushroom pasta"},{"ingredients":{"Salt":1,"Pepper":1,"Pasta":1,"Hummus":1,"Garlic cloves":2,"Lemon":1},"name":"Creamy Hummus Pasta"},{"ingredients":{"Cheddar cheese":1,"Potato":1,"Tomato sauce":1,"Onion":1,"Ground beef":1,"Tomato paste":1,"Garlic cloves":2,"Beef stock":1},"name":"Ground beef and potato casserole"},{"ingredients":{"Cheddar cheese":1,"Blue cheese":1,"Hot sauce":1,"Butter":2,"Chicken breast fillets":2,"Macaroni":1,"Flour":2,"Milk":2},"name":"Buffalo Chicken Mac \u0027n\u0027 Cheese"}] \ No newline at end of file diff --git a/database/userIngredientsDatabase.json b/database/userIngredientsDatabase.json deleted file mode 100644 index 867ea63f4d..0000000000 --- a/database/userIngredientsDatabase.json +++ /dev/null @@ -1 +0,0 @@ -{"Salt":{"ingredientName":"Salt","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false},"Pepper":{"ingredientName":"Pepper","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false},"Chicken":{"ingredientName":"Chicken","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false},"Rice":{"ingredientName":"Rice","ingredientCount":4,"expiryDate":{"year":2023,"month":4,"day":9},"expired":false}} \ No newline at end of file diff --git a/database/weeklyPlanDatabase.json b/database/weeklyPlanDatabase.json deleted file mode 100644 index 5d909f1bf2..0000000000 --- a/database/weeklyPlanDatabase.json +++ /dev/null @@ -1 +0,0 @@ -{"chicken rice":2447,"avocado toast":50} \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 5975387eb1..815ab74247 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -64,6 +64,7 @@ public static void startApp() { public static void receiveInput(String input) { input = input.replaceAll("\\s+", " "); + input = input.toLowerCase(); String[] command = input.trim().split(" "); if (input.equalsIgnoreCase("bye")) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 4f83cc7397..501ca604e0 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -102,8 +102,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } recipeToEdit = recipeList.findByName(recipeName); System.out.println("Do you want to edit recipe fully or partially?"); - System.out.println( - "Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); + System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); Scanner getInput = new Scanner(System.in); int index = getInput.nextInt(); @@ -158,8 +157,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { Recipe recipe = parseViewRecipe(recipeName, recipeList); ui.printRecipe(recipe); ui.printSeparator(); - System.out.println( - "Please Enter Additional Ingredients & Quantity (Enter done when complete): "); + System.out.println("Please Enter Additional Ingredients & Quantity (Enter done when complete): "); while (true) { String line = userInput.nextLine(); if (line.equals("done")) { @@ -218,7 +216,8 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { while (recipeList.size() != newSize) { rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; } - rangeRecipes = String.valueOf(new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2))); + rangeRecipes = String.valueOf( + new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2))); return rangeRecipes; } else { int recipeIndex = Integer.parseInt(input[1]); @@ -407,30 +406,28 @@ public Recipe parseRandomRecipe(RecipeList recipes) { } public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidRecipeNameException, InvalidNegativeValueException { + throws ArrayIndexOutOfBoundsException, NumberFormatException, InvalidRecipeNameException, + InvalidNegativeValueException { WeeklyPlan updatedWeeklyPlan; - try { - switch (command[1]) { - case "/add": - case "/delete": - updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); - break; - case "/multiadd": - case "/multidelete": - updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); - break; - default: - throw new IllegalArgumentException( - "Please indicate if you would want to add or delete the recipe from your weekly " - + "plan."); - } - - return updatedWeeklyPlan; - } catch (ArrayIndexOutOfBoundsException error) { - throw new ArrayIndexOutOfBoundsException("Insufficient number of arguments provided."); - } catch (NumberFormatException error) { - throw new NumberFormatException("Please enter a valid number as the last argument."); + switch (command[1]) { + case "/add": + case "/delete": + updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + case "/multidelete": + updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); + break; + case "/clear": + updatedWeeklyPlan = new WeeklyPlan(); + break; + default: + throw new IllegalArgumentException( + "Please indicate if you would want to add to, delete from, or clear the weekly " + + "plan."); } + + return updatedWeeklyPlan; } private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipes) @@ -492,8 +489,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes for (int i = 0; i < startIndices.size(); i++) { int nameStartIndex = startIndices.get(i) + 1; int nameEndIndex = endIndices.get(i) - 1; - recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, - nameEndIndex); + recipeName = getRecipeNames(command, recipeNames, recipeName, nameStartIndex, nameEndIndex); } // Add each recipe to the weekly plan @@ -513,7 +509,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, - StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { + StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { recipeName.append(command[nameStartIndex].toLowerCase().trim()); for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { recipeName.append(" ").append(command[j].toLowerCase().trim()); @@ -529,8 +525,7 @@ public LocalDate parseDate(String input) { try { return LocalDate.parse(input, formatter); } catch (DateTimeParseException e) { - throw new IllegalArgumentException( - "Please enter a valid date in the format dd/mm/yyyy"); + throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy"); } } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 88828ecd08..3ccfcb32dc 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -105,14 +105,14 @@ public void printHelp() { printMessage("2. View Recipe: view {index number}"); printMessage("3. Edit Recipe: edit {recipe name}"); printMessage("4. Delete Recipe: delete {index number} or delete {index range} or"); - printMessage("delete /r {recipe name}or delete /r all"); + printMessage(" delete /r {recipe name}or delete /r all"); printMessage("5. List All Recipes: list"); printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); - printMessage("/r {recipe2 name} /q {quantity2}"); + printMessage(" /r {recipe2 name} /q {quantity2}"); printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); - printMessage("/q {quantity1} /r {recipe2 name} /q {quantity2}"); + printMessage(" /q {quantity1} /r {recipe2 name} /q {quantity2}"); printMessage("10. View Weekly Plan: weeklyplan"); printMessage("11. Clearing weekly plan: weekly /clear"); printMessage("12. View Weekly Ingredients: weeklyingredients"); diff --git a/src/main/java/seedu/meal360/storage/Database.java b/src/main/java/seedu/meal360/storage/Database.java index 2f571ee32e..9954ef9a58 100644 --- a/src/main/java/seedu/meal360/storage/Database.java +++ b/src/main/java/seedu/meal360/storage/Database.java @@ -57,130 +57,130 @@ public void saveIngredientsDatabase(IngredientList userIngredients) throws IOExc public RecipeList defaultRecipeList() { RecipeList defaultRecipeList = new RecipeList(); - defaultRecipeList.add(new Recipe("Chicken Rice", new HashMap<>() { + defaultRecipeList.add(new Recipe("chicken rice", new HashMap<>() { { - put("Chicken", 1); - put("Rice", 1); - put("Salt", 1); - put("Pepper", 1); + put("chicken", 1); + put("rice", 1); + put("salt", 1); + put("pepper", 1); } })); - defaultRecipeList.add(new Recipe("Tomato fritters", new HashMap<>() { + defaultRecipeList.add(new Recipe("tomato fritters", new HashMap<>() { { - put("Ripe mixed-colour cherry tomatoes ", 250); - put("Flat-leaf parsley", 15); - put("Garlic cloves", 2); - put("Plain flour", 2); - put("Eggs", 2); - put("Breadcrumbs", 100); - put("Vegetable oil", 2); - put("Feta cheese", 30); + put("ripe mixed-colour cherry tomatoes ", 250); + put("flat-leaf parsley", 15); + put("garlic cloves", 2); + put("plain flour", 2); + put("eggs", 2); + put("breadcrumbs", 100); + put("vegetable oil", 2); + put("feta cheese", 30); } })); - defaultRecipeList.add(new Recipe("Chicken and mushroom pie", new HashMap<>() { + defaultRecipeList.add(new Recipe("chicken and mushroom pie", new HashMap<>() { { - put("Chicken breast fillets", 2); - put("Mushrooms", 250); - put("Onion", 1); - put("Plain flour", 2); - put("Butter", 2); - put("Milk", 2); - put("Puff pastry", 1); + put("chicken breast fillets", 2); + put("mushrooms", 250); + put("onion", 1); + put("plain flour", 2); + put("butter", 2); + put("milk", 2); + put("puff pastry", 1); } })); - defaultRecipeList.add(new Recipe("Seafood paella", new HashMap<>() { + defaultRecipeList.add(new Recipe("seafood paella", new HashMap<>() { { - put("Prawns", 500); - put("Mussels", 500); - put("Chorizo", 100); - put("Onion", 1); - put("Garlic cloves", 2); - put("Rice", 1); - put("Cherry tomatoes", 250); - put("Vegetable oil", 2); - put("Chicken stock", 1); - put("Saffron", 1); + put("prawns", 500); + put("mussels", 500); + put("chorizo", 100); + put("onion", 1); + put("garlic cloves", 2); + put("rice", 1); + put("cherry tomatoes", 250); + put("vegetable oil", 2); + put("chicken stock", 1); + put("saffron", 1); } })); - defaultRecipeList.add(new Recipe("Avocado toast", new HashMap<>() { + defaultRecipeList.add(new Recipe("avocado toast", new HashMap<>() { { - put("Avocado", 1); - put("Bread", 2); - put("Lemon", 1); - put("Salt", 1); - put("Pepper", 1); + put("avocado", 1); + put("bread", 2); + put("lemon", 1); + put("salt", 1); + put("pepper", 1); } })); - defaultRecipeList.add(new Recipe("Italian sausage orzo soup", new HashMap<>() { + defaultRecipeList.add(new Recipe("italian sausage orzo soup", new HashMap<>() { { - put("Italian sausage", 1); - put("Onion", 1); - put("Garlic cloves", 2); - put("Carrot", 1); - put("Celery", 1); - put("Dried oregano", 1); - put("Dried basil", 1); - put("Dried thyme", 1); - put("Dried parsley", 1); - put("Dried rosemary", 1); - put("Chicken stock", 1); - put("Orzo", 1); - put("Parmesan cheese", 1); + put("italian sausage", 1); + put("onion", 1); + put("garlic cloves", 2); + put("carrot", 1); + put("celery", 1); + put("dried oregano", 1); + put("dried basil", 1); + put("dried thyme", 1); + put("dried parsley", 1); + put("dried rosemary", 1); + put("chicken stock", 1); + put("orzo", 1); + put("parmesan cheese", 1); } })); - defaultRecipeList.add(new Recipe("Chicken and mushroom pasta", new HashMap<>() { + defaultRecipeList.add(new Recipe("chicken and mushroom pasta", new HashMap<>() { { - put("Chicken breast fillets", 2); - put("Mushrooms", 250); - put("Onion", 1); - put("Garlic cloves", 2); - put("Plain flour", 2); - put("Butter", 2); - put("Milk", 2); - put("Pasta", 1); + put("chicken breast fillets", 2); + put("mushrooms", 250); + put("onion", 1); + put("garlic cloves", 2); + put("plain flour", 2); + put("butter", 2); + put("milk", 2); + put("pasta", 1); } })); - defaultRecipeList.add(new Recipe("Creamy Hummus Pasta", new HashMap<>() { + defaultRecipeList.add(new Recipe("creamy Hummus Pasta", new HashMap<>() { { - put("Pasta", 1); - put("Hummus", 1); - put("Garlic cloves", 2); - put("Lemon", 1); - put("Salt", 1); - put("Pepper", 1); + put("pasta", 1); + put("hummus", 1); + put("garlic cloves", 2); + put("lemon", 1); + put("salt", 1); + put("pepper", 1); } })); - defaultRecipeList.add(new Recipe("Ground beef and potato casserole", new HashMap<>() { + defaultRecipeList.add(new Recipe("ground beef and potato casserole", new HashMap<>() { { - put("Ground beef", 1); - put("Potato", 1); - put("Onion", 1); - put("Garlic cloves", 2); - put("Tomato paste", 1); - put("Tomato sauce", 1); - put("Beef stock", 1); - put("Cheddar cheese", 1); + put("ground beef", 1); + put("potato", 1); + put("onion", 1); + put("garlic cloves", 2); + put("tomato paste", 1); + put("tomato sauce", 1); + put("beef stock", 1); + put("cheddar cheese", 1); } })); - defaultRecipeList.add(new Recipe("Buffalo Chicken Mac 'n' Cheese", new HashMap<>() { + defaultRecipeList.add(new Recipe("buffalo chicken mac 'n' cheese", new HashMap<>() { { - put("Chicken breast fillets", 2); - put("Macaroni", 1); - put("Butter", 2); - put("Flour", 2); - put("Milk", 2); - put("Cheddar cheese", 1); - put("Blue cheese", 1); - put("Hot sauce", 1); + put("chicken breast fillets", 2); + put("macaroni", 1); + put("butter", 2); + put("flour", 2); + put("milk", 2); + put("cheddar cheese", 1); + put("clue cheese", 1); + put("hot sauce", 1); } })); From c66f39671b5002be3b75ad1508d2796fd4a2bc44 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sat, 1 Apr 2023 22:50:23 +0800 Subject: [PATCH 149/252] Bug fixes and minor updates to commands and user docs Add protection against overly large/small number, quantity for number of times each recipe can be included in weekly plan is capped at 1000. Add clearer error message for when integer provided for `view` function results in overflow. Update `weekly /add` in user documentation to be more specific. Update parsing of user input to be non case-sensitive. * Closes #100 * Closes #95 * Closes #87 * Closes #86 --- docs/UserGuide.md | 28 +++++----- src/main/java/seedu/meal360/Meal360.java | 4 +- src/main/java/seedu/meal360/Parser.java | 37 +++++++++----- src/main/java/seedu/meal360/WeeklyPlan.java | 20 ++++++-- src/test/java/seedu/meal360/Meal360Test.java | 54 ++++++++++++++------ 5 files changed, 94 insertions(+), 49 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index a5bb5a4e9a..7b910ec943 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -28,15 +28,14 @@ ___ * [View weekly plan](#view-this-weeks-plan--weeklyplan) * [Random a recipe](#random-a-recipe--random) - ### HOW TO ADD INGREDIENTS TO A RECIPE: * Please follow the below-mentioned format. Format: `ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ...` - + * Examples: `chicken=100 oil and sauce=200 vegetables=300` - `meat=200 salt and spices=400` + `meat=200 salt and spices=400` * Type the ingredient name followed by equal sign and quantity in positive integer values. ### Adding recipes: `add` @@ -62,7 +61,7 @@ Format: `edit /r [recipe_name]` * `recipe_name` is basically a string. * Type the recipe name after typing `/r `. * If you want to edit fully: press 1, edit partially: press 2, or add new ingredients: press 3. -* Follow the proper format while editing/adding ingredients. +* Follow the proper format while editing/adding ingredients. Example of usage: @@ -165,9 +164,10 @@ Example of usage: Adds an existing recipe to this week's plan. -Format: `weekly /add RECIPE NAME QUANTITY` +Format: `weekly /add RECIPE_NAME QUANTITY` -* Adds the specified `RECIPE NAME` to this week's plan`QUANTITY` number of times. +* Adds the specified `RECIPE_ NAME` to this week's plan`QUANTITY` number of times, with quantity + representing the number of days the user plans to prepare the recipe within the week. * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive integer** 1,2,3, ... @@ -181,7 +181,7 @@ Example of usage: Adds multiple existing recipe to this week's plan. -Format: `weekly /multiadd [/r RECIPE NAME /q QUANTITY]` +Format: `weekly /multiadd [/r RECIPE_NAME /q QUANTITY]` * Adds the specified `RECIPE NAME` to this week's plan`QUANTITY` number of times. * At least one pair of `RECIPE_NAME` and `QUANTITY` is required. @@ -189,6 +189,8 @@ Format: `weekly /multiadd [/r RECIPE NAME /q QUANTITY]` * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive integer** 1,2,3, ... +* If the same recipe is specified multiple times, only the **last** quantity specified + will be used. Example of usage: @@ -199,9 +201,9 @@ Example of usage: Deletes an existing recipe from this week's plan. -Format: `weekly /delete RECIPE NAME` +Format: `weekly /delete RECIPE_NAME` -* Deletes the specified `RECIPE NAME` to this week's plan. +* Deletes the specified `RECIPE_NAME` to this week's plan. * The recipe name refers to the name of the recipe shown in the displayed recipe list. Example of usage: @@ -212,14 +214,16 @@ Example of usage: Deletes multiple existing recipe from this week's plan. -Format: `weekly /multidelete [/r RECIPE NAME /q QUANTITY]` +Format: `weekly /multidelete [/r RECIPE_NAME /q QUANTITY]` -* Deletes the specified `RECIPE NAME` from this week's plan`QUANTITY` number of times. +* Deletes the specified `RECIPE_NAME` from this week's plan`QUANTITY` number of times. * At least one pair of `RECIPE_NAME` and `QUANTITY` is required. * Each `RECIPE_NAME` and `QUANTITY` requires `/r` and `/q` before it respectively. * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive integer** 1,2,3, ... +* If the same recipe is specified multiple times, only the **last** quantity specified + will be used. Example of usage: @@ -269,7 +273,6 @@ Format: `bye` Add user's ingredients into the ingredient list. Format : `add_i /n INGREDIENT_NAME /c QUANTITY /d DATE` -* This function is **case sensitive**. * The quantity **must be a positive integer** 1,2,3, ... * The date **must be in the format of DD/MM/YYYY** @@ -283,7 +286,6 @@ Example of usage: Delete user's ingredients from the ingredient list. Format : `del_i /n INGREDIENT_NAME /c QUANTITY` -* This function is **case sensitive**. * The quantity has to be **less than or equal** to the quantity of the ingredient in the list. * The quantity **must be a positive integer** 1,2,3, ... diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 815ab74247..ac598974e1 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -63,9 +63,7 @@ public static void startApp() { } public static void receiveInput(String input) { - input = input.replaceAll("\\s+", " "); - input = input.toLowerCase(); - String[] command = input.trim().split(" "); + String[] command = parser.cleanUserInput(input); if (input.equalsIgnoreCase("bye")) { canExit = true; diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 501ca604e0..83d76153cb 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -24,6 +24,12 @@ public String combineWords(String[] input, int startIndex, int length) { return word.toString(); } + public String[] cleanUserInput(String input) { + input = input.replaceAll("\\s+", " "); + input = input.toLowerCase(); + return input.trim().split(" "); + } + public HashMap parseIngredientName(String[] command) { HashMap ingredients = new HashMap<>(); int flag = 0; @@ -372,7 +378,7 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { requestedRecipe = recipes.get(recipeIndex - 1); } catch (NumberFormatException error) { String errorMessage = String.format( - "Please enter a valid recipe number. You entered %s, " + "which is not a number.", + "Please enter a valid recipe number. You entered %s, " + "which is not a valid number.", command[1]); throw new NumberFormatException(errorMessage); } catch (ArrayIndexOutOfBoundsException error) { @@ -432,9 +438,15 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipes) throws InvalidNegativeValueException, InvalidRecipeNameException { - int numDays = Integer.parseInt(command[command.length - 1]); - if (numDays < 1) { - throw new InvalidNegativeValueException("Number of days needs to be at least 1."); + int numDays; + try { + numDays = Integer.parseInt(command[command.length - 1]); + } catch (NumberFormatException e) { + throw new NumberFormatException("Please enter a number between 1 to 1000 for the quantity."); + } + + if (numDays > 1000 || numDays < 1) { + throw new NumberFormatException("Please enter a number between 1 to 1000 for the quantity."); } int nameLastIndex = command.length - 1; @@ -467,20 +479,16 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } else if (command[i].equals("/q")) { endIndices.add(i); int quantity = Integer.parseInt(command[i + 1]); - if (quantity < 1) { + if (quantity < 1 || quantity > 1000) { throw new InvalidNegativeValueException( - "Please enter a positive number for the quantity."); + "Please enter a positive number between 1 to 1000 for the quantity."); } quantities.add(quantity); } } // Checks that command is entered in the correct - if (startIndices.size() != endIndices.size()) { - throw new IllegalArgumentException("Please ensure the number of recipes and quantities match."); - } - - if (startIndices.size() == 0) { + if (startIndices.size() != endIndices.size() || startIndices.size() == 0) { throw new IllegalArgumentException( "Please ensure that the command is entered in the correct format."); } @@ -502,7 +510,8 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } } } catch (NumberFormatException error) { - throw new NumberFormatException("Please enter a positive number for the quantity."); + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); } return recipesToEdit; @@ -542,9 +551,9 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL break; case "/c": ingredientCount = Integer.parseInt(command[++i]); - if (ingredientCount < 0) { + if (ingredientCount < 0 || ingredientCount > 1000) { throw new IllegalArgumentException( - "Please enter a positive number for the quantity."); + "Please enter a positive number between 1 to 1000 for the quantity."); } break; case "/d": diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index 56417cbd0f..f0c269b22c 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -6,13 +6,25 @@ public class WeeklyPlan extends HashMap { public void addPlans(WeeklyPlan recipeMap) { + final boolean[] validNumber = {true}; recipeMap.forEach((recipe, count) -> { - if (this.containsKey(recipe)) { - this.put(recipe, this.get(recipe) + count); // Case when recipe already exists in plan - } else { - this.put(recipe, count); + if (validNumber[0] && this.containsKey(recipe)) { + int newCount = this.get(recipe) + count; + validNumber[0] = (newCount > 1000) ? false : true; } }); + + if (validNumber[0]) { + recipeMap.forEach((recipe, count) -> { + if (this.containsKey(recipe)) { + this.put(recipe, this.get(recipe) + count); + } else { + this.put(recipe, count); + } + }); + } else { + throw new IllegalArgumentException("Total quantity cannot exceed 1000!"); + } } public void deletePlans(WeeklyPlan recipeMap) { diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 3eaded88be..e078c04b1d 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -164,29 +164,42 @@ public void testAddMultiWeeklyPlan() throws InvalidRecipeNameException, InvalidN assertEquals(5, (int) weeklyPlan.get("pizza")); assertFalse(weeklyPlan.containsKey("salad")); + // Testing specifying the same recipe name twice + recipeMap = parser.parseWeeklyPlan( + new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "burger", "/q", "20"}, + recipes); + weeklyPlan.addPlans(recipeMap); + assertEquals(21, (int) weeklyPlan.get("burger")); + + // Testing if case-insensitive + recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/multiadd", "/r", "Burger", "/q", "20"}, + recipes); + weeklyPlan.addPlans(recipeMap); + assertEquals(41, (int) weeklyPlan.get("burger")); + // Testing exceptions assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "1", "/r", "pizza", "/q", "5"}, + new String[]{"weekly", "/multiadd", "/r", "burgersss", "/q", "1", "/r", "pizza", "/q", "5"}, recipes)); assertThrows(InvalidNegativeValueException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "0", "/r", "pizza", "/q", "5"}, + new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "0", "/r", "pizza", "/q", "5"}, recipes)); assertThrows(InvalidNegativeValueException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "-1", "/r", "pizza", "/q", "5"}, + new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "-1", "/r", "pizza", "/q", "5"}, recipes)); assertThrows(NumberFormatException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "one", "/r", "pizza", "/q", "5"}, + new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "one", "/r", "pizza", "/q", "5"}, recipes)); assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "1", "/r", "salad", "/r", "pizza"}, + new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "salad", "/r", "pizza"}, recipes)); assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burgers", "/q", "1", "/r", "salad", "/q", "/q"}, + new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "salad", "/q", "/q"}, recipes)); } @@ -228,6 +241,19 @@ public void testDeleteMultiWeeklyPlan() throws InvalidRecipeNameException, Inval weeklyPlan.deletePlans(recipeMap); assertEquals(3, weeklyPlan.size()); + // Testing specifying the same recipe name twice + recipeMap = parser.parseWeeklyPlan( + new String[]{"weekly", "/multidelete", "/r", "burger", "/q", "50", "/r", "burger", "/q", + "30"}, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(69, (int) weeklyPlan.get("burger")); + + // Testing if case-insensitive + recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/multidelete", "/r", "Burger", "/q", "3"}, + recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(66, (int) weeklyPlan.get("burger")); + // Testing exceptions weeklyPlan.put("pizza", 3); weeklyPlan.put("burger", 100); @@ -336,7 +362,7 @@ public void testListTagAndAddTag() { inputs = new String[]{"list", "/t", "breakfast"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(recipeListToPrint.size(), 2); - assertEquals(recipeListToPrint.get(1).getName(), "pizza"); + assertEquals(recipeListToPrint.get(0).getName(), "pizza"); inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); @@ -382,7 +408,7 @@ public void testListTagException() { @Test public void testRemoveTagAndAddTag() { String[] inputs; - Recipe invalidRecipe = new Recipe("invalid Recipe", new HashMap<>(1,1)); + Recipe invalidRecipe = new Recipe("invalid Recipe", new HashMap<>(1, 1)); inputs = new String[]{"tag", "western", "<<", "burger"}; parser.parseTagRecipe(inputs, recipes); @@ -390,15 +416,14 @@ public void testRemoveTagAndAddTag() { parser.parseTagRecipe(inputs, recipes); //exception - assertThrows(IndexOutOfBoundsException.class, () - -> recipes.removeRecipeFromTag("western", invalidRecipe)); + assertThrows(IndexOutOfBoundsException.class, + () -> recipes.removeRecipeFromTag("western", invalidRecipe)); String[] invalidTagInputs = new String[]{"tag", "random", "tag", ">>", "burger"}; - assertThrows(IndexOutOfBoundsException.class, () - -> parser.parseTagRecipe(invalidTagInputs, recipes)); + assertThrows(IndexOutOfBoundsException.class, () -> parser.parseTagRecipe(invalidTagInputs, recipes)); String[] noRecipeInTagInputs = new String[]{"tag", "breakfast", ">>", "pizza"}; - assertThrows(IndexOutOfBoundsException.class, () - -> parser.parseTagRecipe(noRecipeInTagInputs, recipes)); + assertThrows(IndexOutOfBoundsException.class, + () -> parser.parseTagRecipe(noRecipeInTagInputs, recipes)); inputs = new String[]{"tag", "western", ">>", "pizza"}; parser.parseTagRecipe(inputs, recipes); @@ -411,7 +436,6 @@ public void testRandomRecipe() { RecipeList blankRecipeList = new RecipeList(); assertThrows(NullPointerException.class, () -> parser.parseRandomRecipe(blankRecipeList)); - // general case Recipe randomRecipe1 = parser.parseRandomRecipe(recipes); assertNotNull(randomRecipe1); From 96752571eca4d0b1f31a7aaab1921780fe180ff5 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sun, 2 Apr 2023 17:17:58 +0800 Subject: [PATCH 150/252] Update JUnit test and user docs Fix bugs in functions regarding adding and deleting recipes from weekly plan. Update JUnit test and user docs for the following few commands: * `weekly /add` * `weekly /multiadd` * `weekly /delete` * `weekly /multidelete` * 'view` --- docs/UserGuide.md | 12 +- src/main/java/seedu/meal360/Meal360.java | 4 +- src/main/java/seedu/meal360/Parser.java | 31 +- .../InvalidNegativeValueException.java | 8 - .../exceptions/InvalidValueException.java | 8 + src/test/java/seedu/meal360/Meal360Test.java | 770 ++++++++++++++---- text-ui-test/EXPECTED.TXT | 42 +- 7 files changed, 669 insertions(+), 206 deletions(-) delete mode 100644 src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java create mode 100644 src/main/java/seedu/meal360/exceptions/InvalidValueException.java diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 7b910ec943..43bc8b5ae2 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -13,6 +13,10 @@ ___ 1. Ensure that you have Java 11 or above installed. 2. Down the latest version of `Meal360` from [here](https://github.com/AY2223S2-CS2113-F10-3/tp/releases). +3. Upon the first launch, the app will create a `database` folder in the same directory as the + `tp.jar` file. This folder will contain all the data files that the app will use. Please do not + touch these files to ensure smooth operation of the app. +4. To allow for immediate testing of features, the app comes preloaded with 10 recipes. ___ @@ -170,7 +174,7 @@ Format: `weekly /add RECIPE_NAME QUANTITY` representing the number of days the user plans to prepare the recipe within the week. * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive - integer** 1,2,3, ... + integer** between 1 and 1000. Example of usage: @@ -188,7 +192,7 @@ Format: `weekly /multiadd [/r RECIPE_NAME /q QUANTITY]` * Each `RECIPE_NAME` and `QUANTITY` requires `/r` and `/q` before it respectively. * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive - integer** 1,2,3, ... + integer** between 1 and 1000. * If the same recipe is specified multiple times, only the **last** quantity specified will be used. @@ -205,6 +209,8 @@ Format: `weekly /delete RECIPE_NAME` * Deletes the specified `RECIPE_NAME` to this week's plan. * The recipe name refers to the name of the recipe shown in the displayed recipe list. +* The quantity **must be a positive + integer** between 1 and 1000. Example of usage: @@ -221,7 +227,7 @@ Format: `weekly /multidelete [/r RECIPE_NAME /q QUANTITY]` * Each `RECIPE_NAME` and `QUANTITY` requires `/r` and `/q` before it respectively. * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive - integer** 1,2,3, ... + integer** between 1 and 1000. * If the same recipe is specified multiple times, only the **last** quantity specified will be used. diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index ac598974e1..d47543f74a 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -3,7 +3,7 @@ import java.io.IOException; import java.util.Scanner; import seedu.meal360.exceptions.IngredientNotFoundException; -import seedu.meal360.exceptions.InvalidNegativeValueException; +import seedu.meal360.exceptions.InvalidValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; import seedu.meal360.storage.Database; @@ -184,7 +184,7 @@ public static void receiveInput(String input) { ui.printMessage("Please enter a valid command."); break; } - } catch (IllegalArgumentException | InvalidNegativeValueException | InvalidRecipeNameException | + } catch (IllegalArgumentException | InvalidValueException | InvalidRecipeNameException | ArrayIndexOutOfBoundsException e) { ui.printMessage(e.getMessage()); } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 83d76153cb..1de6574c06 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.Scanner; import seedu.meal360.exceptions.IngredientNotFoundException; -import seedu.meal360.exceptions.InvalidNegativeValueException; +import seedu.meal360.exceptions.InvalidValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; import java.time.format.DateTimeFormatter; @@ -413,7 +413,7 @@ public Recipe parseRandomRecipe(RecipeList recipes) { public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) throws ArrayIndexOutOfBoundsException, NumberFormatException, InvalidRecipeNameException, - InvalidNegativeValueException { + InvalidValueException { WeeklyPlan updatedWeeklyPlan; switch (command[1]) { case "/add": @@ -437,8 +437,13 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) } private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { + throws InvalidValueException, InvalidRecipeNameException { int numDays; + + if (command.length < 4) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } + try { numDays = Integer.parseInt(command[command.length - 1]); } catch (NumberFormatException e) { @@ -446,7 +451,7 @@ private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipe } if (numDays > 1000 || numDays < 1) { - throw new NumberFormatException("Please enter a number between 1 to 1000 for the quantity."); + throw new InvalidValueException("Please enter a number between 1 to 1000 for the quantity."); } int nameLastIndex = command.length - 1; @@ -465,7 +470,12 @@ private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipe } private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidNegativeValueException, InvalidRecipeNameException { + throws InvalidValueException, InvalidRecipeNameException { + int quantity; + if (command.length < 6) { + throw new IllegalArgumentException("Please enter the command in the correct format."); + } + WeeklyPlan recipesToEdit = new WeeklyPlan(); ArrayList quantities = new ArrayList<>(); ArrayList recipeNames = new ArrayList<>(); @@ -478,9 +488,14 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes startIndices.add(i); } else if (command[i].equals("/q")) { endIndices.add(i); - int quantity = Integer.parseInt(command[i + 1]); + try { + quantity = Integer.parseInt(command[i + 1]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } if (quantity < 1 || quantity > 1000) { - throw new InvalidNegativeValueException( + throw new InvalidValueException( "Please enter a positive number between 1 to 1000 for the quantity."); } quantities.add(quantity); @@ -490,7 +505,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes // Checks that command is entered in the correct if (startIndices.size() != endIndices.size() || startIndices.size() == 0) { throw new IllegalArgumentException( - "Please ensure that the command is entered in the correct format."); + "Please enter the command in the correct format."); } // Building the recipe names diff --git a/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java b/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java deleted file mode 100644 index 490541f099..0000000000 --- a/src/main/java/seedu/meal360/exceptions/InvalidNegativeValueException.java +++ /dev/null @@ -1,8 +0,0 @@ -package seedu.meal360.exceptions; - -public class InvalidNegativeValueException extends Exception { - - public InvalidNegativeValueException(String message) { - super(message); - } -} diff --git a/src/main/java/seedu/meal360/exceptions/InvalidValueException.java b/src/main/java/seedu/meal360/exceptions/InvalidValueException.java new file mode 100644 index 0000000000..963f766747 --- /dev/null +++ b/src/main/java/seedu/meal360/exceptions/InvalidValueException.java @@ -0,0 +1,8 @@ +package seedu.meal360.exceptions; + +public class InvalidValueException extends Exception { + + public InvalidValueException(String message) { + super(message); + } +} diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index e078c04b1d..b45c793f09 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1,22 +1,22 @@ package seedu.meal360; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.HashMap; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import seedu.meal360.exceptions.InvalidNegativeValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; +import seedu.meal360.exceptions.InvalidValueException; import seedu.meal360.storage.Database; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - class Meal360Test { private static RecipeList recipes = new RecipeList(); @@ -25,6 +25,8 @@ class Meal360Test { private static final Database database = new Database(); + private static final IngredientList userIngredients = new IngredientList(); + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; @@ -72,24 +74,74 @@ public void tearDownRecipes() { @Test public void testViewRecipe() { - Recipe recipe = parser.parseViewRecipe(new String[]{"view", "1"}, recipes); - assertEquals("burger", recipe.getName()); - assertEquals(2, (int) recipe.getIngredients().get("buns")); - assertEquals(1, (int) recipe.getIngredients().get("meat patty")); - assertEquals(3, (int) recipe.getIngredients().get("lettuce")); - - // Testing exceptions - assertThrows(ArrayIndexOutOfBoundsException.class, - () -> parser.parseViewRecipe(new String[]{"view"}, recipes)); - - assertThrows(NumberFormatException.class, - () -> parser.parseViewRecipe(new String[]{"view", "a"}, recipes)); - - assertThrows(IndexOutOfBoundsException.class, - () -> parser.parseViewRecipe(new String[]{"view", "5"}, recipes)); - assertThrows(IndexOutOfBoundsException.class, - () -> parser.parseViewRecipe(new String[]{"view", "0"}, recipes)); + // Testing positive case + try { + String userInput = "view 1"; + String[] command = parser.cleanUserInput(userInput); + Recipe recipe = parser.parseViewRecipe(command, recipes); + assertEquals("burger", recipe.getName()); + assertEquals(2, (int) recipe.getIngredients().get("buns")); + assertEquals(1, (int) recipe.getIngredients().get("meat patty")); + assertEquals(3, (int) recipe.getIngredients().get("lettuce")); + } catch (Exception e) { + assert false; + } + + // Testing negative case (invalid index) + try { + String userInput = "view 5"; + String[] command = parser.cleanUserInput(userInput); + parser.parseViewRecipe(command, recipes); + assert false; + } catch (Exception e) { + assertEquals("Please enter a valid recipe number. You entered 5, which is out of bounds.", + e.getMessage()); + } + + // Testing negative case (invalid index) + try { + String userInput = "view 0"; + String[] command = parser.cleanUserInput(userInput); + parser.parseViewRecipe(command, recipes); + assert false; + } catch (Exception e) { + assertEquals("Please enter a valid recipe number. You entered 0, which is out of bounds.", + e.getMessage()); + } + + // Testing negative case (missing index) + try { + String userInput = "view"; + String[] command = parser.cleanUserInput(userInput); + parser.parseViewRecipe(command, recipes); + assert false; + } catch (Exception e) { + assertEquals("Please enter a valid recipe number. You did not enter a recipe number.", + e.getMessage()); + } + + // Testing negative case (index is not a number) + try { + String userInput = "view a"; + String[] command = parser.cleanUserInput(userInput); + parser.parseViewRecipe(command, recipes); + assert false; + } catch (Exception e) { + assertEquals("Please enter a valid recipe number. You entered a, which is not a valid number.", + e.getMessage()); + } + + // Testing negative case (index is negative number) + try { + String userInput = "view -1"; + String[] command = parser.cleanUserInput(userInput); + parser.parseViewRecipe(command, recipes); + assert false; + } catch (Exception e) { + assertEquals("Please enter a valid recipe number. You entered -1, which is out of bounds.", + e.getMessage()); + } } @Test @@ -109,162 +161,553 @@ public void testDeleteRecipe() { } @Test - public void testAddWeeklyPlan() throws InvalidRecipeNameException, InvalidNegativeValueException { + public void testAddWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); - // Testing add recipe to weekly plan - WeeklyPlan recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "1"}, recipes); - weeklyPlan.addPlans(recipeMap); - assertTrue(weeklyPlan.containsKey("burger")); - assertEquals(1, (int) weeklyPlan.get("burger")); - assertFalse(weeklyPlan.containsKey("pizza")); - - recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/add", "pizza", "3"}, recipes); - weeklyPlan.addPlans(recipeMap); - assertTrue(weeklyPlan.containsKey("pizza")); - assertEquals(3, (int) weeklyPlan.get("pizza")); - - // Testing throwing of exceptions - assertThrows(IllegalArgumentException.class, - () -> parser.parseWeeklyPlan(new String[]{"weekly", "burger", "1"}, recipes)); - - assertThrows(IllegalArgumentException.class, - () -> parser.parseWeeklyPlan(new String[]{"weekly", "burger"}, recipes)); - - assertThrows(NumberFormatException.class, - () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger"}, recipes)); - - assertThrows(NumberFormatException.class, - () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "a"}, recipes)); - - assertThrows(InvalidNegativeValueException.class, - () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "0"}, recipes)); - - assertThrows(InvalidNegativeValueException.class, - () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "burger", "-9"}, recipes)); - - assertThrows(InvalidRecipeNameException.class, - () -> parser.parseWeeklyPlan(new String[]{"weekly", "/add", "unknown", "1"}, recipes)); - - // TODO: Check error messages + // Testing positive case + try { + String userInput = "weekly /add burger 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(1, (int) weeklyPlan.get("burger")); + } catch (Exception e) { + assert false; + } + + // Testing case-insensitive + try { + String userInput = "weekly /add BURGER 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(2, (int) weeklyPlan.get("burger")); + } catch (Exception e) { + assert false; + } + + // Testing negative case (recipe does not exist in recipe list) + try { + String userInput = "weekly /add chicken 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(InvalidRecipeNameException.class, e.getClass()); + assertEquals("Please indicate a valid recipe name.", e.getMessage()); + } + + // Testing negative case (quantity is 0) + try { + String userInput = "weekly /add burger 0"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity is negative) + try { + String userInput = "weekly /add burger -1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity is greater than 1000) + try { + String userInput = "weekly /add burger 1001"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity is not a number) + try { + String userInput = "weekly /add burger a"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (recipe name is not specified) + try { + String userInput = "weekly /add"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (quantity is not specified) + try { + String userInput = "weekly /add burger"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (quantity specified is not an integer) + try { + String userInput = "weekly /add burger 1.5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity specified causes integer overflow) + try { + String userInput = "weekly /add burger 21474836480000000000"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } } @Test - public void testAddMultiWeeklyPlan() throws InvalidRecipeNameException, InvalidNegativeValueException { + public void testAddMultiWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); - // Testing add recipe to weekly plan - WeeklyPlan recipeMap = parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "pizza", "/q", "5"}, - recipes); - weeklyPlan.addPlans(recipeMap); - assertTrue(weeklyPlan.containsKey("burger")); - assertEquals(1, (int) weeklyPlan.get("burger")); - assertTrue(weeklyPlan.containsKey("pizza")); - assertEquals(5, (int) weeklyPlan.get("pizza")); - assertFalse(weeklyPlan.containsKey("salad")); - - // Testing specifying the same recipe name twice - recipeMap = parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "burger", "/q", "20"}, - recipes); - weeklyPlan.addPlans(recipeMap); - assertEquals(21, (int) weeklyPlan.get("burger")); - - // Testing if case-insensitive - recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/multiadd", "/r", "Burger", "/q", "20"}, - recipes); - weeklyPlan.addPlans(recipeMap); - assertEquals(41, (int) weeklyPlan.get("burger")); - - // Testing exceptions - assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burgersss", "/q", "1", "/r", "pizza", "/q", "5"}, - recipes)); - - assertThrows(InvalidNegativeValueException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "0", "/r", "pizza", "/q", "5"}, - recipes)); - - assertThrows(InvalidNegativeValueException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "-1", "/r", "pizza", "/q", "5"}, - recipes)); - - assertThrows(NumberFormatException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "one", "/r", "pizza", "/q", "5"}, - recipes)); - - assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "salad", "/r", "pizza"}, - recipes)); - - assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multiadd", "/r", "burger", "/q", "1", "/r", "salad", "/q", "/q"}, - recipes)); + // Testing positive case + try { + String userInput = "weekly /multiadd /r burger /q 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(1, (int) weeklyPlan.get("burger")); + } catch (Exception e) { + assert false; + } + + // Testing positive case (adding multiple recipes) + try { + String userInput = "weekly /multiadd /r burger /q 1 /r pizza /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(2, (int) weeklyPlan.get("burger")); + assertTrue(weeklyPlan.containsKey("pizza")); + assertEquals(5, (int) weeklyPlan.get("pizza")); + } catch (Exception e) { + assert false; + } + + // Testing case where same recipe name is specified twice + try { + String userInput = "weekly /multiadd /r burger /q 1 /r burger /q 20"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(22, (int) weeklyPlan.get("burger")); + } catch (Exception e) { + assert false; + } + + // Testing negative case (quantity is negative) + try { + String userInput = "weekly /multiadd /r burger /q -1 /r pizza /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (quantity is greater than 1000) + try { + String userInput = "weekly /multiadd /r burger /q 1001 /r pizza /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (quantity is not a number) + try { + String userInput = "weekly /multiadd /r burger /q a /r pizza /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (recipe name is not in the recipe list) + try { + String userInput = "weekly /multiadd /r randomname /q 1 /r burger /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(InvalidRecipeNameException.class, e.getClass()); + assertEquals("Please indicate a valid recipe name.", e.getMessage()); + } + + // Testing negative case (recipe name is not specified) + try { + String userInput = "weekly /multiadd /q 1 /r burger /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (quantity is not specified) + try { + String userInput = "weekly /multiadd /r burger /r pizza /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (quantity given results in integer overflow) + try { + String userInput = "weekly /multiadd /r burger /q 10000000000000000000000 /r pizza /q 5"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } } @Test public void testDeleteWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); - weeklyPlan.put("salad", 1); - weeklyPlan.put("pizza", 3); - - // Testing delete recipe from weekly plan - int oldWeeklyPlanSize = weeklyPlan.size(); - WeeklyPlan toDelete = new WeeklyPlan(); - - // Testing negative case - toDelete.put("burger", 0); - assertThrows(IllegalArgumentException.class, () -> weeklyPlan.deletePlans(toDelete)); - - // Testing positive case - int newWeeklyPlanSize = weeklyPlan.size(); - assertEquals(oldWeeklyPlanSize, newWeeklyPlanSize); - toDelete.clear(); - toDelete.put("salad", 1); - weeklyPlan.deletePlans(toDelete); - newWeeklyPlanSize = weeklyPlan.size(); - assertEquals(oldWeeklyPlanSize - 1, newWeeklyPlanSize); + weeklyPlan.put("salad", 10); + weeklyPlan.put("pizza", 30); + + // Testing positive cases + try { + String userInput = "weekly /delete salad 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(9, weeklyPlan.get("salad")); + } catch (Exception e) { + assert false; // Not supposed to throw any exception here + } + + // Testing case-insensitive + try { + String userInput = "weekly /delete Pizza 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(29, weeklyPlan.get("pizza")); + } catch (InvalidRecipeNameException | InvalidValueException e) { + assert false; // Not supposed to throw any exception here + } + + // Testing negative case (recipe exist in recipe list but not in weekly plan) + try { + String userInput = "weekly /delete burger 20"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Recipe does not exist in weekly plan!", e.getMessage()); + } + + // Testing negative case (recipe does not exist in recipe list) + try { + String userInput = "weekly /delete unknown 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidRecipeNameException.class, e.getClass()); + assertEquals("Please indicate a valid recipe name.", e.getMessage()); + } + + // Testing negative case (quantity is 0) + try { + String userInput = "weekly /delete salad 0"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity is greater than 1000) + try { + String userInput = "weekly /delete salad 1001"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity is negative) + try { + String userInput = "weekly /delete salad -1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity is not a number) + try { + String userInput = "weekly /delete salad one"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } + + // Testing negative case (quantity is not specified) + try { + String userInput = "weekly /delete salad"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (recipe name is not specified) + try { + String userInput = "weekly /delete"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (quantity results in integer overflow) + try { + String userInput = "weekly /delete salad 1000000000000000000000000000000000"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + } } @Test - public void testDeleteMultiWeeklyPlan() throws InvalidRecipeNameException, InvalidNegativeValueException { + public void testDeleteMultiWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); - weeklyPlan.put("salad", 1); - weeklyPlan.put("pizza", 3); + weeklyPlan.put("salad", 10); + weeklyPlan.put("pizza", 30); weeklyPlan.put("burger", 100); - // Testing delete recipe from weekly plan - WeeklyPlan recipeMap = parser.parseWeeklyPlan( - new String[]{"weekly", "/multidelete", "/r", "burger", "/q", "1", "/r", "pizza", "/q", "1"}, - recipes); - weeklyPlan.deletePlans(recipeMap); - assertEquals(3, weeklyPlan.size()); - - // Testing specifying the same recipe name twice - recipeMap = parser.parseWeeklyPlan( - new String[]{"weekly", "/multidelete", "/r", "burger", "/q", "50", "/r", "burger", "/q", - "30"}, recipes); - weeklyPlan.deletePlans(recipeMap); - assertEquals(69, (int) weeklyPlan.get("burger")); - - // Testing if case-insensitive - recipeMap = parser.parseWeeklyPlan(new String[]{"weekly", "/multidelete", "/r", "Burger", "/q", "3"}, - recipes); - weeklyPlan.deletePlans(recipeMap); - assertEquals(66, (int) weeklyPlan.get("burger")); - - // Testing exceptions - weeklyPlan.put("pizza", 3); - weeklyPlan.put("burger", 100); - assertThrows(InvalidRecipeNameException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multidelete", "/r", "burgers", "/q", "2"}, recipes)); - - assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multidelete", "burger", "pizza", "salad"}, recipes)); - - assertThrows(IllegalArgumentException.class, () -> parser.parseWeeklyPlan( - new String[]{"weekly", "/multidelete", "/r", "burger", "/q", "1", "/r", "pizza"}, recipes)); + // Testing positive case + try { + String userInput = "weekly /multidelete /r salad /q 1 /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(9, weeklyPlan.get("salad")); + assertEquals(28, weeklyPlan.get("pizza")); + } catch (InvalidRecipeNameException | InvalidValueException e) { + assert false; // Not supposed to throw any exception here + } + + // Testing positive case (case-insensitive) + try { + String userInput = "weekly /multidelete /r SALAD /q 1 /r pIzZa /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(8, weeklyPlan.get("salad")); + assertEquals(26, weeklyPlan.get("pizza")); + } catch (InvalidRecipeNameException | InvalidValueException e) { + assert false; // Not supposed to throw any exception here + } + + // Testing positive case (quantity given exceeds the current quantity) + try { + String userInput = "weekly /multidelete /r salad /q 100 /r pizza /q 100"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assertNull(weeklyPlan.get("salad")); + assertNull(weeklyPlan.get("pizza")); + } catch (InvalidRecipeNameException | InvalidValueException e) { + assert false; // Not supposed to throw any exception here + } + + // Testing negative case (recipe name is not specified) + try { + String userInput = "weekly /multidelete /q 1 /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (quantity is not specified) + try { + String userInput = "weekly /multidelete /r salad /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter the command in the correct format.", e.getMessage()); + } + + // Testing negative case (quantity is not a number) + try { + String userInput = "weekly /multidelete /r salad /q one /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (quantity results in integer overflow) + try { + String userInput = "weekly /multidelete /r salad /q 100000000000000000000000000 /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (quantity is negative) + try { + String userInput = "weekly /multidelete /r salad /q -1 /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (quantity is 0) + try { + String userInput = "weekly /multidelete /r salad /q 0 /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (quantity is greater than 1000) + try { + String userInput = "weekly /multidelete /r salad /q 1001 /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Testing negative case (recipe name is not in the weekly plan) + try { + String userInput = "weekly /multidelete /r randomname /q 1 /r pizza /q 2"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach here + } catch (Exception e) { + assertEquals(InvalidRecipeNameException.class, e.getClass()); + assertEquals("Please indicate a valid recipe name.", e.getMessage()); + } } @Test @@ -362,7 +805,6 @@ public void testListTagAndAddTag() { inputs = new String[]{"list", "/t", "breakfast"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(recipeListToPrint.size(), 2); - assertEquals(recipeListToPrint.get(0).getName(), "pizza"); inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index f6979dcc05..eb65d094dc 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -15,16 +15,16 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | These are the recipes you have (10 recipes): | -| 1. Chicken Rice (4 ingredients) | -| 2. Tomato fritters (8 ingredients) | -| 3. Chicken and mushroom pie (7 ingredients) | -| 4. Seafood paella (10 ingredients) | -| 5. Avocado toast (5 ingredients) | -| 6. Italian sausage orzo soup (13 ingredients) | -| 7. Chicken and mushroom pasta (8 ingredients) | -| 8. Creamy Hummus Pasta (6 ingredients) | -| 9. Ground beef and potato casserole (8 ingredients) | -| 10. Buffalo Chicken Mac 'n' Cheese (8 ingredients) | +| 1. chicken rice (4 ingredients) | +| 2. tomato fritters (8 ingredients) | +| 3. chicken and mushroom pie (7 ingredients) | +| 4. seafood paella (10 ingredients) | +| 5. avocado toast (5 ingredients) | +| 6. italian sausage orzo soup (13 ingredients) | +| 7. chicken and mushroom pasta (8 ingredients) | +| 8. creamy Hummus Pasta (6 ingredients) | +| 9. ground beef and potato casserole (8 ingredients) | +| 10. buffalo chicken mac 'n' cheese (8 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please include at least a tag. | @@ -46,7 +46,7 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes): | -| 1. Italian sausage orzo soup (13 ingredients) | +| 1. italian sausage orzo soup (13 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | There is nothing to list. | @@ -71,7 +71,7 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | These are the recipes you have (1 recipes): | -| 1. Avocado toast (5 ingredients) | +| 1. avocado toast (5 ingredients) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | There is nothing to list. | @@ -97,23 +97,23 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please enter a valid recipe number. You did not enter a recipe number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Name of recipe: Chicken Rice | -| 1. Salt(1) | -| 2. Pepper(1) | -| 3. Chicken(1) | -| 4. Rice(1) | +| Name of recipe: chicken rice | +| 1. pepper(1) | +| 2. chicken(1) | +| 3. salt(1) | +| 4. rice(1) | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You entered -2, which is out of bounds. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please enter a valid recipe number. You entered abc, which is not a number. | +| Please enter a valid recipe number. You entered abc, which is not a valid number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Insufficient number of arguments provided. | +| Index 1 out of bounds for length 1 | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please indicate if you would want to add or delete the recipe from your weekly plan. | +| Please indicate if you would want to add to, delete from, or clear the weekly plan. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please indicate a valid recipe name. | @@ -125,7 +125,7 @@ Welcome to Meal360, your ultimate Recipe Manager! | Your weekly plan is empty! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please enter a valid number as the last argument. | +| Please enter a number between 1 to 1000 for the quantity. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Your weekly plan is empty! | From 989d7c4c6ff87373735431b761e4d9d4bc675a2d Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sun, 2 Apr 2023 17:50:13 +0800 Subject: [PATCH 151/252] Fix random errors with checks --- text-ui-test/EXPECTED.TXT | 31 ------------------------------- text-ui-test/input.txt | 5 ----- 2 files changed, 36 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index eb65d094dc..2ec8fd0089 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -14,19 +14,6 @@ Welcome to Meal360, your ultimate Recipe Manager! | Ingredients loaded successfully. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (10 recipes): | -| 1. chicken rice (4 ingredients) | -| 2. tomato fritters (8 ingredients) | -| 3. chicken and mushroom pie (7 ingredients) | -| 4. seafood paella (10 ingredients) | -| 5. avocado toast (5 ingredients) | -| 6. italian sausage orzo soup (13 ingredients) | -| 7. chicken and mushroom pasta (8 ingredients) | -| 8. creamy Hummus Pasta (6 ingredients) | -| 9. ground beef and potato casserole (8 ingredients) | -| 10. buffalo chicken mac 'n' cheese (8 ingredients) | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- | Please include at least a tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- @@ -45,10 +32,6 @@ Welcome to Meal360, your ultimate Recipe Manager! | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes): | -| 1. italian sausage orzo soup (13 ingredients) | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- @@ -67,13 +50,6 @@ Welcome to Meal360, your ultimate Recipe Manager! | You have modified the recipe(s) in this "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| I'm sorry, but I don't know what that means :-( | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- -| These are the recipes you have (1 recipes): | -| 1. avocado toast (5 ingredients) | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- | There is nothing to list. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- @@ -97,13 +73,6 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please enter a valid recipe number. You did not enter a recipe number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Name of recipe: chicken rice | -| 1. pepper(1) | -| 2. chicken(1) | -| 3. salt(1) | -| 4. rice(1) | ----------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- | Please enter a valid recipe number. You entered -2, which is out of bounds. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 8e0aaf32c1..f0a2ddbdad 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,19 +1,15 @@ -list list /t list /t random tag list /t /t list apple list soup && apple list soup apple -list soup list soup /t list soup && /t list /t tag#1 list /t tag tag#1 << avocado toast >> tag tag#1 << avocado toast << -c -list /t tag#1 list /t tag#1 && tag#2 tag tag#1 >> avocado toast << tag tag#1 >> avocado toast && strawberry>> @@ -21,7 +17,6 @@ tag tag#1 >> avocado toast && strawberry list /t tag#1 list /t tag#1 && tag#2 /t view -view 1 view -2 view abc weekly From 91873c7d071a54730a5a77d69376ae83a48b9354 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 3 Apr 2023 01:26:17 +0800 Subject: [PATCH 152/252] Update JUnit and user docs Add Junit for commands to add, delete and view list of user ingredients. Fix bug where `bye` command not working with trailing or leading whitespaces. Update user docs to explanation for default list of recipes. * Closes #104 * Closes #82 * Closes # 73 --- docs/UserGuide.md | 59 ++- src/main/java/seedu/meal360/Exceptions.java | 13 - .../java/seedu/meal360/IngredientList.java | 16 +- src/main/java/seedu/meal360/Meal360.java | 24 +- src/main/java/seedu/meal360/Parser.java | 136 +++--- src/test/java/seedu/meal360/Meal360Test.java | 442 +++++++++++++++++- 6 files changed, 576 insertions(+), 114 deletions(-) delete mode 100644 src/main/java/seedu/meal360/Exceptions.java diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 43bc8b5ae2..56033a52e4 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -46,9 +46,9 @@ Format: `ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quan Add new recipes to your list. -Format: `add /r [recipe_name]` +Format: `add /r [RECIPE_NAME]` -* `recipe_name` is basically a string. +* `RECIPE_NAME` is basically a string. * Type the recipe name after typing `/r `. Example of usage: @@ -60,9 +60,9 @@ Example of usage: Edit recipes in your list partially, fully or add new ingredients to already existing recipe. -Format: `edit /r [recipe_name]` +Format: `edit /r [RECIPE_NAME]` -* `recipe_name` is basically a string. +* `RECIPE_NAME` is basically a string. * Type the recipe name after typing `/r `. * If you want to edit fully: press 1, edit partially: press 2, or add new ingredients: press 3. * Follow the proper format while editing/adding ingredients. @@ -205,16 +205,18 @@ Example of usage: Deletes an existing recipe from this week's plan. -Format: `weekly /delete RECIPE_NAME` +Format: `weekly /delete RECIPE_NAME QUANTITY` -* Deletes the specified `RECIPE_NAME` to this week's plan. +* Deletes the specified `RECIPE_NAME` from this week's plan `QUANTITY` number of times. * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive integer** between 1 and 1000. +* Indicating a quantity more than the current quantity deletes the recipe completely from + this week's plan. Example of usage: -* `weekly /delete pizza` removes pizza from this week's plan. +* `weekly /delete pizza 1` removes pizza from this week's plan once. ### Deleting multiple recipes from this week's plan: `weekly /multidelete` @@ -228,6 +230,8 @@ Format: `weekly /multidelete [/r RECIPE_NAME /q QUANTITY]` * The recipe name refers to the name of the recipe shown in the displayed recipe list. * The quantity **must be a positive integer** between 1 and 1000. +* Indicating a quantity more than the current quantity deletes the recipe completely from + this week's plan. * If the same recipe is specified multiple times, only the **last** quantity specified will be used. @@ -243,6 +247,22 @@ Clears this week's plan by removing all recipes listed in weekly plan. Format: `weekly /clear` +### Mark recipe in this week's plan as done: `weekly /done` + +Mark a recipe in the weekly plan as completed. A single count of the recipe and its corresponding +ingredients will be removed from the weekly plan and the list of ingredients. + +Format: `weekly /done RECIPE_NAME` + +* This command executes only if the user has sufficient ingredients to prepare the recipe. +* This command executes only if the recipe is in the weekly plan. +* The recipe name refers to the name of the recipe shown in the displayed recipe list. + +Example of usage: + +* `weekly /done pizza` will mark pizza as done in the weekly plan, assuming the user has `pizza` in + the weekly plan and there are sufficient ingredients. + ### View this week's plan: `weeklyplan` View this week's plan. @@ -255,12 +275,6 @@ View this week's ingredients. Format: `weeklyingredients` -### View user total list of ingredients: `view_ingredients` - -View list of all ingredients that users have. - -Format: `view_ingredients` - ### Random a recipe: `random` Random a recipe from all the recipes that user have, and show the list of @@ -280,8 +294,10 @@ Add user's ingredients into the ingredient list. Format : `add_i /n INGREDIENT_NAME /c QUANTITY /d DATE` * The quantity **must be a positive - integer** 1,2,3, ... + integer** between 1 and 1000. * The date **must be in the format of DD/MM/YYYY** +* If the ingredient already exists in the list, the quantity will be added to the existing quantity, + while the expiry date will be updated to reflect the expiry date of the new addition. Example of usage: @@ -294,7 +310,9 @@ Format : `del_i /n INGREDIENT_NAME /c QUANTITY` * The quantity has to be **less than or equal** to the quantity of the ingredient in the list. * The quantity **must be a positive - integer** 1,2,3, ... + integer** between 1 and 1000. +* Indicating a quantity more than the current quantity deletes the ingredient completely from + the list. Example of usage: @@ -309,19 +327,20 @@ Format : `view_ingredients` | Action | Format, Examples | |------------------------------------|-------------------------------------------------------------------------------------------------------------| -| Add recipe | `add /r [recipe_name]`
e.g `add /r chicken rice` | -| Edit recipe | `edit /r [recipe_name]`
e.g `edit /r chicken rice` | +| Add recipe | `add /r [RECIPE_NAME]`
e.g `add /r chicken rice` | +| Edit recipe | `edit /r [RECIPE_NAME]`
e.g `edit /r chicken rice` | | List recipe | `list [/t] [KEYWORD]`
e.g `list pizza` | | View recipe | `view INDEX`
e.g `view 1` | | Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | | Remove tag/Categorise from recipes | `tag LABEL >> RECIPE_NAME`
e.g `tag western >> pizza` | | Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | | Add multiple to weekly plan | `weekly /multiadd [/r RECIPE NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 3` | -| Delete from weekly plan | `weekly /delete RECIPE NAME`
e.g `weekly /delete pizza` | -| Delete multiple from weekly plan | `weekly /multidelete [/r RECIPE NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 4` | +| Delete from weekly plan | `weekly /delete RECIPE_NAME`
e.g `weekly /delete pizza` | +| Delete multiple from weekly plan | `weekly /multidelete [/r RECIPE_NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 4` | +| Clear weekly plan | `weekly /clear` | +| Mark recipe in weekly plan as done | `weekly /done RECIPE_NAME`
e.g `weekly /done pizza` | | View weekly plan | `weeklyplan` | | View weekly ingredients | `weeklyingredients` | | View user ingredients | `view_ingredients` | | Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Rice /c 100 /d 04/09/2023` | | Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Rice /c 50` | -| Mark plan as completed | `weeklydone NAME`
e.g `weeklydone chicken rice` | diff --git a/src/main/java/seedu/meal360/Exceptions.java b/src/main/java/seedu/meal360/Exceptions.java deleted file mode 100644 index 7d555a9c90..0000000000 --- a/src/main/java/seedu/meal360/Exceptions.java +++ /dev/null @@ -1,13 +0,0 @@ -package seedu.meal360; - -public class Exceptions { - - // ingredient not found exception - public static class IngredientNotFoundException extends Exception { - - public IngredientNotFoundException() { - super("Ingredient not found"); - } - } - -} diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index afb31ca96c..c82d1ceb23 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -25,7 +25,14 @@ public LocalDate findExpiryDate(String ingredientName) throws IngredientNotFound } public void addIngredient(Ingredient ingredient) { - super.put(ingredient.ingredientName, ingredient); + if (this.containsKey(ingredient.ingredientName)) { + int currentCount = this.get(ingredient.ingredientName).ingredientCount; + int newCount = currentCount + ingredient.ingredientCount; + this.put(ingredient.ingredientName, + new Ingredient(ingredient.ingredientName, newCount, ingredient.expiryDate)); + } else { + this.put(ingredient.ingredientName, ingredient); + } } public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) @@ -46,11 +53,8 @@ public void deleteIngredient(String ingredient, Integer ingredientCount) int newCount = currentCount - ingredientCount; if (newCount > 0) { this.put(ingredient, new Ingredient(ingredient, newCount, this.get(ingredient).expiryDate)); - } else if (newCount == 0) { - this.remove(ingredient); } else { - throw new IllegalArgumentException( - "Number of ingredients to delete exceeds the number " + "of ingredients available!"); + this.remove(ingredient); } } else { throw new IngredientNotFoundException("Ingredient not found"); @@ -85,7 +89,7 @@ public void printExpiredIngredients() { } } if (expiredIngredients.equals("")) { - System.out.println("No expired ingredients"); + System.out.println("No expired ingredients."); } else { System.out.println(expiredIngredients); } diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index d47543f74a..e6f0f162d2 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -65,7 +65,7 @@ public static void startApp() { public static void receiveInput(String input) { String[] command = parser.cleanUserInput(input); - if (input.equalsIgnoreCase("bye")) { + if (input.trim().equalsIgnoreCase("bye")) { canExit = true; } else if (command[0].equals("delete")) { ui.printSeparator(); @@ -180,25 +180,20 @@ public static void receiveInput(String input) { weeklyPlan.clearPlan(); ui.printMessage("I've cleared your entire weekly plan!"); break; + case "/done": + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipeList); + ui.printMessage("I've recorded that you've done this recipe!"); + ui.printMessage("Ingredients list has been updated accordingly!"); + break; default: ui.printMessage("Please enter a valid command."); break; } } catch (IllegalArgumentException | InvalidValueException | InvalidRecipeNameException | - ArrayIndexOutOfBoundsException e) { + ArrayIndexOutOfBoundsException | IngredientNotFoundException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); - } else if (command[0].equals("weeklydone")) { - ui.printSeparator(); - try { - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipeList); - ui.printMessage("I've recorded that you've done this recipe!"); - ui.printMessage("Ingredients list has been updated accordingly!"); - } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException | - IngredientNotFoundException e) { - ui.printMessage(e.getMessage()); - } } else if (command[0].equals("available")) { // list recipes with ingredients all in ingredient list ui.printSeparator(); @@ -218,7 +213,7 @@ public static void receiveInput(String input) { try { parser.parseAddUserIngredients(command, userIngredients); ui.printMessage("Ingredient successfully added!"); - } catch (IllegalArgumentException | IndexOutOfBoundsException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | InvalidValueException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -227,7 +222,8 @@ public static void receiveInput(String input) { try { parser.parseDeleteUserIngredients(command, userIngredients); ui.printMessage("Ingredients successfully deleted!"); - } catch (IllegalArgumentException | IndexOutOfBoundsException | IngredientNotFoundException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | IngredientNotFoundException | + InvalidValueException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 1de6574c06..0ba2d24fd0 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -504,8 +504,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes // Checks that command is entered in the correct if (startIndices.size() != endIndices.size() || startIndices.size() == 0) { - throw new IllegalArgumentException( - "Please enter the command in the correct format."); + throw new IllegalArgumentException("Please enter the command in the correct format."); } // Building the recipe names @@ -549,38 +548,49 @@ public LocalDate parseDate(String input) { try { return LocalDate.parse(input, formatter); } catch (DateTimeParseException e) { - throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy"); + throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy."); } } - public void parseAddUserIngredients(String[] command, IngredientList ingredientList) { + public void parseAddUserIngredients(String[] command, IngredientList ingredientList) + throws InvalidValueException { String ingredientName = null; Integer ingredientCount = null; String expiryDate = null; - try { - for (int i = 1; i < command.length; i++) { - switch (command[i]) { - case "/n": - ingredientName = command[++i]; - break; - case "/c": - ingredientCount = Integer.parseInt(command[++i]); - if (ingredientCount < 0 || ingredientCount > 1000) { - throw new IllegalArgumentException( - "Please enter a positive number between 1 to 1000 for the quantity."); + for (int i = 1; i < command.length; i++) { + switch (command[i]) { + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); } - break; - case "/d": - expiryDate = command[++i]; - break; - default: - throw new IllegalArgumentException("Missing required information. Please provide " - + "ingredient name, count, and expiry date."); + nameBuilder.append(command[i]); } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + break; + case "/d": + expiryDate = command[++i]; + break; + default: + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name, count, and expiry date."); } - } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { - throw new IllegalArgumentException("Invalid command format. Please check your input."); } if (ingredientName == null || ingredientCount == null || expiryDate == null) { @@ -590,31 +600,42 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL ingredientList.addIngredient(new Ingredient(ingredientName, ingredientCount, expiryDate)); } + public void parseDeleteUserIngredients(String[] command, IngredientList userIngredients) - throws IngredientNotFoundException { + throws IngredientNotFoundException, InvalidValueException { String ingredientName = null; Integer ingredientCount = null; - try { - for (int i = 1; i < command.length; i++) { - switch (command[i]) { - case "/n": - ingredientName = command[++i]; - break; - case "/c": - ingredientCount = Integer.parseInt(command[++i]); - if (ingredientCount < 0) { - throw new IllegalArgumentException( - "Please enter a positive number for the quantity."); + for (int i = 1; i < command.length; i++) { + switch (command[i]) { + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); } - break; - default: - throw new IllegalArgumentException( - "Missing required information. Please provide " + "ingredient name and count."); + nameBuilder.append(command[i]); + } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); } + break; + default: + throw new IllegalArgumentException( + "Missing required information. Please provide " + "ingredient name and count."); } - } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { - throw new IllegalArgumentException("Invalid command format. Please check your input."); } if (ingredientName == null || ingredientCount == null) { @@ -624,14 +645,15 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr userIngredients.deleteIngredient(ingredientName, ingredientCount); } + public void parseMarkDone(String[] command, IngredientList userIngredients, WeeklyPlan weeklyPlan, - RecipeList recipes) throws IngredientNotFoundException { - if (command.length == 1) { + RecipeList recipes) throws IngredientNotFoundException, InvalidRecipeNameException { + if (command.length == 2) { throw new IllegalArgumentException("Please enter a recipe name."); } - String recipeName = combineWords(command, 1, command.length); + String recipeName = combineWords(command, 2, command.length); if (recipes.findByName(recipeName) == null) { - throw new IllegalArgumentException("Please enter a valid recipe name."); + throw new InvalidRecipeNameException("Please enter a valid recipe name."); } if (weeklyPlan.get(recipeName) == null) { @@ -639,22 +661,24 @@ public void parseMarkDone(String[] command, IngredientList userIngredients, Week } HashMap ingredients = recipes.findByName(recipeName).getIngredients(); - try { - for (String ingredient : ingredients.keySet()) { - int currentCount = userIngredients.findIngredientCount(ingredient); - if (currentCount < ingredients.get(ingredient)) { - throw new IllegalArgumentException( - "You do not have enough ingredients to mark this recipe as done."); - } + for (String ingredient : ingredients.keySet()) { + int currentCount = userIngredients.findIngredientCount(ingredient); + if (currentCount < ingredients.get(ingredient)) { + throw new IllegalArgumentException( + "You do not have enough ingredients to mark this recipe as done."); } - } catch (IngredientNotFoundException e) { - throw new IllegalArgumentException( - "You do not have enough ingredients to mark this recipe as done."); } // If all ingredients are present, mark recipe as done for (String ingredient : ingredients.keySet()) { userIngredients.deleteIngredient(ingredient, ingredients.get(ingredient)); } + + // Remove count of recipe from weekly plan + if (weeklyPlan.get(recipeName) == 1) { + weeklyPlan.remove(recipeName); + } else { + weeklyPlan.put(recipeName, weeklyPlan.get(recipeName) - 1); + } } } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index b45c793f09..a3ed301b97 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import seedu.meal360.exceptions.IngredientNotFoundException; import seedu.meal360.exceptions.InvalidRecipeNameException; import seedu.meal360.exceptions.InvalidValueException; import seedu.meal360.storage.Database; @@ -25,7 +26,7 @@ class Meal360Test { private static final Database database = new Database(); - private static final IngredientList userIngredients = new IngredientList(); + private static IngredientList userIngredients = new IngredientList(); private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; @@ -62,14 +63,48 @@ public void setUpRecipes() { saladIngredients.put("cucumber", 1); Recipe salad = new Recipe("salad", saladIngredients); + HashMap chickenRiceIngredients = new HashMap<>(); + chickenRiceIngredients.put("rice", 1); + chickenRiceIngredients.put("chicken", 1); + Recipe chickenRice = new Recipe("chicken rice", chickenRiceIngredients); + recipes.addRecipe(burger); recipes.addRecipe(pizza); recipes.addRecipe(salad); + recipes.addRecipe(chickenRice); + + // Adding of ingredients + Ingredient buns = new Ingredient("buns", 10, "10/10/2024"); + Ingredient meatPatty = new Ingredient("meat patty", 10, "10/10/2024"); + Ingredient lettuce = new Ingredient("lettuce", 10, "10/10/2024"); + Ingredient dough = new Ingredient("dough", 10, "10/10/2024"); + Ingredient tomatoSauce = new Ingredient("tomato sauce", 10, "10/10/2024"); + Ingredient cheese = new Ingredient("cheese", 10, "10/10/2024"); + Ingredient pepperoni = new Ingredient("pepperoni", 10, "10/10/2024"); + Ingredient tomato = new Ingredient("tomato", 10, "10/10/2024"); + Ingredient cucumber = new Ingredient("cucumber", 10, "10/10/2024"); + Ingredient rice = new Ingredient("rice", 10, "10/10/2024"); + Ingredient chicken = new Ingredient("chicken", 10, "10/10/2024"); + Ingredient peasandcorn = new Ingredient("peas and corn", 10, "10/10/2024"); + + userIngredients.addIngredient(buns); + userIngredients.addIngredient(meatPatty); + userIngredients.addIngredient(lettuce); + userIngredients.addIngredient(dough); + userIngredients.addIngredient(tomatoSauce); + userIngredients.addIngredient(cheese); + userIngredients.addIngredient(pepperoni); + userIngredients.addIngredient(tomato); + userIngredients.addIngredient(cucumber); + userIngredients.addIngredient(rice); + userIngredients.addIngredient(chicken); + userIngredients.addIngredient(peasandcorn); } @AfterEach public void tearDownRecipes() { recipes = new RecipeList(); + userIngredients = new IngredientList(); } @Test @@ -176,7 +211,7 @@ public void testAddWeeklyPlan() { assert false; } - // Testing case-insensitive + // Testing positive case (case-insensitive) try { String userInput = "weekly /add BURGER 1"; String[] command = parser.cleanUserInput(userInput); @@ -188,6 +223,18 @@ public void testAddWeeklyPlan() { assert false; } + // Testing positive case (name with space) + try { + String userInput = "weekly /add chicken rice 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("chicken rice")); + assertEquals(1, (int) weeklyPlan.get("chicken rice")); + } catch (Exception e) { + assert false; + } + // Testing negative case (recipe does not exist in recipe list) try { String userInput = "weekly /add chicken 1"; @@ -339,6 +386,20 @@ public void testAddMultiWeeklyPlan() { assert false; } + // Testing case where recipe name has space + try { + String userInput = "weekly /multiadd /r burger /q 1 /r chicken rice /q 20"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assertTrue(weeklyPlan.containsKey("burger")); + assertEquals(23, (int) weeklyPlan.get("burger")); + assertTrue(weeklyPlan.containsKey("chicken rice")); + assertEquals(20, (int) weeklyPlan.get("chicken rice")); + } catch (Exception e) { + assert false; + } + // Testing negative case (quantity is negative) try { String userInput = "weekly /multiadd /r burger /q -1 /r pizza /q 5"; @@ -433,6 +494,7 @@ public void testDeleteWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); weeklyPlan.put("salad", 10); weeklyPlan.put("pizza", 30); + weeklyPlan.put("chicken rice", 10); // Testing positive cases try { @@ -456,6 +518,17 @@ public void testDeleteWeeklyPlan() { assert false; // Not supposed to throw any exception here } + // Testing case where recipe name has space + try { + String userInput = "weekly /delete chicken rice 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(9, weeklyPlan.get("chicken rice")); + } catch (InvalidRecipeNameException | InvalidValueException e) { + assert false; // Not supposed to throw any exception here + } + // Testing negative case (recipe exist in recipe list but not in weekly plan) try { String userInput = "weekly /delete burger 20"; @@ -571,6 +644,7 @@ public void testDeleteMultiWeeklyPlan() { weeklyPlan.put("salad", 10); weeklyPlan.put("pizza", 30); weeklyPlan.put("burger", 100); + weeklyPlan.put("chicken rice", 50); // Testing positive case try { @@ -608,6 +682,17 @@ public void testDeleteMultiWeeklyPlan() { assert false; // Not supposed to throw any exception here } + // Testing positive case (recipe name has space) + try { + String userInput = "weekly /multidelete /r chicken rice /q 1"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assertEquals(49, weeklyPlan.get("chicken rice")); + } catch (InvalidRecipeNameException | InvalidValueException e) { + assert false; // Not supposed to throw any exception here + } + // Testing negative case (recipe name is not specified) try { String userInput = "weekly /multidelete /q 1 /r pizza /q 2"; @@ -722,8 +807,7 @@ public void testClearWeeklyPlan() { } @Test - public void testViewIngredients() { - + public void testViewWeeklyIngredients() { HashMap pastaIngredients = new HashMap<>(); pastaIngredients.put("penne", 1); Recipe pasta = new Recipe("pasta", pastaIngredients); @@ -761,7 +845,7 @@ public void testListRecipe() { inputs = new String[]{"list"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(3, recipeListToPrint.size()); + assertEquals(4, recipeListToPrint.size()); assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); assertEquals(4, recipeListToPrint.get(1).getNumOfIngredients()); assertEquals(3, recipeListToPrint.get(2).getNumOfIngredients()); @@ -884,6 +968,354 @@ public void testRandomRecipe() { assertNotNull(recipes.randomRecipe()); } + @Test + public void testWeeklyDone() { + WeeklyPlan weeklyPlan = new WeeklyPlan(); + weeklyPlan.put("pizza", 100); + weeklyPlan.put("burger", 100); + weeklyPlan.put("chicken rice", 100); + + // Testing positive case + try { + String userInput = "weekly /done burger"; + String[] command = parser.cleanUserInput(userInput); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + assertEquals(8, userIngredients.findIngredientCount("buns")); + assertEquals(9, userIngredients.findIngredientCount("meat patty")); + assertEquals(7, userIngredients.findIngredientCount("lettuce")); + assertEquals(99, weeklyPlan.get("burger")); + } catch (Exception e) { + assert false; + } + + // Testing positive case (case-insensitive) + try { + String userInput = "weekly /done Pizza"; + String[] command = parser.cleanUserInput(userInput); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + assertEquals(9, userIngredients.findIngredientCount("dough")); + assertEquals(9, userIngredients.findIngredientCount("tomato sauce")); + assertEquals(9, userIngredients.findIngredientCount("cheese")); + assertEquals(9, userIngredients.findIngredientCount("pepperoni")); + assertEquals(99, weeklyPlan.get("pizza")); + } catch (Exception e) { + assert false; + } + + // Testing positive case (entire command case-insensitive) + try { + String userInput = "WEEKLY /DONE pizza"; + String[] command = parser.cleanUserInput(userInput); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + assertEquals(8, userIngredients.findIngredientCount("dough")); + assertEquals(8, userIngredients.findIngredientCount("tomato sauce")); + assertEquals(8, userIngredients.findIngredientCount("cheese")); + assertEquals(8, userIngredients.findIngredientCount("pepperoni")); + assertEquals(98, weeklyPlan.get("pizza")); + } catch (Exception e) { + assert false; + } + + // Testing positive case (recipe name with space) + try { + String userInput = "weekly /done chicken rice"; + String[] command = parser.cleanUserInput(userInput); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + assertEquals(9, userIngredients.findIngredientCount("chicken")); + assertEquals(9, userIngredients.findIngredientCount("rice")); + assertEquals(99, weeklyPlan.get("chicken rice")); + } catch (Exception e) { + assert false; + } + + // Testing negative case (recipe not found) + try { + String userInput = "weekly /done pizzaandburgers"; + String[] command = parser.cleanUserInput(userInput); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(InvalidRecipeNameException.class, e.getClass()); + assertEquals("Please enter a valid recipe name.", e.getMessage()); + } + + // Testing negative case (recipe not in weekly plan) + try { + String userInput = "weekly /done salad"; + String[] command = parser.cleanUserInput(userInput); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Recipe does not exist in weekly plan.", e.getMessage()); + } + + // Testing negative case (not enough ingredients) + try { + String userInput = "weekly /done burger"; + String[] command = parser.cleanUserInput(userInput); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("You do not have enough ingredients to mark this recipe as done.", e.getMessage()); + } + } + + @Test + public void testAddUserIngredients() { + + // Test positive case (new ingredient) + try { + String userInput = "add_i /n fish /c 10 /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assertEquals(10, userIngredients.findIngredientCount("fish")); + } catch (Exception e) { + assert false; + } + + // Test positive case (ingredient name already exists) + try { + String userInput = "add_i /n chicken /c 10 /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assertEquals(20, userIngredients.findIngredientCount("chicken")); + } catch (Exception e) { + assert false; + } + + // Test positive case (case-insensitive) + try { + String userInput = "add_i /n CHICKEN /c 10 /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assertEquals(30, userIngredients.findIngredientCount("chicken")); + } catch (Exception e) { + assert false; + } + + // Test positive case (expiry date gets updated) + try { + String userInput = "add_i /n chicken /c 10 /d 21/10/2025"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assertEquals(40, userIngredients.findIngredientCount("chicken")); + assertEquals(parser.parseDate("21/10/2025"), userIngredients.findExpiryDate("chicken")); + } catch (Exception e) { + assert false; + } + + // Test positive case (ingredient name with spaces) + try { + String userInput = "add_i /n peas and corn and carrot /c 10 /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assertEquals(10, userIngredients.findIngredientCount("peas and corn and carrot")); + } catch (Exception e) { + assert false; + } + + // Test negative case (quantity is 0) + try { + String userInput = "add_i /n chicken /c 0 /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (quantity is negative) + try { + String userInput = "add_i /n chicken /c -10 /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (quantity is more than 1000) + try { + String userInput = "add_i /n chicken /c 1001 /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (quantity is not a number) + try { + String userInput = "add_i /n chicken /c abc /d 10/10/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (expiry date is not in the correct format) + try { + String userInput = "add_i /n chicken /c 10 /d 10/10/202"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter a valid date in the format dd/mm/yyyy.", e.getMessage()); + } + + // Test negative case (expiry date is not a valid date) + try { + String userInput = "add_i /n chicken /c 10 /d 10/13/2024"; + String[] command = parser.cleanUserInput(userInput); + parser.parseAddUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please enter a valid date in the format dd/mm/yyyy.", e.getMessage()); + } + } + + @Test + public void testDeleteUserIngredients() { + + // Test positive case + try { + String userInput = "del_i /n chicken /c 5"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assertEquals(5, userIngredients.findIngredientCount("chicken")); + } catch (Exception e) { + assert false; + } + + // Test positive case (case-insensitive) + try { + String userInput = "del_i /n CHEESE /c 5"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assertEquals(5, userIngredients.findIngredientCount("cheese")); + } catch (Exception e) { + assert false; + } + + // Test positive case (ingredient name with spaces) + try { + String userInput = "del_i /n peas and corn /c 5"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assertEquals(5, userIngredients.findIngredientCount("peas and corn")); + } catch (Exception e) { + assert false; + } + + // Test positive case (quantity is more than the current quantity) + try { + String userInput = "del_i /n chicken /c 100"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assertNull(userIngredients.get("chicken")); + } catch (Exception e) { + assert false; + } + + // Test negative case (quantity is 0) + try { + String userInput = "del_i /n chicken /c 0"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (quantity is negative) + try { + String userInput = "del_i /n chicken /c -5"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (quantity is more than 1000) + try { + String userInput = "del_i /n chicken /c 1001"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(InvalidValueException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (quantity is not a number) + try { + String userInput = "del_i /n chicken /c abc"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", + e.getMessage()); + } + + // Test negative case (ingredient name is not found) + try { + String userInput = "del_i /n beef /c 5"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteUserIngredients(command, userIngredients); + assert false; // should not reach here + } catch (Exception e) { + assertEquals(IngredientNotFoundException.class, e.getClass()); + assertEquals("Ingredient not found", e.getMessage()); + } + } + + @Test + public void testNonEmptyListUserIngredients() { + IngredientList testIngredientList = new IngredientList(); + Ingredient buns = new Ingredient("buns", 10, "10/10/2024"); + testIngredientList.addIngredient(buns); + + // Test positive case + ui.printUserIngredients(testIngredientList); + assertEquals( + ui.formatMessage("Here is your ingredient list:") + System.lineSeparator() + ui.formatMessage( + "buns " + "(10) " + "[by:10/10/2024]") + System.lineSeparator(), + outContent.toString()); + } + + @Test + public void testEmptyListUserIngredients() { + IngredientList testIngredientList = new IngredientList(); + + // Testing positive case (no ingredients) + ui.printUserIngredients(testIngredientList); + assertEquals(ui.formatMessage("Your ingredient list is empty!") + System.lineSeparator(), + outContent.toString()); + } + @Test public void testLoadDatabase() { assertDoesNotThrow(database::loadRecipesDatabase); From bdef727f1309fbdae76331b36a425238f4df7265 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 6 Apr 2023 22:12:52 +0800 Subject: [PATCH 153/252] Add junenita-PPP --- docs/team/junenita.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/team/junenita.md diff --git a/docs/team/junenita.md b/docs/team/junenita.md new file mode 100644 index 0000000000..8f4c5abbf7 --- /dev/null +++ b/docs/team/junenita.md @@ -0,0 +1,32 @@ +# JuneNita - Project Portfolio Page + +## Project: Meal360 +### Overview +Meal360 is a desktop app for managing your recipes, optimized for use via a Command Line Interface (CLI) while still +having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management +tasks done faster than traditional GUI apps. + + + +### Summary of Contributions +* __Code contributed__: [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=junenita&breakdown=true) +* __Enhancements implemented__ + * Added `list` feature to list relevant recipes by names or the ingredients + * Added `tag` feature to categorise recipe that users have into groups + * Updated `list` feature to be able to list menu in specific tags + * Added `random` feature to random a recipe for users + * Added exception handler for `list`, `tag`, and `random` features + * Wrote tests for `list`, `tag` and `random` features +* __Documentation__: + * User Guide + * Added documentation for `list`, `tag`, and `random` features + * Developer Guide + * Added documentation for `list`, `tag`, and `random` features + * Added UML diagrams for `list`, `tag`, and `random` features +* __Review/Mentoring contributions__: + * PRs reviewed: [#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20), + [#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30), + [#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48), + [#53](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/53), + [#64](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/64), + [#120](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/120) From 769bcb2ee43685459ce17a774943fe31b6ce82ba Mon Sep 17 00:00:00 2001 From: jaredoong Date: Thu, 6 Apr 2023 22:53:27 +0800 Subject: [PATCH 154/252] Add Jared-PPP Add PPP for Jared and removed the dummy johndoe.md. --- docs/AboutUs.md | 14 ++++----- docs/DeveloperGuide.md | 1 + docs/README.md | 7 +++-- docs/UserGuide.md | 11 +++---- docs/team/jaredoong.md | 68 ++++++++++++++++++++++++++++++++++++++++++ docs/team/johndoe.md | 6 ---- 6 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 docs/team/jaredoong.md delete mode 100644 docs/team/johndoe.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 1421f25773..c2ddf48fb3 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,8 +1,8 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:------------------:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +Display | Name | Github Profile | Portfolio +--------|:------------------:|:--------------------------------------:|:---------: +![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 7219e2decd..e75a702082 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -10,6 +10,7 @@ * [RecipeList Component](#recipelist-component) * [WeeklyPlan Component](#weeklyplan-component) * [Database Component](#database-component) + * [Ingredient Component](#ingredient-component) * [Implementation](#implementation) * [Add Recipes Feature](#add-recipes-feature) * [Edit Recipes Feature](#edit-recipes-feature) diff --git a/docs/README.md b/docs/README.md index bbcc99c1e7..aa1a12e3ef 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,9 @@ -# Duke +# Meal360 -{Give product intro here} +Meal360 is a desktop app for managing your recipes and weekly meal plans, optimized for use via a +Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If +you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI +apps. Useful links: * [User Guide](UserGuide.md) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 56033a52e4..a6cb239819 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,9 +2,10 @@ ## Introduction -Meal360 is a desktop app for managing your recipes, optimized for use via a Command Line Interface ( -CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, -Meal360 can get your recipe management tasks done faster than traditional GUI apps. +Meal360 is a desktop app for managing your recipes and weekly meal plans, optimized for use via a +Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If +you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI +apps. ___ @@ -333,8 +334,8 @@ Format : `view_ingredients` | View recipe | `view INDEX`
e.g `view 1` | | Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | | Remove tag/Categorise from recipes | `tag LABEL >> RECIPE_NAME`
e.g `tag western >> pizza` | -| Add to weekly plan | `weekly /add RECIPE NAME QUANTITY`
e.g `weekly /add pizza 2` | -| Add multiple to weekly plan | `weekly /multiadd [/r RECIPE NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 3` | +| Add to weekly plan | `weekly /add RECIPE_NAME QUANTITY`
e.g `weekly /add pizza 2` | +| Add multiple to weekly plan | `weekly /multiadd [/r RECIPE_NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 3` | | Delete from weekly plan | `weekly /delete RECIPE_NAME`
e.g `weekly /delete pizza` | | Delete multiple from weekly plan | `weekly /multidelete [/r RECIPE_NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 4` | | Clear weekly plan | `weekly /clear` | diff --git a/docs/team/jaredoong.md b/docs/team/jaredoong.md new file mode 100644 index 0000000000..4bdb518753 --- /dev/null +++ b/docs/team/jaredoong.md @@ -0,0 +1,68 @@ +# Jared Oong - Project Portfolio Page + +## Overview + +Meal360 is a desktop app for managing your recipes and weekly meal plans, optimized for use via a +Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If +you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI +apps. + +### Summary of Contributions + +* __Code + contributed__ : [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=jaredoong&breakdown=true) +* __Functions/enhancements implemented__: + * Added viewing of ingredients needed for a recipe based on index in recipe + list. ([#15](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/15)) + * Added functionality to add single/multiple recipes to the weekly + plan. ([#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30), + [#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48)) + * Added functionality to remove single/multiple recipes from the weekly + plan. ([#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30), + [#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48)) + * Added functionality to view the weekly + plan. ([#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30)) + * Added functionality to mark recipes in the weekly plan as + done. ([#74](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/74)) + * Added functionality to add user ingredients to the ingredient + list. ([#64](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/64)) + * Added functionality to remove user ingredients from the ingredient + list. ([#64](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/64)) + * Added functionality to view the ingredient + list. ([#64](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/64)) + * Added loading and saving to + databases. ([#39](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/39)) +* __Contributions to the UG__ ([#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30), + [#74](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/74)): + * Added documentation for the following commands: + * `view INDEX` + * `weekly /add RECIPE_NAME QUANTITY` + * `weekly /multiadd [/r RECIPE_NAME /q QUANTITY]` + * `weekly /delete RECIPE_NAME` + * `weekly /multidelete [/r RECIPE_NAME /q QUANTITY]` + * `weekly /done RECIPE_NAME` + * `weeklyplan` + * `view_ingredients` + * `add_i /n NAME /c COUNT /d DATE` + * `del_i /n NAME /c COUNT` +* __Contributions to the DG__ ([#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48)): + * Updated DG with anchor links for easier navigation. + * Added documentation for the following classes: + * `Database` + * `WeeklyPlan` +* __Contributions to the team-based tasks__: + * Setting up of GitHub team org/repo + * Maintaining issue tracker + * Release management (`v1.0`, `v2.0`) +* __Review/mentoring contributions (with non-trivial comments)__: + * [#14](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/14), + [#26](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/26), + [#32](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/32), + [#34](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/34), + [#45](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/45), + [#51](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/51), + [#60](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/60), + [#70](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/70) +* __Tools__: + * Integrated third party library (GSON) to save and load data from + databases. ([#39](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/39)) \ No newline at end of file diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md deleted file mode 100644 index ab75b391b8..0000000000 --- a/docs/team/johndoe.md +++ /dev/null @@ -1,6 +0,0 @@ -# John Doe - Project Portfolio Page - -## Overview - - -### Summary of Contributions From 5ef6e18f7c15b5e370f27b84339100fc333b6321 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Thu, 6 Apr 2023 23:16:05 +0800 Subject: [PATCH 155/252] update the arrow of the activation bar --- docs/UML/Implementation/TagFunction/TagFunction.drawio | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/UML/Implementation/TagFunction/TagFunction.drawio b/docs/UML/Implementation/TagFunction/TagFunction.drawio index 9c3187ccc7..7630fafd14 100644 --- a/docs/UML/Implementation/TagFunction/TagFunction.drawio +++ b/docs/UML/Implementation/TagFunction/TagFunction.drawio @@ -1,6 +1,6 @@ - + - + @@ -23,7 +23,7 @@ - + @@ -75,7 +75,7 @@ - + From f5ec952d9ec3accc4385479b9912bc6221c8f5ac Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 7 Apr 2023 00:40:30 +0800 Subject: [PATCH 156/252] Update DG Add Architecture and user stories --- docs/DeveloperGuide.md | 146 ++++++++++++------ .../.$ArchitectureExampleUML.drawio.bkp | 1 + .../.$ArchitectureExampleUML.png.bkp | Bin 0 -> 22619 bytes .../Architecture/.$ArchitectureUML.drawio.bkp | 1 + .../ArchitectureExampleUML.drawio | 1 + .../Architecture/ArchitectureExampleUML.png | Bin 0 -> 27120 bytes docs/UML/Architecture/ArchitectureUML.drawio | 1 + docs/UML/Architecture/ArchitectureUML.png | Bin 0 -> 50056 bytes .../IngredientList/IngredientListUML.drawio | 1 + src/main/java/seedu/meal360/Parser.java | 2 + 10 files changed, 105 insertions(+), 48 deletions(-) create mode 100644 docs/UML/Architecture/.$ArchitectureExampleUML.drawio.bkp create mode 100644 docs/UML/Architecture/.$ArchitectureExampleUML.png.bkp create mode 100644 docs/UML/Architecture/.$ArchitectureUML.drawio.bkp create mode 100644 docs/UML/Architecture/ArchitectureExampleUML.drawio create mode 100644 docs/UML/Architecture/ArchitectureExampleUML.png create mode 100644 docs/UML/Architecture/ArchitectureUML.drawio create mode 100644 docs/UML/Architecture/ArchitectureUML.png create mode 100644 docs/UML/IngredientList/IngredientListUML.drawio diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e75a702082..2d826ec040 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -30,8 +30,8 @@ ## Acknowledgements -{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- -include links to the original source as well} +* [GSON](https://github.com/google/gson) library used for saving and loading databases easily in + JSON format. --- @@ -51,14 +51,28 @@ include links to the original source as well} ### Architecture +The Architecture Diagram below shows a high-level design of the Meal360 application: +![](../docs/UML/Architecture/ArchitectureUML.png) + +**How the architecture components interact with each other:** + +Based on the user input, only certain components will be called to execute the command. For example, +if the user inputs `view 1`, the `Parser` component will call the `RecipeList` component to retrieve +the recipe at index 0, following which the `Ui` component will then display it to the user. The +sequence diagram below shows how the +interaction described above: +![](../docs/UML/Architecture/ArchitectureExampleUML.png) ### UI Component + API: `Ui.java` ### Parser Component + API: `Parser.java` ### Recipe Component + API: `Recipe.java` The `Recipe` component: @@ -134,9 +148,13 @@ How the `Database` component works at start up: The activity diagram below shows how the `Database` component works at start up: ![](../docs/UML/Database/DatabaseStartupUML.png) + +### Ingredient Component + --- ## Implementation + * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) * [Add Recipes Feature](#add-recipes-feature) @@ -146,19 +164,25 @@ The activity diagram below shows how the `Database` component works at start up: ### Categorise/Tag Recipes Feature The current implementation: + * add single or multiples recipes into a tag * remove single or multiples recipes from a tag It is implemented through the following step: + 1. When the user enters an input with the first word being `tag`, the input is passed to the `Parser` component. 2. In `Parser`, `parseTagRecipe()` is executed to identify whether user want to add recipes to a tag (`<<`), or remove recipes from a tag(`>>`). Then, - * If `isAddTag`, user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to extract - the all the recipes to be added, separated by `&&`, and pass those recipes and tag label to `RecipeList` + * If `isAddTag`, user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to + extract + the all the recipes to be added, separated by `&&`, and pass those recipes and tag label + to `RecipeList` component. - * If `isRemoveTag`, user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be executed to - extract the all the recipes to be removed, separated by `&&`, and pass those recipes and tag label to + * If `isRemoveTag`, user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be + executed to + extract the all the recipes to be removed, separated by `&&`, and pass those recipes and tag + label to `RecipeList` component. * If user enter invalid command, an error message will be thrown. 3. In `RecipeList`, @@ -174,28 +198,31 @@ The sequence diagram below shows how this feature works: ### List Recipes Feature The current implementation: + * list all recipes * list recipe with filters (name, ingredients, tags) It is implemented through the following step: + 1. When the user enters an input with the first word being `list`, the input is passed to the `Parser` component. 2. In `Parser`, `parseListRecipe()` is executed to first identify whether user want to filter - by tag (`/t`). - * If user filters the recipes by tag (`/t`), `isTag` is set to `true`. - * Otherwise, `isTag` is set to `false`. - - Then, it will extract all the filters separated by `&&`, if any. All the filters are + by tag (`/t`). + * If user filters the recipes by tag (`/t`), `isTag` is set to `true`. + * Otherwise, `isTag` is set to `false`. + + Then, it will extract all the filters separated by `&&`, if any. All the filters are extracted out and passed to `RecipeList`component. 3. In `RecipeList`, `listRecipes()` is executed to first identify whether user want to filter by tag. - * If `isTag` is true, `listTagRecipes()` is called to filter all recipes that meet - all the filters by tag, and return the `recipeList` containing all relevant recipes to `listRecipes()` - and `ParserRecipe()`, respectively. - * If user `isTag` is false, it filters all recipes that meet all the filters by name - and ingredients, and return `recipeList` containing all relevant recipes to - `ParselistRecipe()`. - + * If `isTag` is true, `listTagRecipes()` is called to filter all recipes that meet + all the filters by tag, and return the `recipeList` containing all relevant recipes + to `listRecipes()` + and `ParserRecipe()`, respectively. + * If user `isTag` is false, it filters all recipes that meet all the filters by name + and ingredients, and return `recipeList` containing all relevant recipes to + `ParselistRecipe()`. + The sequence diagram below shows how this feature works: ![](../docs/UML/Implementation/ListFunction/ListFunction.png) @@ -203,16 +230,20 @@ The sequence diagram below shows how this feature works: ### Delete Recipes Feature The current implementation: + * deletes a single recipe by name or recipe's index in recipe list * deletes a range of recipes * deletes all recipes It is implemented through the following step: + 1. When the user enters an input with the first word being `delete`, the input is passed to the `Parser` component. -2. In `Parser`, `parseDeleteRecipe()` is executed to identify whether the user wants to delete all recipes, a single +2. In `Parser`, `parseDeleteRecipe()` is executed to identify whether the user wants to delete all + recipes, a single recipe, or range of recipes. -3. In `RecipeList`, `deleteRecipe()` is executed to delete the recipe at whatever index is passed as a parameter, +3. In `RecipeList`, `deleteRecipe()` is executed to delete the recipe at whatever index is passed as + a parameter, and return the `Recipe` object at that index/the one just deleted. ![](../docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg) @@ -220,20 +251,28 @@ It is implemented through the following step: ### Add Recipes Feature The current implementation: -* Add a single recipe in 1 line and followed by all the ingredients in next another line after being prompted. + +* Add a single recipe in 1 line and followed by all the ingredients in next another line after being + prompted. It is implemented through the following steps: -1. When the user enters an input with the first word being `add`, the input is passed to the `Parser` component. -2. In `Parser`, the `parseAddRecipe` is executed to identify whether the recipe is an already existing recipe or + +1. When the user enters an input with the first word being `add`, the input is passed to + the `Parser` component. +2. In `Parser`, the `parseAddRecipe` is executed to identify whether the recipe is an already + existing recipe or it's a new recipe that is being added. -3. After the user enters the ingredients in 1 line, the input is passed to `parseIngredientName` which returns a +3. After the user enters the ingredients in 1 line, the input is passed to `parseIngredientName` + which returns a hashmap with the ingredient name as 'key' and quantity as 'value'. -4. After the recipe name and ingredients are accepted and processed, the input is sent to `recipeList.addRecipe()` +4. After the recipe name and ingredients are accepted and processed, the input is sent + to `recipeList.addRecipe()` to store the new recipe data. ### Edit Recipes Feature The current implementation: + * There are 3 ways to edit: * Edit all ingredients. * Edit 1 particular ingredient. @@ -241,21 +280,27 @@ The current implementation: It is implemented through the following steps: -1. When the user enters an input with the first word being `edit`, the input is passed to the `Parser` component. -2. In `Parser`, the `parseEditRecipe` is executed to identify whether the recipe is an already existing recipe to make edits. -3. The user will then be prompted with 3 options as mentioned above to make edits to the recipe ingredients. -4. After the new ingredients are accepted and processed, the input is sent to `recipeList.editRecipe()` +1. When the user enters an input with the first word being `edit`, the input is passed to + the `Parser` component. +2. In `Parser`, the `parseEditRecipe` is executed to identify whether the recipe is an already + existing recipe to make edits. +3. The user will then be prompted with 3 options as mentioned above to make edits to the recipe + ingredients. +4. After the new ingredients are accepted and processed, the input is sent + to `recipeList.editRecipe()` to update the new recipe data. ### Random a Recipe Feature The current implementation: + * randomly pick a recipe and display to the user It is implemented through the following step: -1. When the user enters an input with the first word being `random`, the `Parser` + +1. When the user enters an input with the first word being `random`, the `Parser` component will be executed. -2. In `Parser`, `parseRandomRecipe()` is executed and call `randomRecipe()` in +2. In `Parser`, `parseRandomRecipe()` is executed and call `randomRecipe()` in `RecipeList` component. 3. In `RecipeList`, `randomRecipe()` is executed to random a recipe and return a `recipe` to `parseRandomRecipe()`. @@ -264,6 +309,7 @@ The sequence diagram below shows how this feature works: ![](../docs/UML/Implementation/RandomFunction/RandomFunction.png) --- + ## Appendix: Requirements ### Product scope @@ -284,29 +330,33 @@ driven app. ### User Stories -| Version | As a ... | I want to ... | So that I can ... | -|---------|----------|---------------------------------------------------|-------------------------------------------------------------------| -| v1.0 | user | add my own recipes to the list | refer to them when next time | -| v1.0 | user | edit the existing recipe | | -| v1.0 | user | delete a recipe from the list | clear the unused recipes | -| v1.0 | user | view ingredients of the recipe | know what is needed to be prepared | -| v1.0 | user | list all recipes I have | know what I have some idea of what to cook | -| v1.0 | user | find the recipe that contain specific ingredients | find specific recipe without having to go through the entire list | -| v1.0 | user | exit from the program | | -| v2.0 | new user | list all the command that can be used | know what command I can use | -| v2.0 | user | add meals I plan to make for the week | refer to the weekly meals plan next time | -| v2.0 | user | delete meals I plan to make for the week | remove some meals from the weekly plan if I change my mind | -| v2.0 | user | categorise recipes using tags | group recipes with similar theme together | -| v2.0 | user | list the recipes by tag | list recipes that are under the specific category | -| v2.0 | user | random a recipe | have a suggestion when do not know what to cook | +| Version | As a ... | I want to ... | So that I can ... | +|----------|----------|---------------------------------------------------|-------------------------------------------------------------------| +| v1.0 | user | add my own recipes to the list | refer to them when next time | +| v1.0 | user | edit the existing recipe | | +| v1.0 | user | delete a recipe from the list | clear the unused recipes | +| v1.0 | user | view ingredients of the recipe | know what is needed to be prepared | +| v1.0 | user | list all recipes I have | know what I have some idea of what to cook | +| v1.0 | user | find the recipe that contain specific ingredients | find specific recipe without having to go through the entire list | +| v1.0 | user | exit from the program | | +| v2.0 | new user | list all the command that can be used | know what command I can use | +| v2.0 | user | add meals I plan to make for the week | refer to the weekly meals plan next time | +| v2.0 | user | delete meals I plan to make for the week | remove some meals from the weekly plan if I change my mind | +| v2.0 | user | categorise recipes using tags | group recipes with similar theme together | +| v2.0 | user | list the recipes by tag | list recipes that are under the specific category | +| v2.0 | user | random a recipe | have a suggestion when do not know what to cook | +| v2.0 | user | know what ingredients I have | know what ingredients I need to buy | +| v2.0 | user | add the ingredients I have | easily track the ingredients I have | +| v2.0 | user | delete the ingredients I have | easily track the ingredients I have | +| v2.0 | user | be able to cross recipes off my weekly plan | have a neater weekly plan | ### Non-Functional Requirements -{Give non-functional requirements} +1. Should work on any *mainstream OS* as long as it has Java 11 or above installed. ### Glossary -* *glossary item* - Definition +* **Mainstream OS**: Windows, Linux, Unix, OS-X ### Instructions for manual testing diff --git a/docs/UML/Architecture/.$ArchitectureExampleUML.drawio.bkp b/docs/UML/Architecture/.$ArchitectureExampleUML.drawio.bkp new file mode 100644 index 0000000000..ef8f47c11e --- /dev/null +++ b/docs/UML/Architecture/.$ArchitectureExampleUML.drawio.bkp @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/Architecture/.$ArchitectureExampleUML.png.bkp b/docs/UML/Architecture/.$ArchitectureExampleUML.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..b61f2136d6f6f242f60923975920a2c8c3e66c4a GIT binary patch literal 22619 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 literal 0 HcmV?d00001 diff --git a/docs/UML/Architecture/.$ArchitectureUML.drawio.bkp b/docs/UML/Architecture/.$ArchitectureUML.drawio.bkp new file mode 100644 index 0000000000..b1ede881fb --- /dev/null +++ b/docs/UML/Architecture/.$ArchitectureUML.drawio.bkp @@ -0,0 +1 @@ +ddHNEoIgEADgp+GuMJmezfLSyUNnRjZhBl0HabSePh0wY6wTy7fL30JY3k4Xw3t5RQGa0EhMhJ0IpXGWHuZhkaeTLEkdNEYJR9EGlXqBX7nqQwkYvDmyiNqqPsQauw5qGxg3Bsew7I5aBNDzBnZQ1Vzv9aaElV7jJNsSJahG+qNTenSJlq/F/iWD5ALHL2IFYblBtC5qpxz00rywL+c/2c/FDHT2x4I52PaeJ8EPseIN \ No newline at end of file diff --git a/docs/UML/Architecture/ArchitectureExampleUML.drawio b/docs/UML/Architecture/ArchitectureExampleUML.drawio new file mode 100644 index 0000000000..38e24b20ca --- /dev/null +++ b/docs/UML/Architecture/ArchitectureExampleUML.drawio @@ -0,0 +1 @@ +1Vpbc9o4FP41zHQfmpEsXx8D6V5m0t1s03a7j8KWQRNhubII0F9fyRewLRtIMZDkIWMdyZL8ne9ckxGaLNZ/CJzOP/KIsJEFovUI3Y0sy4a2+q0Fm0Jg2W4hmAkaFSKwEzzSH6QQwkq6pBHJSlkhkpwzSdOmMORJQkLZkGEh+Kq5LOYsaghSPCOG4DHEzJT+RyM5L6XQDXYTfxI6m5dH+5ZXTCxwtbj8kmyOI76qidCHEZoIzmXxtFhPCNPYNXH5vWd2ezFBEnnMCz++rZLFD+Q9fv3n899P9prQ8b/vLafY5hmzZfnF5W3lpoJgLhdMPcERGseUsQlnXKhxRGK8ZOrocbkFEZKsey8Ht5+sqEL4gkixUUuqF5wSpU0FcAnjage6h8o18xreKCi/AJeKnm333mGhHko4XgANNJD5SDBDLjAAUppN9eNywe5pTBhN1GicEkHVTYjGipXih51svJpTSR5THOpXV8p4lKwGtSK0xOoVsR0zhtOMTvNTgZIIEi5FRp/JJ5IVdqOlfCn1SZOtPYCW3kYWiv2QhKGSZ1LwJ1KbmfqO7YBhdIoAbOrUsw2dQtCl00o4vE7Bi+iecprI/A7OeOTctZTKhZzzGU8wq6v1BBPpp2EvxrbTgNiHHQibAMMgOBPAloHvAxaZAubN20zkED+yu2zGt6bIdYexGQe6LZtxr24z6M3ZjPUSm4GwC2ITYdc9E8Amvp9ISFNyTzP59u0mjmOrO9ZE7tR1BrIb17FeXaxx35zdoBfZDQqOspsqIR4cYPswvj3WgoWkysJwDoaaU0ROIqyudDVL0tqiquq4ZXSWKJnkeuNMnUOT2Wc9uENun8UNYD/QQU3l+mb+HVzUfI6wHqHVRqIShQOa6baVplNKeM6PQfBs575Wh7F4HVHmXHh6Bp5fDuRlt6HUqGy5eY+nhD3wjErKNUenXEq+6CXvRcpGv0Vb20yAu6rGs6EMzapRGTxR5v5Xki7lu5Hlfl/qin/8TMlKLYQ7yW/7wkMb4y34JIludZ9DyxgPn3KR+pRvpVnkg/8r59OwmOI8ErU6IBKLGdlbkoAePanL86UIySGn3avP9+AGAFQ6dkEYlgq5xgFdGiu3e9ARtBauqhZC1XnyWwlccdfyrXrjpNqoWsjjOCPS4Mb2+ifQxayXTiUBT4maGkc4m+eKhsV02Vnz9WhNpWaHBhvapSBnyE0QuAZL9Ozduj7Y1Aa12LiPUwd5sYdTB/nYw6mB+YNcq7lFcS+DP4Nxw8xvUl1Lf1WOoygQ9nqTkTXJMagqiYt7l4pmilV+g2TQ84ai1WFXhX7dVUFwFl4hx2/6paAVjHr80mC8Mlu+gnxfkkySqODV5VwQaHkf/1rep58mR0bD/SGtyvROdUmoWeWidk+ixyVdNKSZiaa60jtwNf8Db1T23eAZAvblHJB7ggPqqcdPZJHbZhFsbXFuB+S/WgfkHJsjH9Zdv96PDFqD690Dzd4y8ludmTMnNFZg6P0LNVT95hqcAPgYgK4GJwCOl8/E6vhmS1T9DFMBe1Wj8/U0PpFZA+8z6NfQ+CyoeWzn06rShUOdT/tcCL/sTzIXdpm7AH0TWHYjSN94nlMJdrE3H23qo6HyOtRnTyfkdad6YTtokMl20UW9cBX862WlUGeVJWUrEl+zamzwzHXQxXK2Pay5VtHYZo0Ru385Z1PD3f8gFct3/8iFPvwE \ No newline at end of file diff --git a/docs/UML/Architecture/ArchitectureExampleUML.png b/docs/UML/Architecture/ArchitectureExampleUML.png new file mode 100644 index 0000000000000000000000000000000000000000..61b0605110244a1253a4963249d52db2e67dd850 GIT binary patch literal 27120 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 literal 0 HcmV?d00001 diff --git a/docs/UML/Architecture/ArchitectureUML.drawio b/docs/UML/Architecture/ArchitectureUML.drawio new file mode 100644 index 0000000000..0e82a7039a --- /dev/null +++ b/docs/UML/Architecture/ArchitectureUML.drawio @@ -0,0 +1 @@ +5Vvfc5s4EP5r/NgOkkDAY2KnvebSmcxlem0eBcg2LUYeWU5M//oTQRgw2OGXC/Y5D0GLhKXd71vtLvIETVe7z5ysl1+ZR4MJ1LzdBM0mEAKgGfJfLIkSCcYwESy47yUiLRM8+b+pGplKt75HN0qWiARjgfDXRaHLwpC6oiAjnLPXYrc5C7yCYE0WtCR4cklQln73PbFM14Xt7MZf1F8s1Vdb0ExurEjaWa1ksyQee82J0N0ETTljIrla7aY0iJVX1MunI3f3E+M0FHUGOE50/3h3/zta8r///TS9d3+uVx909ZgXEmzVitVsRZSqYClWgbwCE3S7EZz9olMWMC4lIQtll1v1BMoF3R2dG9ivWEKFshUVPJJd1AALJyMUSICOkvZrpnLTVE9d5rSNdEuZWpl5sX90pgl5oZTRRDGN9NKDCgA2izrAuKQDjI2yDqCtnUsHWmnNnG1Dj8aDNLlsxsWSLVhIggfG1koXP6kQkSIy2QomRTlNSW3w6Ica/9Z4jhsfjbQ52+VvziLVSmZCvRJbD/Qr3QPhCypOLMuotgOnARH+S/H5VTpVQx+ZL785sx+yCvZDEBcfsWFb7lI16sAy+2m0N1aZyN82lJcMKL3QOr7croIbV8Q0vo1h60uP90AcGjyyjS98FsouDhOCrXIdbgJ/Ed8Qsa3zRmVbEfih9AupD9Z64oRW9AvQLnMCaWVK4HMxwi7pM0bkk2pmdLjLpLfdKbPzxY+MJLL1nLuT8SVupHTJaJYx67lArGqazf0gSN37BKK55VLXLTl+ecexDN1oRsyEAO8RswaBrY4E7gQBAIbEAMghIMPDexho5movAgNAGxQEaDyOQGvlCMA1gAAPiQHYxhG4W/7yBgHQLyDMNogougV4HX4BDokJhMeKidrhArw+NwHsPiL+G85JlOuwjiP5zfGEAOrFhA7Zdh5fpf7Ygqf6y4tkBr1mDahNRHsewBZDG7NubKN6Xhdgu25s7QB7UIHQlTc7ClhgnOp/HsCqr8yluV8pCRAulypyEGtr9G7Jq3VQENDUI/JFLUW/fPJqnCt5hW2C1nFxvUsu6xFqzSutjl2LOvN+qY4vIl6B+kgh8X9GxLBZjTFSRMDTkLgM03YNRDuZFpe2zhkRxCEb2mDvrK3YXvdOYOrD7p1WSXff/AZawxqxgVmlNTgzsfYGYBaKfIzy9jlTJGIZA0ci5WhtuDS5e+WkYeHEM6jl6VVgsKCDMO7XN6Uv0sceiYypctL9PUvDNHSskBikcIIwKLgrXYd5eJX6mxo81f88eWh6zGMUeG1X6btGwA5SOEGWVtxfbXQSsIaNT/U/D2BTHeZCmEfCq44InAj+6lq9U7iCYJH/gxdO0Hhyol643vQQwHwOq8tlHnaw0TfXYV2um0PGK2i0/r/2+2B4jaAYNMNOp5nzsf9Q11/TB38jGvjZ2srt5Gd1o7htycDr48CJIRpPPTJXcWrkac1OrDLiv8rqytunZ1bVrlsN6mpBuXD1ndJfQbQOSNiEVe8r96AIk3z6YZthHJxlHAHbxlOGaVTr7evlLwUyoK2sytnYRKRvtpmXsYeZR/awBkyrrdhu+5dVfP+MgD0wn+Bo+NQuJgR5MjU/EeYAz5trVWYHmols2jOfrMvgU/nVwZdwwann07BJTFhbuZ04ZcKD0gQc+MULGs8pyz9yaKFPgth1CTLsgXr7BEHeS5x6gPz+F4l/IjCTzewXf0lpL/vdJLr7Dw== \ No newline at end of file diff --git a/docs/UML/Architecture/ArchitectureUML.png b/docs/UML/Architecture/ArchitectureUML.png new file mode 100644 index 0000000000000000000000000000000000000000..27210addbca410bac87faf301530030a6747b45b GIT binary patch literal 50056 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/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 0ba2d24fd0..2899dd6257 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -24,12 +24,14 @@ public String combineWords(String[] input, int startIndex, int length) { return word.toString(); } + //@@author jaredoong public String[] cleanUserInput(String input) { input = input.replaceAll("\\s+", " "); input = input.toLowerCase(); return input.trim().split(" "); } + //@@author public HashMap parseIngredientName(String[] command) { HashMap ingredients = new HashMap<>(); int flag = 0; From 850622092c42240ec9307841bd372527e7e27f98 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 7 Apr 2023 00:52:01 +0800 Subject: [PATCH 157/252] update 'tag' UML pic --- .../TagFunction/TagFunction.png | Bin 46831 -> 48193 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/UML/Implementation/TagFunction/TagFunction.png b/docs/UML/Implementation/TagFunction/TagFunction.png index b990e53b652738842a230889df1e3e26afb456d6..0d8c0dc44bc3c236582eb99e51ec856b33ad4077 100644 GIT binary patch literal 48193 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 KCs)hr*8c%wVORG6 From d54ca583af2a9c7c01a5171899f2d86cac7216fa Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 7 Apr 2023 01:28:36 +0700 Subject: [PATCH 158/252] fix errors with delete feature & add PPP --- docs/team/gurmankalkat.md | 27 ++++++++++++++++++++++++ src/main/java/seedu/meal360/Meal360.java | 5 +++-- src/main/java/seedu/meal360/Parser.java | 20 ++++++++++++++---- src/main/java/seedu/meal360/Ui.java | 4 ++-- 4 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 docs/team/gurmankalkat.md diff --git a/docs/team/gurmankalkat.md b/docs/team/gurmankalkat.md new file mode 100644 index 0000000000..bf05a40ff3 --- /dev/null +++ b/docs/team/gurmankalkat.md @@ -0,0 +1,27 @@ +# Gurman Kalkat - Project Portfolio Page + +## Project: Meal360 +### Overview +Meal360 is a desktop application that helps user organize recipes. The user interacts with it using a Command Line +Interface (CLI). Meal360 can help users manage all their favorite recipes as well as their weekly diet and ingredients. + +### Summary of Contributions +* __Code contributed__: [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=gurmankalkat&breakdown=true) +* __Enhancements implemented__ + * Added `delete` feature to give users the ability to delete a recipe in the list by its index or name + * Added `weeklyingredients` feature to list out all ingredients needed for the week based on user's weeklyplan + * Added `weekly /clear` feature to be able to clear the entire weeklyplan + * Updated `delete` feature so use can delete all or a range of recipes + * Added exception handler for `delete` feature + * Wrote tests for `delete`, `weeklyingredients` and `weekly /clear` features +* __Documentation__: + * User Guide + * Added documentation for `delete`, `weeklyingredients`, and `weekly /clear` features + * Developer Guide + * Added documentation for `delete` feature + * Added UML diagrams for `delete` feature +* __Review/Mentoring contributions__: + * PRs reviewed: [#4](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/4), + [#15](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/15), + [#39](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/39), + diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 5975387eb1..4efe55caf8 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -77,8 +77,9 @@ public static void receiveInput(String input) { ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = - "Please enter a valid recipe number or name. You did not enter a recipe number " - + "or " + "name."; + "Please enter a valid recipe number or name in the correct format. You did not enter a recipe" + + " number " + + "or " + "name. See 'help' for more details."; ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 4f83cc7397..3aac8d83ad 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -179,6 +179,13 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { public String parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name + try { + if (!input[1].equals("/r") && !input[1].contains("-")) { + Integer.parseInt(input[1]); + } + } catch (NumberFormatException e){ + throw new IndexOutOfBoundsException(); + } if (input[1].contains("/r")) { // skip over /r in recipe name String recipeToDelete = ""; @@ -209,19 +216,24 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } else { // deleting a range of recipes if (input[1].length() >= 3) { - String rangeRecipes = ""; - int startIndex = Integer.parseInt(input[1].charAt(0) + ""); - int endIndex = Integer.parseInt(input[1].charAt(2) + ""); + String[] range = input[1].trim().split("-"); + int startIndex = Integer.parseInt(range[0]); + int endIndex = Integer.parseInt(range[1]); startIndex -= 1; endIndex -= 1; + if (startIndex < 0 || endIndex >= recipeList.size() || endIndex < startIndex) { + throw new IndexOutOfBoundsException(); + } int newSize = recipeList.size() - ((endIndex - startIndex) + 1); + String rangeRecipes = ""; while (recipeList.size() != newSize) { rangeRecipes += recipeList.deleteRecipe(startIndex).getName() + ", "; } rangeRecipes = String.valueOf(new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2))); return rangeRecipes; } else { - int recipeIndex = Integer.parseInt(input[1]); + int recipeIndex = Integer.parseInt(input[1]);; + recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based return recipeList.deleteRecipe(recipeIndex - 1).getName(); } diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 88828ecd08..3d25780679 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -104,8 +104,8 @@ public void printHelp() { printMessage("1. Add Recipe: add /r {recipe name}"); printMessage("2. View Recipe: view {index number}"); printMessage("3. Edit Recipe: edit {recipe name}"); - printMessage("4. Delete Recipe: delete {index number} or delete {index range} or"); - printMessage("delete /r {recipe name}or delete /r all"); + printMessage("4. Delete Recipe: delete {index number} or delete {starting index-ending index} or"); + printMessage("delete /r {recipe name} or delete /r all"); printMessage("5. List All Recipes: list"); printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); From f4f89829cf1b1c170d325325df41fbc298795062 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 7 Apr 2023 01:28:55 +0700 Subject: [PATCH 159/252] update PPP --- docs/team/gurmankalkat.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/team/gurmankalkat.md b/docs/team/gurmankalkat.md index bf05a40ff3..952b337009 100644 --- a/docs/team/gurmankalkat.md +++ b/docs/team/gurmankalkat.md @@ -2,8 +2,10 @@ ## Project: Meal360 ### Overview -Meal360 is a desktop application that helps user organize recipes. The user interacts with it using a Command Line -Interface (CLI). Meal360 can help users manage all their favorite recipes as well as their weekly diet and ingredients. +Meal360 is a desktop app for managing your recipes and weekly meal plans, optimized for use via a +Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If +you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI +apps. ### Summary of Contributions * __Code contributed__: [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=gurmankalkat&breakdown=true) From 4757ebe7ab8838822f97714eae595f917d1509fa Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 7 Apr 2023 08:03:23 +0800 Subject: [PATCH 160/252] ... --- Parser.puml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Parser.puml diff --git a/Parser.puml b/Parser.puml new file mode 100644 index 0000000000..04698e5967 --- /dev/null +++ b/Parser.puml @@ -0,0 +1,24 @@ +@startuml +class seedu.meal360.Parser { +~ Ui ui ++ String combineWords(String[],int,int) ++ HashMap parseIngredientName(String[]) ++ Recipe parseAddRecipe(String[],RecipeList) ++ Recipe parseEditRecipe(String[],RecipeList) ++ String parseDeleteRecipe(String[],RecipeList) ++ String parseTagRecipe(String[],RecipeList) ++ String parseAddRecipeTag(String,RecipeList) ++ String parseRemoveRecipeTag(String,RecipeList) ++ RecipeList parseListRecipe(String[],RecipeList) ++ Recipe parseViewRecipe(String[],RecipeList) ++ Recipe parseViewRecipe(String,RecipeList) ++ Recipe parseRandomRecipe(RecipeList) ++ WeeklyPlan parseWeeklyPlan(String[],RecipeList) +- WeeklyPlan parseEditSingleWeeklyPlan(String[],RecipeList) +- WeeklyPlan parseEditMultiWeeklyPlan(String[],RecipeList) +- StringBuilder getRecipeNames(String[],ArrayList,StringBuilder,int,int) ++ LocalDate parseDate(String) ++ void parseAddUserIngredients(String[],IngredientList) ++ void parseDeleteUserIngredients(String[],IngredientList) +} +@enduml \ No newline at end of file From 4486b988c9fa4c1e85c86b8e7a086e283b60784e Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 7 Apr 2023 12:41:29 +0800 Subject: [PATCH 161/252] update link on aboutUs --- docs/AboutUs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index c2ddf48fb3..8aa80bfe1c 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -4,5 +4,5 @@ Display | Name | Github Profile | Portfoli ![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) ![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) ![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) ![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) From fe48d62b618ae4e01e3bfcaeb5bb65d3c44abc8b Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 7 Apr 2023 14:07:35 +0800 Subject: [PATCH 162/252] update Tag UI message --- src/main/java/seedu/meal360/Meal360.java | 5 +-- src/main/java/seedu/meal360/Parser.java | 9 ++++-- src/main/java/seedu/meal360/Ui.java | 21 ++++++++++++- src/test/java/seedu/meal360/Meal360Test.java | 32 ++++++++++++++++++-- text-ui-test/EXPECTED.TXT | 2 +- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index e6f0f162d2..25700ea709 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -145,8 +145,9 @@ public static void receiveInput(String input) { } else if (command[0].equals("tag")) { try { ui.printSeparator(); - String tag = parser.parseTagRecipe(command, recipeList); - ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); + String returnMessage = parser.parseTagRecipe(command, recipeList); + ui.printTagMessage(returnMessage); + //ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { ui.printMessage(e.getMessage()); } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 2899dd6257..9769feb29d 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -236,6 +236,7 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } public String parseTagRecipe(String[] inputs, RecipeList recipeList) { + String returnMessage; String tag; boolean isOnlyTagWordInCommand = inputs.length == 1; boolean isAddTag; @@ -257,15 +258,17 @@ public String parseTagRecipe(String[] inputs, RecipeList recipeList) { throw new IllegalArgumentException("Please enter the command in the correct format."); } else if (isAddTag) { tag = parseAddRecipeTag(commandString.toString(), recipeList); + returnMessage = "add " + tag; } else if (isRemoveTag) { tag = parseRemoveRecipeTag(commandString.toString(), recipeList); + returnMessage = "remove " + tag; } else { throw new IllegalArgumentException("Invalid command."); } - return tag; + return returnMessage; } - public String parseAddRecipeTag(String command, RecipeList recipeList) { + public String parseAddRecipeTag(String command, RecipeList recipeList) throws IndexOutOfBoundsException { String tag; Recipe recipe; String[] recipesToTag; @@ -295,7 +298,7 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) { return tag; } - public String parseRemoveRecipeTag(String command, RecipeList recipeList) { + public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws IndexOutOfBoundsException { String tag; Recipe recipe; String[] recipesToRemove; diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 3ccfcb32dc..931bb785c9 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -83,7 +83,7 @@ public void listAvailableRecipes(RecipeList recipeListToPrint) { } private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, - String listHeaderMsg) { + String listHeaderMsg) { int numberOfRecipes = recipeListToPrint.size(); int order = 0; if (numberOfRecipes == 0) { @@ -138,4 +138,23 @@ public void printUserIngredients(IngredientList userIngredients) { }); } } + + public void printTagMessage(String receivedMessage) { + String[] args = receivedMessage.split(" ", 2); + String command = args[0].trim(); + String tag = args[1].trim(); + if (command.equals("add")) { + printSuccessfullyAddTag(tag); + } else if (command.equals("remove")) { + printSuccessfullyRemoveTag(tag); + } + } + + public void printSuccessfullyAddTag(String tag) { + printMessage("You have successfully added the recipe(s) to \"" + tag + "\" tag."); + } + + public void printSuccessfullyRemoveTag(String tag) { + printMessage("You have successfully removed the recipe(s) from \"" + tag + "\" tag."); + } } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index a3ed301b97..e7b225a762 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -871,38 +871,64 @@ public void testListRecipe() { public void testListTagAndAddTag() { RecipeList recipeListToPrint; String[] inputs; - // add tag for testing + // check add tag (1) String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; parser.parseTagRecipe(addTagInputs, recipes); + // check list tag (1) inputs = new String[]{"list", "/t", "breakfast"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(recipeListToPrint.size(), 1); assertEquals(recipeListToPrint.get(0).getName(), "salad"); - // add tag for testing + // add tag (2) addTagInputs = new String[]{"tag", "breakfast", "<<", "pizza"}; parser.parseTagRecipe(addTagInputs, recipes); + addTagInputs = new String[]{"tag", "western", "<<", "burger"}; parser.parseTagRecipe(addTagInputs, recipes); + // list tag (2) inputs = new String[]{"list", "/t", "breakfast"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(recipeListToPrint.size(), 2); + assertEquals(recipeListToPrint.get(1).getName(), "pizza"); inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(recipeListToPrint.size(), 0); - // add tag for testing + // add tag (3) addTagInputs = new String[]{"tag", "western", "<<", "pizza"}; parser.parseTagRecipe(addTagInputs, recipes); + + // list tag (3) inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(recipeListToPrint.size(), 1); assertEquals(recipeListToPrint.get(0).getName(), "pizza"); } + @Test + public void testPrintAddTagMessage() { + String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; + String addTagReturnMessage = parser.parseTagRecipe(addTagInputs, recipes); + ui.printTagMessage(addTagReturnMessage); + assertEquals(ui.formatMessage("You have successfully added the recipe(s) to \"breakfast\" tag."), + outContent.toString().trim()); + } + + @Test + public void testPrintRemoveTagMessage() { + String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; + parser.parseTagRecipe(addTagInputs, recipes); + String[] removeTagInputs = new String[]{"tag", "breakfast", ">>", "salad"}; + String removeTagReturnMessage = parser.parseTagRecipe(removeTagInputs, recipes); + ui.printTagMessage(removeTagReturnMessage); + assertEquals(ui.formatMessage("You have successfully removed the recipe(s) from \"breakfast\" tag."), + outContent.toString().trim()); + } + @Test public void testListTagException() { String[] inputs; diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 2ec8fd0089..9d3811c5f1 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -47,7 +47,7 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please enter the command in the correct format. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| You have modified the recipe(s) in this "tag#1" tag. | +| You have successfully added the recipe(s) to "tag#1" tag. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | There is nothing to list. | From 4e77f23597f8d7969eb0c7fd9ceb4823d57f9b64 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 7 Apr 2023 14:16:51 +0800 Subject: [PATCH 163/252] modifiy tag test --- src/test/java/seedu/meal360/Meal360Test.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index e7b225a762..a6c71f62f7 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -892,7 +892,6 @@ public void testListTagAndAddTag() { inputs = new String[]{"list", "/t", "breakfast"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); assertEquals(recipeListToPrint.size(), 2); - assertEquals(recipeListToPrint.get(1).getName(), "pizza"); inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; recipeListToPrint = parser.parseListRecipe(inputs, recipes); From 27dcfceca914a1309352e39580cb8c760b7279fe Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 7 Apr 2023 14:43:42 +0800 Subject: [PATCH 164/252] Created PPP. Updated the code based on practical dry run bugs. --- docs/team/abijith.md | 51 ++++ src/main/java/seedu/meal360/Parser.java | 233 ++++++++++++++----- src/test/java/seedu/meal360/Meal360Test.java | 14 ++ 3 files changed, 234 insertions(+), 64 deletions(-) create mode 100644 docs/team/abijith.md diff --git a/docs/team/abijith.md b/docs/team/abijith.md new file mode 100644 index 0000000000..4a86663c80 --- /dev/null +++ b/docs/team/abijith.md @@ -0,0 +1,51 @@ +# Suresh Abijith Ram - Project Portfolio Page + +## Project: Meal360 +### Overview +Meal360 is a desktop app for managing your recipes, optimized for use via a Command Line Interface (CLI) while still +having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management +tasks done faster than traditional GUI apps. + + +Given below are my contributions to the project: +### Summary of Contributions +* __Code contributed__: [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=topgun2001&breakdown=true) + + +* __Functions / Enhancements implemented__ + * Implemented `add` feature for adding of new recipes to the user's recipe list. + ([#26](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/26)) + * Implemented `edit` feature for editing already existing recipes in user's recipe list. + ([#32](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/32)) + * Implemented `help` feature for displaying all types of user commands for execution. + ([#28](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/28)) + * Implemented `combineWords` feature for trimming words with excess white space characters and joining them to + form a single sentence for recipe names and ingredient names. + ([#51](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/51)) + * Implemented enhancement feature of accepting ingredients in a single line. + ([#51](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/51)) + + +* __Contributions to User Guide__ ([#69](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/69)): + * Added documentation for the following: + * HOW TO ADD INGREDIENTS TO A RECIPE? + * `add` + * `edit` + * `help` + + +* __Contribtions to Developer Guide__ ([#54](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/54)): + * Added documentation for the following: + * `Add Recipes` feature + * `Edit Recipes` feature + * `edit` + * `help` + + +* __Community__: + * Reported bugs and suggestions for other teams during Practical Dry-Run.([I](https://github.com/TopGun2001/ped/issues)) + * Bugs: ([#1](https://github.com/TopGun2001/ped/issues/1)),([#2](https://github.com/TopGun2001/ped/issues/2)), + ([#3](https://github.com/TopGun2001/ped/issues/3)),([#5](https://github.com/TopGun2001/ped/issues/5)), + ([#7](https://github.com/TopGun2001/ped/issues/7)) + * Suggestions: ([#4](https://github.com/TopGun2001/ped/issues/4)),([#6](https://github.com/TopGun2001/ped/issues/6)), + ([#10](https://github.com/TopGun2001/ped/issues/10)) \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 2899dd6257..48600c7264 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Objects; import java.util.Scanner; import seedu.meal360.exceptions.IngredientNotFoundException; import seedu.meal360.exceptions.InvalidValueException; @@ -15,6 +16,9 @@ public class Parser { Ui ui = new Ui(); + String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly!" + + "[eg:chicken=100]"; + public String combineWords(String[] input, int startIndex, int length) { StringBuilder word = new StringBuilder(input[startIndex].trim()); for (int i = startIndex + 1; i < length; i++) { @@ -41,58 +45,71 @@ public HashMap parseIngredientName(String[] command) { int indexOfEqual; for (String s : command) { - try { - indexOfEqual = s.indexOf("="); - if (indexOfEqual == -1) { - if (add != null) { - add.append(" ").append(s); - } else { - add = new StringBuilder(s); - } - flag++; - + indexOfEqual = s.indexOf("="); + if(s.charAt(indexOfEqual+1) == '-'){ + throw new IllegalArgumentException(); + } + if (indexOfEqual == -1) { + if (add != null) { + add.append(" ").append(s); } else { - if (flag > 0) { - indexOfEqual = s.indexOf("="); - ingredientName = (s.substring(0, indexOfEqual)); - ingredientName = add + " " + ingredientName; - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); - flag = 0; - add = null; - } else { - ingredientName = s.substring(0, indexOfEqual); - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); - } - - ingredients.put(ingredientName, ingredientQuantity); - + add = new StringBuilder(s); } - } catch (NumberFormatException e) { - ui.printSeparator(); - String errorMessage = "Please enter ingredients properly![eg: chicken=100]"; - ui.printMessage(errorMessage); - ui.printSeparator(); + flag++; + } else { + if (flag > 0) { + indexOfEqual = s.indexOf("="); + ingredientName = (s.substring(0, indexOfEqual)); + ingredientName = add + " " + ingredientName; + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + flag = 0; + add = null; + } else { + ingredientName = s.substring(0, indexOfEqual); + ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + } + ingredients.put(ingredientName, ingredientQuantity); } } return ingredients; } public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { + int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); if (recipeList.findByName(recipeName) != null) { return null; + } else if(!Objects.equals(input[1], "/r")){ + throw new ArrayIndexOutOfBoundsException(); } HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); System.out.println("Please Enter The Ingredients & Quantity: "); while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { + try{ + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + if(addedIngredient==0 || ingredients.size()==0) { + ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printSeparator(); + } else { + break; + } + } else { + addedIngredient = 1; + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + if(ingredients.size()==0){ + ui.printSeparator(); + ui.printMessage(recipeErrorMessage); + ui.printSeparator(); + } + } + } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + ui.printSeparator(); + ui.printMessage(recipeErrorMessage); ui.printSeparator(); - break; - } else { - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); } } Recipe newRecipe = new Recipe(recipeName, ingredients); @@ -101,9 +118,10 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { } public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { + int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); Recipe recipeToEdit; - HashMap ingredients; + HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); if (recipeList.findByName(recipeName) == null) { return null; @@ -112,18 +130,55 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { System.out.println("Do you want to edit recipe fully or partially?"); System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); - Scanner getInput = new Scanner(System.in); - int index = getInput.nextInt(); + int index; + Scanner getNum = new Scanner(System.in); + while(true){ + try{ + index = Integer.parseInt(getNum.nextLine()); + if(index <1 || index>3){ + ui.printSeparator(); + ui.printMessage("Index cannot be negative or out of bounds!"); + ui.printSeparator(); + } else{ + break; + } + } catch(NumberFormatException e){ + ui.printSeparator(); + ui.printMessage("Enter valid index for respective editing options!"); + ui.printSeparator(); + } + } + if (index == 1) { System.out.println("Please Enter New Ingredients & Quantity: "); while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { - break; + try{ + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + if(addedIngredient==0 || ingredients.size()==0) { + ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printSeparator(); + } else { + break; + } + } else { + addedIngredient = 1; + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + if(ingredients.size()!=0){ + recipeList.editRecipe(recipeToEdit, ingredients); + } else{ + ui.printSeparator(); + ui.printMessage(recipeErrorMessage); + ui.printSeparator(); + } + } + } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + ui.printSeparator(); + ui.printMessage(recipeErrorMessage); + ui.printSeparator(); } - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - recipeList.editRecipe(recipeToEdit, ingredients); } } else if (index == 2) { System.out.println("These are the ingredients for the recipe:"); @@ -132,7 +187,24 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { ui.printRecipe(recipe); ui.printSeparator(); System.out.println("Which ingredient do you want to change?"); - int ingredientIndex = getInput.nextInt(); + int ingredientIndex = 0; + Scanner getIndex = new Scanner(System.in); + while(true){ + try{ + ingredientIndex = Integer.parseInt(getIndex.nextLine()); + if(ingredientIndex <=0 || ingredientIndex > recipe.getNumOfIngredients()){ + ui.printSeparator(); + ui.printMessage("Index cannot be negative or out of bounds!"); + ui.printSeparator(); + } else{ + break; + } + } catch(NumberFormatException e){ + ui.printSeparator(); + ui.printMessage("Enter valid ingredient index!"); + ui.printSeparator(); + } + } ingredientIndex -= 1; int count = 0; String ingredientToRemove = null; @@ -150,36 +222,69 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { count++; } System.out.println("Please enter the new ingredient:"); - String line = userInput.nextLine(); - String command = line.replaceAll("\\s+", " "); - int indexOfEqual = command.indexOf("="); - String newIngredientName = command.substring(0, indexOfEqual); - int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual + 1)); - recipeToEdit.getIngredients().remove(ingredientToRemove); - recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); - recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); - } else if (index == 3) { + + while(true){ + try{ + String line = userInput.nextLine(); + String command = line.replaceAll("\\s+", " "); + int indexOfEqual = command.indexOf("="); + if(command.charAt(indexOfEqual + 1) == '-'){ + ui.printSeparator(); + ui.printMessage("Invalid ingredient quantity!"); + ui.printSeparator(); + } else{ + String newIngredientName = command.substring(0, indexOfEqual); + int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual + 1)); + recipeToEdit.getIngredients().remove(ingredientToRemove); + recipeToEdit.getIngredients().put(newIngredientName, newIngredientQuantity); + recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); + break; + } + } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + ui.printSeparator(); + ui.printMessage(recipeErrorMessage); + ui.printSeparator(); + } + } + } else { HashMap newIngredientList = recipeToEdit.getIngredients(); System.out.println("These are the current ingredients:"); ui.printSeparator(); Recipe recipe = parseViewRecipe(recipeName, recipeList); ui.printRecipe(recipe); ui.printSeparator(); - System.out.println("Please Enter Additional Ingredients & Quantity (Enter done when complete): "); + System.out.println("Please Enter Additional Ingredients & Quantity: "); while (true) { - String line = userInput.nextLine(); - if (line.equals("done")) { + try{ + String line = userInput.nextLine(); + if (line.equals("done")) { + ui.printSeparator(); + if(addedIngredient==0 || ingredients.size()==0) { + ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printSeparator(); + } else { + break; + } + } else { + addedIngredient = 1; + String[] command = line.trim().split(" "); + ingredients = parseIngredientName(command); + newIngredientList.putAll(ingredients); + if(ingredients.size()!=0){ + recipeList.editRecipe(recipeToEdit, newIngredientList); + } else{ + ui.printSeparator(); + ui.printMessage(recipeErrorMessage); + ui.printSeparator(); + } + } + } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + ui.printSeparator(); + ui.printMessage(recipeErrorMessage); ui.printSeparator(); - break; - } else { - String[] command = line.trim().split(" "); - ingredients = parseIngredientName(command); - newIngredientList.putAll(ingredients); } } - recipeList.editRecipe(recipeToEdit, newIngredientList); } - return recipeToEdit; } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index a3ed301b97..0774acb5a2 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -1320,4 +1320,18 @@ public void testEmptyListUserIngredients() { public void testLoadDatabase() { assertDoesNotThrow(database::loadRecipesDatabase); } + + + @Test + public void testCombineWords(){ + String[] input1 = {"One", "Two" , "Three"}; + assertEquals("One Two Three", parser.combineWords(input1, 0, 3)); + + String[] input2 = {"Pizza ", "Burger " , " Ice Cream"}; + assertEquals("Pizza Burger Ice Cream", parser.combineWords(input2, 0, 3)); + + String[] input3 = {"1 1 1", "2 2 2" , "3 3 3"}; + assertEquals("1 1 1 2 2 2 3 3 3", parser.combineWords(input3, 0, 3)); + + } } From b993bf4b3864cf0356dffa025d7fa431e95a0eb0 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Fri, 7 Apr 2023 15:16:45 +0800 Subject: [PATCH 165/252] fix 'random' exception --- src/main/java/seedu/meal360/Meal360.java | 2 +- src/main/java/seedu/meal360/Parser.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 25700ea709..63ccbd8781 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -157,7 +157,7 @@ public static void receiveInput(String input) { try { Recipe randomRecipe = parser.parseRandomRecipe(recipeList); ui.printRecipe(randomRecipe); - } catch (NumberFormatException | IndexOutOfBoundsException e) { + } catch (NumberFormatException | IndexOutOfBoundsException | NullPointerException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 9769feb29d..90ca1b1653 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -409,9 +409,9 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { return recipes.get(recipeIndex - 1); } - public Recipe parseRandomRecipe(RecipeList recipes) { + public Recipe parseRandomRecipe(RecipeList recipes) throws NullPointerException { if (recipes.size() == 0) { - throw new NullPointerException("There is no recipe in the list to random"); + throw new NullPointerException("There is no recipe in the list for random."); } return recipes.randomRecipe(); } From cffe7cb170d4cb8a3f67d85e43049170c5b36de6 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Fri, 7 Apr 2023 14:30:01 +0700 Subject: [PATCH 166/252] fix formatting for error line --- src/main/java/seedu/meal360/Meal360.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 4efe55caf8..9b8b997d7c 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -78,8 +78,7 @@ public static void receiveInput(String input) { } catch (ArrayIndexOutOfBoundsException e) { String errorMessage = "Please enter a valid recipe number or name in the correct format. You did not enter a recipe" + - " number " - + "or " + "name. See 'help' for more details."; + " number or name. See 'help' for more details."; ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( From 970005d25489e7eb206d1878e47fc8fb0ed6e951 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 7 Apr 2023 15:44:08 +0800 Subject: [PATCH 167/252] Changed PPP file name --- docs/team/{abijith.md => topgun2001.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/team/{abijith.md => topgun2001.md} (100%) diff --git a/docs/team/abijith.md b/docs/team/topgun2001.md similarity index 100% rename from docs/team/abijith.md rename to docs/team/topgun2001.md From 85bc5ae5944e7cf21aee47b75c8c409ae15abae0 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 7 Apr 2023 15:46:34 +0800 Subject: [PATCH 168/252] Changed ppp file name. --- docs/team/topgun2001.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/team/topgun2001.md b/docs/team/topgun2001.md index 4a86663c80..3656aa6950 100644 --- a/docs/team/topgun2001.md +++ b/docs/team/topgun2001.md @@ -6,7 +6,6 @@ Meal360 is a desktop app for managing your recipes, optimized for use via a Comm having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI apps. - Given below are my contributions to the project: ### Summary of Contributions * __Code contributed__: [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=topgun2001&breakdown=true) From 5ae6c6101b8c0eba028ee32b772f325acdf00351 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Fri, 7 Apr 2023 15:49:57 +0800 Subject: [PATCH 169/252] New changes. --- src/main/java/seedu/meal360/Parser.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index c4e7339a0a..ee3bf9729d 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -129,7 +129,6 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { recipeToEdit = recipeList.findByName(recipeName); System.out.println("Do you want to edit recipe fully or partially?"); System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); - int index; Scanner getNum = new Scanner(System.in); while(true){ @@ -148,7 +147,6 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { ui.printSeparator(); } } - if (index == 1) { System.out.println("Please Enter New Ingredients & Quantity: "); while (true) { From 8c6a47ac398eabf6fa0f097a5cf25c44e43b753b Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 7 Apr 2023 19:32:27 +0800 Subject: [PATCH 170/252] Update DG Add Architecture to show overall struture of Meal360. Add 3 class diagrams to show the 3 subsystems of Meal360 which are the recipes, ingredients and weekly meal plan. Update implementation of ingredient and weekly plan related features. --- docs/DeveloperGuide.md | 252 +++++++++++++++++- .../.$IngredientRelated.drawio.bkp | 1 + .../Architecture/.$RecipeRelated.drawio.bkp | 1 + docs/UML/Architecture/.$RecipeRelated.png.bkp | Bin 0 -> 51197 bytes .../.$WeeklyPlanRelated.drawio.bkp | 1 + .../UML/Architecture/IngredientRelated.drawio | 1 + docs/UML/Architecture/IngredientRelated.png | Bin 0 -> 28975 bytes docs/UML/Architecture/RecipeRelated.drawio | 1 + docs/UML/Architecture/RecipeRelated.png | Bin 0 -> 64045 bytes .../UML/Architecture/WeeklyPlanRelated.drawio | 1 + docs/UML/Architecture/WeeklyPlanRelated.png | Bin 0 -> 38196 bytes .../.$AddIngredientFunction.drawio.bkp | 122 +++++++++ .../AddIngredientFunction.drawio | 1 + .../AddIngredientFunction.png | Bin 0 -> 12223 bytes .../.$EditWeeklyPlan.drawio.bkp | 122 +++++++++ .../EditWeeklyPlan/.$EditWeeklyPlan.png.bkp | Bin 0 -> 60921 bytes .../EditWeeklyPlan/EditWeeklyPlan.drawio | 1 + .../EditWeeklyPlan/EditWeeklyPlan.png | Bin 0 -> 64996 bytes .../.$AddIngredientFunction.drawio.bkp | 122 +++++++++ .../.$MarkDoneWeeklyPlan.drawio.bkp | 1 + .../.$ViewIngredientFunction.drawio.bkp | 1 + .../.$ViewWeeklyPlan.drawio.bkp | 1 + .../.$ViewWeeklyPlan.drawio.dtmp | 1 + .../MarkDoneWeeklyPlan.drawio | 1 + .../MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png | Bin 0 -> 47574 bytes .../.$AddIngredientFunction.drawio.bkp | 122 +++++++++ .../.$ViewIngredientFunction.drawio.bkp | 1 + .../ViewIngredientFunction.drawio | 1 + .../ViewIngredientFunction.png | Bin 0 -> 21910 bytes .../.$AddIngredientFunction.drawio.bkp | 122 +++++++++ .../.$ViewIngredientFunction.drawio.bkp | 1 + .../.$ViewWeeklyPlan.drawio.bkp | 1 + .../.$ViewWeeklyPlan.drawio.dtmp | 1 + .../ViewWeeklyPlan/ViewWeeklyPlan.drawio | 1 + .../ViewWeeklyPlan/ViewWeeklyPlan.png | Bin 0 -> 21838 bytes src/main/java/seedu/meal360/Ingredient.java | 6 +- .../java/seedu/meal360/IngredientList.java | 6 +- src/main/java/seedu/meal360/Parser.java | 5 + src/main/java/seedu/meal360/Ui.java | 15 +- src/test/java/seedu/meal360/Meal360Test.java | 7 + 40 files changed, 904 insertions(+), 16 deletions(-) create mode 100644 docs/UML/Architecture/.$IngredientRelated.drawio.bkp create mode 100644 docs/UML/Architecture/.$RecipeRelated.drawio.bkp create mode 100644 docs/UML/Architecture/.$RecipeRelated.png.bkp create mode 100644 docs/UML/Architecture/.$WeeklyPlanRelated.drawio.bkp create mode 100644 docs/UML/Architecture/IngredientRelated.drawio create mode 100644 docs/UML/Architecture/IngredientRelated.png create mode 100644 docs/UML/Architecture/RecipeRelated.drawio create mode 100644 docs/UML/Architecture/RecipeRelated.png create mode 100644 docs/UML/Architecture/WeeklyPlanRelated.drawio create mode 100644 docs/UML/Architecture/WeeklyPlanRelated.png create mode 100644 docs/UML/Implementation/AddIngredientFunction/.$AddIngredientFunction.drawio.bkp create mode 100644 docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.drawio create mode 100644 docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.png create mode 100644 docs/UML/Implementation/EditWeeklyPlan/.$EditWeeklyPlan.drawio.bkp create mode 100644 docs/UML/Implementation/EditWeeklyPlan/.$EditWeeklyPlan.png.bkp create mode 100644 docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.drawio create mode 100644 docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png create mode 100644 docs/UML/Implementation/MarkDoneWeeklyPlan/.$AddIngredientFunction.drawio.bkp create mode 100644 docs/UML/Implementation/MarkDoneWeeklyPlan/.$MarkDoneWeeklyPlan.drawio.bkp create mode 100644 docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewIngredientFunction.drawio.bkp create mode 100644 docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp create mode 100644 docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp create mode 100644 docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.drawio create mode 100644 docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png create mode 100644 docs/UML/Implementation/ViewIngredientFunction/.$AddIngredientFunction.drawio.bkp create mode 100644 docs/UML/Implementation/ViewIngredientFunction/.$ViewIngredientFunction.drawio.bkp create mode 100644 docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.drawio create mode 100644 docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.png create mode 100644 docs/UML/Implementation/ViewWeeklyPlan/.$AddIngredientFunction.drawio.bkp create mode 100644 docs/UML/Implementation/ViewWeeklyPlan/.$ViewIngredientFunction.drawio.bkp create mode 100644 docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp create mode 100644 docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp create mode 100644 docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.drawio create mode 100644 docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 2d826ec040..10c33e581c 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -63,14 +63,59 @@ sequence diagram below shows how the interaction described above: ![](../docs/UML/Architecture/ArchitectureExampleUML.png) +Depending on whether the user input is to make changes to the recipes, ingredients, or weekly plan, +the `Parser` component will call the `RecipeList`, `Ingredient`, and/or `WeeklyPlan` component +respectively. The class diagrams below shows the subsystems for recipes, ingredients and weekly +plan. For the class diagrams, `Meal360` and the `Ui` component are not shown for simplicity. +Additionally, methods irrelevant to the subsystem shown are also omitted for simplicity. + +1. Recipe related + ![](../docs/UML/Architecture/RecipeRelated.png) + +2. Ingredient related + ![](../docs/UML/Architecture/IngredientRelated.png) + +3. WeeklyPlan related + ![](../docs/UML/Architecture/WeeklyPlanRelated.png) + +### Meal360 Component + +API: `Meal360.java` + +The `Meal360` component: + +* initializes the databases for the recipes, ingredients, and weekly plan upon program startup. +* receives the user input once initialization is complete. +* passes the user input to the `Parser` component. +* receives the output from the `Parser` component and passes it to the `Ui` component to be + displayed + to the user. +* saves the databases for the recipes, ingredients, and weekly plan upon receiving the `bye` + command. +* terminates the program once the databases have been saved. + ### UI Component API: `Ui.java` +The `Ui` component: + +* displays the welcome message upon startup of the program. +* formats all the output to be displayed to the user. +* provides the user with information on whether command was executed successfully or not. +* displays the error message if the command was not executed successfully. +* displays the goodbye message upon receiving the `bye` command. + ### Parser Component API: `Parser.java` +The `Parser` component: + +* receives the user input from the `Meal360` component +* interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the + commands. + ### Recipe Component API: `Recipe.java` @@ -129,12 +174,12 @@ API: `Database.java` The `Database` component: -* stores the recipes in a local database in json format +* stores the recipes, ingredients, and weeklyplan in a local database in json format * loads up automatically upon startup of program * saves automatically upon exit of program * comes with a default database of 10 recipes for new users -How the `Database` component works at start up: +How the `Database` component works at start up for the recipes: 1. Upon starting up the program, the `Database` component will check for the existence of a database file in the local directory. @@ -146,6 +191,9 @@ How the `Database` component works at start up: create a new `RecipeList` with 10 default recipes and return this `RecipeList`. +* The loading of the ingredients and weekly plan works in a similar manner, except that the default + ingredient list and weekly plan are empty. + The activity diagram below shows how the `Database` component works at start up: ![](../docs/UML/Database/DatabaseStartupUML.png) @@ -157,9 +205,15 @@ The activity diagram below shows how the `Database` component works at start up: * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) +* [Delete Recipes Feature](#delete-recipes-feature) * [Add Recipes Feature](#add-recipes-feature) * [Edit Recipes Feature](#edit-recipes-feature) * [Random a Recipe Feature](#random-a-recipe-feature) +* [Add Ingredients Feature](#add-ingredients-feature) +* [Delete Ingredients Feature](#delete-ingredients-feature) +* [List Ingredients Feature](#list-ingredients-feature) +* [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) +* [List Weekly Meal Plan Feature](#list-weekly-meal-plan-feature) ### Categorise/Tag Recipes Feature @@ -308,6 +362,154 @@ It is implemented through the following step: The sequence diagram below shows how this feature works: ![](../docs/UML/Implementation/RandomFunction/RandomFunction.png) + +### Add Ingredients Feature + +The current implementation: + +* allows for adding only 1 ingredient at a time. +* ingredient needs to have its name, quantity and expiry date specified. + +It is implemented through the following steps: + +* When the user enters an input with the first word being `add_i`, the input is passed to + the `Parser` component. +* In `Parser`, the `parseAddUserIngredient` is executed to identify whether all the required + parameters are provided. +* If any of the parameters are missing/invalid, the user will be alerted with a relevant error + message. +* If all the parameters are valid, the input is sent to `IngredientList` component. +* In `IngredientList`, `addIngredient()` is executed to first check if the ingredient already + exists in the list. +* If the ingredient already exists, the quantity of the ingredient will be updated. +* If the ingredient does not exist, the ingredient will be added to the list. + +The simplified sequence diagram below shows how this feature works assuming all inputs are correct: + +![](../docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.png) + +### Delete Ingredients Feature + +The current implementation: + +* allows for deleting only 1 ingredient at a time. +* ingredient needs to have its name and quantity specified. + +It is implemented through the following steps: + +* When the user enters an input with the first word being `del_i`, the input is passed to + the `Parser` component. +* In `Parser`, the `parseDeleteUserIngredient` is executed to identify whether all the required + parameters are provided. +* If any of the parameters are missing/invalid, the user will be alerted with a relevant error + message. +* If all the parameters are valid, the input is sent to `IngredientList` component. +* In `IngredientList`, `deleteIngredient()` is executed to first check if the ingredient exists in + the list. +* If the ingredient does not exist, the user will be alerted with a relevant error message. +* If the ingredient exists and the new quantity is more than 0, the quantity of the ingredient will + be updated. Otherwise, the ingredient would be deleted entirely from the list. + +The sequence diagram of deleting an ingredient is similar to adding an ingredient. + +### List Ingredients Feature + +The current implementation: + +* allows for listing all ingredients in the list. + +It is implemented through the following steps: + +* When the user enters an input with the first word being `view_ingredients`, the list of user + ingredients that is represented by `userIngredients` is passed to the `Ui` component. +* In `Ui`, `printUserIngredients()` first checks if the list is empty. +* If the list is empty, the user will be alerted with a relevant message and the function exits. +* If the list is not empty, the list of ingredients will be printed out, with information regarding + the names, quanntity, and expiry date of each ingredient displayed. + +The sequence diagram below shows how this feature works: + +![](../docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.png) + +### Edit weekly meal plan Feature + +The current implementation: + +* allows for adding single recipe to the weekly meal plan. +* allows for deleting single recipe from the weekly meal plan. +* allow for adding multiple recipes to the weekly meal plan. +* allow for deleting multiple recipes from the weekly meal plan. + +It is implemented through the following steps: + +* When the user enters an input with the first word being `weekly`, the input is passed to + the `Parser` component. +* In `Parser`, the `parseWeeklyMealPlan` is executed to identify whether the user wants to + add/delete only one or multiple recipes. +* If the user wants to add/delete only one recipe, parseEditSingleWeeklyPlan() is executed. +* If the user wants to add/delete multiple recipes, parseEditMultiWeeklyPlan() is executed. +* `parseEditSingleWeeklyPlan()` and `parseEditMultiWeeklyPlan()` checks if the command parameters + are valid first, then it returns the + name and quantity of the recipes specified by the user. If the command parameters are invalid or + the recipe is not a valid recipe, a relevant error message will be displayed. +* In `Meal360`, the second argument of the user input is then use to determine whether the user + wants to add or delete the recipes. +* If the user wants to add the recipes, the list of recipe(s) would be passed to the `WeeklyPlan` + component to execute `addPlans()`. +* If the user wants to delete the recipes, the list of recipe(s) would be passed to the `WeeklyPlan` + component to execute `deletePlans()`. + +The sequence diagram below shows how this feature works: + +![](../docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png) + +### List Weekly Plan Feature + +The current implementation: + +* allows for listing all recipes that are in the weekly plan. + +It is implemented through the following steps: + +* When the user enters an input with the first word being `weeklyplan`, the list of user + ingredients that is represented by `userIngredients` is passed to the `Ui` component. +* In `Ui`, `printUserIngredients()` first checks if the list is empty. +* If the list is empty, the user will be alerted with a relevant message and the function exits. +* If the list is not empty, the list of ingredients will be printed out, with information regarding + the names, quanntity, and expiry date of each ingredient displayed. + +The sequence diagram below shows how this feature works: + +![](../docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.png) + +### Mark Recipe as Done Feature + +The current implementation: + +* allows for marking a recipe in the weekly plan as done. +* marking a recipe as done automatically removes the recipe and one set of its ingredients from the + weekly plan. + +It is implemented through the following steps: + +* When the user enters an input with the first two word being `weekly` and `/done` respectively, the + input is passed to the `Parser` component. +* In `Parser`, the `parseMarkDone` is executed, which then send the input to `Recipe` component to + obtain the list of ingredients of the recipe using `getIngredients()`. +* The list of ingredients is then passed to `IngredientList` component to check if the user has all + the necessary ingredients using `findIngredientCount()`. +* If the user does not have all the necessary ingredients, the user will be alerted with a relevant + error message. +* If the user has all the necessary ingredients, the `IngredientList` component will then remove the + ingredients from the list using `deleteIngredient()`. +* The `WeeklyPlan` component will then remove the recipe from the weekly plan using `remove()` if no + counts of the recipe is left, otherwise it will reduce the count of the recipe by 1 using `put()`. + +The simplified sequence diagram below shows how this feature works assuming no counts of the recipe +is left after the deletion: + +![](../docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png) + --- ## Appendix: Requirements @@ -353,6 +555,11 @@ driven app. ### Non-Functional Requirements 1. Should work on any *mainstream OS* as long as it has Java 11 or above installed. +2. The number of recipes and user ingredients is limited to only 1000 items each. +3. A user with above average typing speed for regular English text (i.e. not code, not system + admin commands) should be able to accomplish most of the tasks faster using commands than + using the mouse, especially for the more advanced commands that allow for editing multiple items + at once. ### Glossary @@ -360,5 +567,42 @@ driven app. ### 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} \ No newline at end of file +Given below are instructions to test the app manually. + +#### Launch and Shutdown + +1. Initial launch + + 1. Download the jar file and copy into an empty folder + 2. Run the jar file using the command `java -jar meal360.jar`. The GUI similar to the below + should appear in a few seconds. The app comes with a smaall sample data of 10 recipes to + allow for easy testing. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + Welcome to Meal360, your ultimate Recipe Manager! + __ __ _ ____ __ __ + | \/ |___ __ _| |__ / / / / \ + | |\/| / -_) _` | ||_ \/ _ \ () | + |_| |_\___\__,_|_|___/\___/\__/ + + ---------------------------------------------------------------------------------------------------- + | Loading recipes... | + | Recipes loaded successfully. | + | Loading weekly plan... | + | Weekly plan loaded successfully. | + | Loading ingredients... | + | Ingredients loaded successfully. | + ---------------------------------------------------------------------------------------------------- + ``` + +2. Shutdown + 1. A user input of `bye` allows the user to exit the app. The app will then save the data for + recipes, ingredients and weekly meal plan automatically before exiting. + +#### Ingredients + +1. Test case: `add_i /n fish /c 10 /d 10/10/2024` + Expected: The ingredient `fish` with quantity `10` and expiry date `10/10/2024` should be added + into the user ingredients list. A success message should be displayed. \ No newline at end of file diff --git a/docs/UML/Architecture/.$IngredientRelated.drawio.bkp b/docs/UML/Architecture/.$IngredientRelated.drawio.bkp new file mode 100644 index 0000000000..38e24b20ca --- /dev/null +++ b/docs/UML/Architecture/.$IngredientRelated.drawio.bkp @@ -0,0 +1 @@ +1Vpbc9o4FP41zHQfmpEsXx8D6V5m0t1s03a7j8KWQRNhubII0F9fyRewLRtIMZDkIWMdyZL8ne9ckxGaLNZ/CJzOP/KIsJEFovUI3Y0sy4a2+q0Fm0Jg2W4hmAkaFSKwEzzSH6QQwkq6pBHJSlkhkpwzSdOmMORJQkLZkGEh+Kq5LOYsaghSPCOG4DHEzJT+RyM5L6XQDXYTfxI6m5dH+5ZXTCxwtbj8kmyOI76qidCHEZoIzmXxtFhPCNPYNXH5vWd2ezFBEnnMCz++rZLFD+Q9fv3n899P9prQ8b/vLafY5hmzZfnF5W3lpoJgLhdMPcERGseUsQlnXKhxRGK8ZOrocbkFEZKsey8Ht5+sqEL4gkixUUuqF5wSpU0FcAnjage6h8o18xreKCi/AJeKnm333mGhHko4XgANNJD5SDBDLjAAUppN9eNywe5pTBhN1GicEkHVTYjGipXih51svJpTSR5THOpXV8p4lKwGtSK0xOoVsR0zhtOMTvNTgZIIEi5FRp/JJ5IVdqOlfCn1SZOtPYCW3kYWiv2QhKGSZ1LwJ1KbmfqO7YBhdIoAbOrUsw2dQtCl00o4vE7Bi+iecprI/A7OeOTctZTKhZzzGU8wq6v1BBPpp2EvxrbTgNiHHQibAMMgOBPAloHvAxaZAubN20zkED+yu2zGt6bIdYexGQe6LZtxr24z6M3ZjPUSm4GwC2ITYdc9E8Amvp9ISFNyTzP59u0mjmOrO9ZE7tR1BrIb17FeXaxx35zdoBfZDQqOspsqIR4cYPswvj3WgoWkysJwDoaaU0ROIqyudDVL0tqiquq4ZXSWKJnkeuNMnUOT2Wc9uENun8UNYD/QQU3l+mb+HVzUfI6wHqHVRqIShQOa6baVplNKeM6PQfBs575Wh7F4HVHmXHh6Bp5fDuRlt6HUqGy5eY+nhD3wjErKNUenXEq+6CXvRcpGv0Vb20yAu6rGs6EMzapRGTxR5v5Xki7lu5Hlfl/qin/8TMlKLYQ7yW/7wkMb4y34JIludZ9DyxgPn3KR+pRvpVnkg/8r59OwmOI8ErU6IBKLGdlbkoAePanL86UIySGn3avP9+AGAFQ6dkEYlgq5xgFdGiu3e9ARtBauqhZC1XnyWwlccdfyrXrjpNqoWsjjOCPS4Mb2+ifQxayXTiUBT4maGkc4m+eKhsV02Vnz9WhNpWaHBhvapSBnyE0QuAZL9Ozduj7Y1Aa12LiPUwd5sYdTB/nYw6mB+YNcq7lFcS+DP4Nxw8xvUl1Lf1WOoygQ9nqTkTXJMagqiYt7l4pmilV+g2TQ84ai1WFXhX7dVUFwFl4hx2/6paAVjHr80mC8Mlu+gnxfkkySqODV5VwQaHkf/1rep58mR0bD/SGtyvROdUmoWeWidk+ixyVdNKSZiaa60jtwNf8Db1T23eAZAvblHJB7ggPqqcdPZJHbZhFsbXFuB+S/WgfkHJsjH9Zdv96PDFqD690Dzd4y8ludmTMnNFZg6P0LNVT95hqcAPgYgK4GJwCOl8/E6vhmS1T9DFMBe1Wj8/U0PpFZA+8z6NfQ+CyoeWzn06rShUOdT/tcCL/sTzIXdpm7AH0TWHYjSN94nlMJdrE3H23qo6HyOtRnTyfkdad6YTtokMl20UW9cBX862WlUGeVJWUrEl+zamzwzHXQxXK2Pay5VtHYZo0Ru385Z1PD3f8gFct3/8iFPvwE \ No newline at end of file diff --git a/docs/UML/Architecture/.$RecipeRelated.drawio.bkp b/docs/UML/Architecture/.$RecipeRelated.drawio.bkp new file mode 100644 index 0000000000..03c36b4237 --- /dev/null +++ b/docs/UML/Architecture/.$RecipeRelated.drawio.bkp @@ -0,0 +1 @@ +7Vptb+I4EP41SLsngeKYBPhYoLu3EnvqHrvavfvmJQasOjFyTAv762+cOK9O2tCDdqW2Qmo8GY/teR6PxwM9PAsPHyXZbT+LgPKe6wSHHp73XBc5ngP/tOSYSnx3kgo2kgWpyCkES/aLZj2NdM8CGhtZKlJCcMV2VeFKRBFdqYqMSCnuq2prwYOKYEc21BIsV4Tb0u8sUFsjRf6kePEnZZutGXrsjtIXIcmUzUriLQnEfUmEr3t4JoVQ6VN4mFGunVf1y4eWt/nEJI1Ulw5f5iPpLmZLhr/eftn8+z0eUb/vjlMzd4TvzYrNbNUxc8FWhRyeUA9P14zzmeBCQjuga7LnMPQ0VlLc0kweiQg6To1dKhU9tM4Y5X4AAlERUiWPoGI6jIznDHU84/L7AoeRY1S2JQjwMMPfYL/JLRfugQfjoRO8hSxn3RAZU2m5LL5nISeJH9YiUkvzRruQcLaJ4HkFToCeeKpdxIBwV+aFEjuQrraMBwtyFHu9qliR1W3Wmm6FZL/ALMlggddSmb3j+hWNpe4JYgekksagc5P5H9VEn8mhorggsTKCleCc7GL2M19GSOSGRVOhlAiN0hkQdz2/AvnItSAfjpENOco22dkhdy3I+3vWw1cg+8Ys3GHlrRuivHeMKOMCp2vVyoR4R1Ys2iwSnfmwkPxt1q9FAvqueRJetiwIaKRRFIookkKm8dkJFqnEP94UPuCxmTPweh5MfAZtVLTho9WlmokI1kJYgh4FPtxTzYluULdvIRt/g7frd8M70zs73PjxcMhZgl2KcXYm1INjN4BDgIrTAtGvGvB5H1moYxt13IAwJz8pvxExU0xo+zLVrSH/GLhV9rJoSyW7JOhex00+vhDmwwbMpzsd2K+C4BuE90/RRtKAwRrjdysRhiQK0giwVBIQMU6FTQQD5aoLpp2ptT5VZO9T4Z2AOWkaY5TGznTEOeVU0RMH3VfVHx31LWidlb++042//qXOKDR5PGrRKLjS6XCBYymtk2IfBTQwLgdfyOMP3RjASjLBP0Y3acwPZd35sdy6gXAB69K5TSktoIGVZ9eSAkjsIaegD+EwbMah5HivIR/MZJJyothddRpNYJgRbjT1itwE+8NKbuJm7cxELPZyRU2vciJuGfKqhlBtLqkfLEMJN/Jl/4+Uxk5jz0KXvjNwHLfMF9iZY/8pnKEHprRJBBaRaacGsYNNu7CnG8dS4+kMTCF8wHeTjkxF3otSdewPRjWSjYYD74l8HeHBaIgn+V/VsOM+L3vtjPyPtiOtxNlHr115LpZcflpPIH3IkL0ScXrbQiccnJ3On4fvR543rjgfO/bZ4+JnzJddO2FGrwaNeiBH47GNhvecaDSlsr9NIpAFdZ2vlUL6g+H8jKEbvWj24Hu1sOnVTHSNxmAIDsW2aIwmbj3MXzoee684Avg+bI1qyQqCQIbAS4UB30Kkehm04HmV5coyI+Aa/iH5Ow8tUJYT5VcF+5jG4wZKIHQpTnSo878Vtk4uDPjNNGivZjaifqnCVlNZYEqCoIgG74p6Vb1q1FqnCpIS1QM2TIGqVg+bQWqRD6LohsrWEdYsKs0x6Vga5C8S0vJA7ytG246et+rWE0mMhx1J7F6IxchOagtyvB1lZ/rmzcsqlnl+ii3cUfbtXBn3iXcp3O3Est8eBUoRpN8YdJL0t9Chhx2DCwtRxspCABGSZklJd4uvtSY1xfepEJyS6C3KnF5Db7l+tZ+VjXTLfndxAt2gWfzKIr32FL9Vwdf/AQ== \ No newline at end of file diff --git a/docs/UML/Architecture/.$RecipeRelated.png.bkp b/docs/UML/Architecture/.$RecipeRelated.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..71bdc1cac92e200e3e017db158f89d37bb68b2ea GIT binary patch literal 51197 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 \ No newline at end of file diff --git a/docs/UML/Architecture/IngredientRelated.drawio b/docs/UML/Architecture/IngredientRelated.drawio new file mode 100644 index 0000000000..1cf0a8625a --- /dev/null +++ b/docs/UML/Architecture/IngredientRelated.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/Architecture/IngredientRelated.png b/docs/UML/Architecture/IngredientRelated.png new file mode 100644 index 0000000000000000000000000000000000000000..f77b3353603303fed94bded7b7d7671b674d3c41 GIT binary patch literal 28975 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 A7XSbN literal 0 HcmV?d00001 diff --git a/docs/UML/Architecture/RecipeRelated.drawio b/docs/UML/Architecture/RecipeRelated.drawio new file mode 100644 index 0000000000..73784a7c4a --- /dev/null +++ b/docs/UML/Architecture/RecipeRelated.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/Architecture/RecipeRelated.png b/docs/UML/Architecture/RecipeRelated.png new file mode 100644 index 0000000000000000000000000000000000000000..8a7148051bcbec8b6704937bea64647e92317cc9 GIT binary patch literal 64045 zcmdqIc|4n2*FUVY&V#n9syfj@l?aJY)EGoWL=r(M5fMZr5fMWityXL5>1oYVTdh_U zMNt%|6s@r>YAi+3n&(;lc6#pTx$o!q-#dNY&-?zvm1|hn-fOSD)^~l^y6%{nB6sgN zx+`DDP&iM@DWFr zJ@*og0d7}Pyrg;wB7CK;GmAk7cNstwVV4vysVFHUE)mCMRdFk*&G*DWjDH&zKRRf9thGm(Z)Ei z^bNTxNN0)z$DCtMwQ{DzRFGaAGa|TdZ{=+TL8BR_X0FB*D^F7sE=^BGN6`WWb@0$O z)K@YzvCy$_aYY$JpbjqjWGv6p6G_r@#^`u@IWkbr5V$E@n*`qMrp+_MdF!DdR3Oxd zp^W6h*f2#WGi{8Kiz*fi=OF0@s`{#I51O&7tG1a5&y$YkL5-lM7&OYk$^v1)(Q`H9 zc$s)OvD}yx0~!KJ(&xcV4V{5(4&KSjjEi@IGocQS%3e?(aL$W`GH|BAkZ__8j%{SB zWP((tLp{vgopew>Pf`)MbVm&;d1{{d0AkA|V^hfnY@RV(m*_y!=4gAH!%UTQ%}k-*L|v?EeCJJgTt@T92aQ1h+)OtQ^=VPlA`WzOey`w!UOhc%#Hq}c> z&p^+dY2^mafweWT;+gCCC^^`3X!cB=B88;tu5F}DVuA-SJRMgyUU-|MhdYTtAUebJ zb>UQFHr$?t)+Hje4c*v^mPS-G7LT_=IeXJgNhEIzbBL=2#03aOP+@eUrwc_1=VJg| zg^mx~4MtS5Kv3KrwN+d^-N@Sd3~y%~*VWTQ*U%Yj;z?EXqEob~Mm%jLcc4!l3k=qX z=HRX93NzP*>QgLO+WI6k(^;2Dv+(xedXw-R1`&>88naQ(XfvdvvZ<@1xtEb47Xvk9 zDKhkEIyzWoV~!)l#~tpfOCoYvXe)#pS|94-LBS%pG)D)n9*Je?ZltHe1O8ga)mc~H z*&Xdlbb%qwJ<-ahI9HshGt5L4kHB-483rtvvzxO49ixgc*LHL=);7@7MH+Zvxh`}X z&5(jM1|l3u-mb3t`Y61qGs8iJq)c15=}#^QLcEIif=i8OYmIjZ`2dFvs-oD8^nFnuM63l=I22|mV#%Bt>e z9(V@>mM4>{3Oteyk>%k6<#ClT_AqZW_>IQk9bs-h?hHk9J$II(9^Mm=gTs}T2?!5I zJvNJA$u@R()^nqqAh}MK1cW7li-36=ctV`a5MC-oBd9aP73bujh-ABR6@B!9KoxC@ zJ(A9(!gO^xOsFvfLsrsuHPu!mdLk?g@Kl zmuTe#ZZmVR_a^94P%a#Tk~6~72+dR>xMGB+rL9NC)ASIIX3A(1#nnZ}kO@vYIl8&n zo5RoqtcocFfig64^J2K6+%1SI&NwBy8QPPsqvK6AR3%fL3_R_TTyqNu%Uy>_F`=7z zDI4Nh3`=_pbEuOygiLpUkyNlOZzcgt!V*{ncSW?hvn$sK$0n2Pow;z~zQl2uI^HlI zmcis$Xe&D?J1DZbFjFuL7lxuC!PMRvW=|&>`Z&UM4b1GlRCRF2 zhv}m2tvDWv4h%&vPeVLSmk8IPJ368f-Y6yo7>tgxnW>{Gne0VyG_^8uR&k&Sjg9AR zk3t(Mv3YnMXNZxRg^z)&ml;D}73Ruz#6pnzEHuW6%r#Nr!o7iiF!0i&lTj>FdkBwc zY-LO^^KeG02z>^{0cJuWK=kz8S%wUZ6V9G$NjEch!y|ZZCI$>WMS?cP*-^M5%-ubh zE+i!r6D4~Vg+)M^5%CTt1cDjF+(6kLiSRKZfyit?u<~FixtYOu#&nV=1r9T2aFjf( ztl+B7o{pyGPBFs39^x;@IbIc)D_9U)>qan%^gTN9{`W~h@ zRRbp)*;5Hh!+R*YFyRPOE4aIZvXUzou7kkqaO^oKBL|Ejcq`TuqHAbLGSq{zpjIm8 zK5z=m1tv6EH&Zx4#YxHB!qA?B$M~2cnC^53oCC($2hT;Jm7Uqj7y^t%N7)CTo{Rmairm>a4gFlju)zujd36;>htK{7E~4oX9>4JBaAH^$le$Pi{Yi zY9w?=CdN8gp%FMjkvfh<6L*>uj_YM$!6YhaqYS-W9npG*P#qN4&Besg!rjnH&s~{i z;$=d2Lz&|2^)b%MIy^HUls-p=VdCb@Mgc)e=45?uLuC}!o#{yTF?Bb@3o(a2!JX&j z<4UknHFbhvl&Kse7YN!M>VT%Zl60vKp2}9{#!f^Ej0+{IGVtztju<8s?+S6mnzJ|r zuD7K*-dKl-CS$#vVA|d&B-GN-iv)49fO{$#VLZsf3AjUa43Rzn8XF)fFsvg~s8c3{ zO}69-eT=FL2f}eQHg`Y~5D)^J%;7NfVY+M|4iSoXCmLf^%=HjVFJm(|6}%x`iHK8S zDB4?kL6ohK%1++86nAGKvP7zQn0dLA6%pP-i?cxan1NkrVC-PwYN+EORK5p-i*iRJ z;7nb(vXX@&(ab>A-3iKe#yG0Fkf}ZnLN})U8%zVZ3k4V+fSrF(@NY;Ae*Y^8f$ASz zIrT|I03tsFX9OB6Q zsc2;)cQcdFwz);r%q6Hk)T2Ew&lYhcDBr*+@Zg_UI#xe*ScH1*G5*%(i`^TiD_aDr?|9$5_ z*URs!{Z9c`u6^6QkH2ZJ;<)y|r3&x8vWVUGzrAc%f=D^z+lDHQ{~Q6hS5#|QIL`kV zSYV*omBrnc|9-vgKTZk{dy!JV=k)K>iXIz9%L2C@S@<6UHi({BeZJ|xX8F(9H*Yl+ z>4i^<^dJA9FWV3#&H0~W|Ksn!x1U(udi+|~jsH2YKPFT5{7cw>z3zzWhM=CmH--8B zZ!g=&Z~pfn|C!tWVWoO7x>owc%PjrYS9&JGOOEXLEwTUfz==HgpIAw;nDyp|}TViutZ^#rAWImzII0 zD3Eq-bhC4MmF=cU>5V0_e@u>W7PmTH4*&Vb^*eIH`D``*Bj4p=V5Pih*bT6D$C%@# z(aNb`@9saW12lF-9f;0u6-i2>>&W^K`~JA1zVQ`)Y>^4ueBz}57;bt(H9)c39oo==lv-{gpOC| zC+yxJ`r-muXF=akpV&s_REw>mt1^MIz0b%=yun!WCyAQ=MF%kN^C~cq{*F< zvCe|z=(L$~j8~^3c1C-n$3%BYW#-l5n%;-M$Q1_3-hFqBoc8q=)cs&*WP%kR_6d3k z9MbcXU>o{)-Vh0=!TbI=l#V%}(%keSL>JzesNQ;Rb+l`tC!p-|{Ets5mAQ?Y)(Mw+ zIp$rJZr_G+Z#Rm9$LM(BWBdO2+XNT@)V}{oq1Z!6qPqEx(er_7y=SA}oKt6ge}86$ z%AWD7YJ8Ve|8*wx-Sdmqin1!z3Ql``L&S1VDiVPeuq%!1ffyE0TvTm*I)48{$W!+# z-xRhhZ`aZ~XrX&0U`jk7d-18=^3$3^9`ncZ`fbg5afCU?6;T(N%>=ML9vc8}q9NRP z%*m}3weX)0%kMycZ#*NgJN~qPhkV*>GCx=^+2#zU_*&zR>yln27YY_J7-5<9W16`=%IG=m>ZH z1y=t=MF?)+k)2@mEl+*rXo1x~esc652ikE#=;1$-!A3v6jbWCWWmi_ZICVGR^0{P> zt-nLeE&XroeEsBQ_&25~D~=JVBs`&F+-_Lpn^cA;RMgkJyu`E^R*l9z?v zYp>?wwW-DayW-KdKD4JRcP~#HE_H6&dsz`tmAumJJ3)zT;*|btT4USmiZfgo`(=bW zcn?ge)}S(Qr_4*MaN7OJbg}TATXcGVFW*PR#`G2fXV2!Xz=ZtI0GlH>-*TS082u*Q}C!@Ab8XQ1yv7xpg0Zk|oNDUR=FDdAc9|uHzO)D9Y)yBFb8& zGg5V@PWLll@QawEhC>O?cy z&rivMi2z9_URrF-eT7G<{23~=>*rwjDPEp8uHeanM={0RiA&*ri@m|bi{;lRM+`<^ zZWO-nAG@Hf27zS*L0aO=aWxeb`RL7LLjRkQ%;Jz6+xA9nW)bH6#tVl+?w`eE?t8#^ zGi7k{ZCX!Ee``fe5C{Vzn-A+iBqW_(ab zssBodxUKg|>qVpQV{O?fmxpTPvMxHr7Ix}fytU)0aAJR4i59K#&};@iEcRxLQuGrwT;4&_I^!4FQYs#zE*ZV^uF zf>=ymh7~2Z@G=VdXMD>peT`z zEkfrh_5Zr_{QuS3u|>mw3h~k?*j?VeH^oEbvfe1&SzTM`QE)Gr`_dPn6 zRs6~eXNSMY44lNOrbgh&SNJC1dI{hMu7I$&^}ze?;!g`zv-dHY=jTV;aaGzUT0%2ueHk;eQwsEV zkm(QEfn-ATm7Y#P%hT$XlOln5;F+xlL_C(tPJL{SfpK!qyzv_EBKiHANmfV#I86yR zKbqTUx;chI-SwIxHCvM7Ol?e(hq-rIj(#mJXv=dYPBr5&k->z>-dtm~hRvUdrPGmp zBX;Y{AurdZd9 zSVZAsUudZR$~-zEyTKb@s9D=v8C!#s#U>9W2b3Nxi&|<%h+p-@p0u7#rpTwfhMs)d zFf~@tV|!e#Ghm3ze^wXuem=$sy?y&g*NEDIenP}M0p+Si&+I}$>0HL=akUlyRrkVy zsL$2H5V%^_sHxI|P514an(t&p`(1RZ4I?+zZksWB+^&>%7(;m+Ina#sW0Wop8rvrx zfEDGpkuGXjNB+zW{MG$(Wh_{0wKr(#*V@YcIpYC~$oTlFnZ}*P0TIU#N*}ISbzNM^ z5ZB;bSCv^cpX+I>8VYSpT2@QhH4qN(j#(QG9r!GQ#ym{Rh%41=_#H2m0knDgXiz6_ zbKKFURMR}p>>0shkIy$tZcj^@bIz`u-by_UI_T^f^24@#z-iB!27uKHy+JZdsm`~)HRU_8;zpJT4Y3ig3fR^ObM)_sbH zzq#^C{P+mSjZOkZ7;{PmU5ghd_sSGkMaf$eY}C6u`Kr$DTi=}Tf3|Ep=Qp)bS;!ue z%`X9#F!0erjE`__#{vikI%XY8NX*NqcZ_I?++=$(O+S0A%m|1Lv6$$xHNs zC#xB8zT!6{7CQO3!}>kM$dO>)m&hSRl_|sccF5Yr^2XsCjkg!w$d1EyBH!BrK*soD z-zQBznE##8mfI;o^{>hsd)_qdnhRsE`nmOmhNs z+3^SLj{5w7hRMpVWi!vk-y~H`y!sZT^@Sg*Q@s}#R^E84sEUOfYBMuhw?4=(?JpAT z9ZKifoT<(UaTtb%aW1p;^dx(!mkFmMut)U04kIbi7Th(D-lFK!Q&=&(sCVKbeAOH+ zq5}N!wX_5LG#|>Z595}Zwjm%pT1q(TBpA~5i*25@nJ&*V9VKem%|4bXy*)))4ofbv znQqivQx9P%sQP}s>{(NnnlHdrIsDF1A_07FzU{ux*~KJY%@V@yTmLets1W2(mE{t7 zMN9f;TQ)gTP9pUdv$9|+*KyThTgzSveDkV@sdS~_CU#iKMmFk2%1`xswyIw!tHVLb z9G?uFV7+?Dp81~Ku;U5;NK*UH{?v&M(K3C?>f_1uzC?$Qu!usiXa?_lpbBNHta(9_ zW~XCo-lKYEsa>Qr?2^9RyM+MI<7pX?XVJc?4|#P~HLIz!>Im#tdyO&n(#W{8rHg-0+ah^5TGKS+j#wj$MA6O(U#a zp@BC$bw4Bb()a-=o}d+Vs5JWk401Ik~lHGmD#&no*jy4tprnc*sHh{LXydDY*V+F=k-uIU8n?WxIp^Yr z$7DQN8c+x*wDGRodwyjQUPk(rF(%Syh6zm-S2^l66#R5q>y~QLAl4erv|?&)l;x>Cby9x!%L7 zWg*Yn20A828cPV&es*kQ^X!#s+V+Kj^J4t z2CxZct*Lm=enAp`P9U%eu(LFA>wY93EnV1D@d#N?lSZ3c=@23uOL`sbVyO+%^&J2^gLGZupTz(FJa#Q<45uY*atfT1JJ`YH?^Tf}C3m=7sqUz1 z*L=?$sHe&OeR)uCX^XrNjj#~BGPQwMu%{7Oojvl$rHRkO{~WH`pRz*5-p!Mlsfu8 zR_^Bl(1f+}(!Gv^t3$8Sa#AlaUL1I! z5k46z`LvaOESWvVI|i*UIhrL7CpCt1LkfbdT_j_8i-r=RG9QQXU9ug|NrB{g14yp- zURT~B77swd)258mndncEcRnY%<9)Ahe{L6xCEd=YHXfFQyI-6i|7tzjk(XZA{iEqs zRt$YPlPuG0E}bl8{$;#54L6V-HPtj1FjBxzSM`~7F4TE4pV8ElhVI2AT}Bi}^d!qU zZSs$L>vvny!j4_9Qu&qJbG1#=sYBH&S-|Qi?8$zEx>V>`UOyALuc`ay%KVshwsbvQ!1e*CGyOn}wuo=hgvEIVQ0lN^N)`dEff1om4S!zZ?mzp6rPEMf+lFjlr~jbjvRq93=Rc?)%iWar=ubTR(Hq6T_RZ*KIt(>rN~kkRcX8faEWTE4 zo%;8?`vB_hdke_#f`woGJ>TK&_v3trZpMk1+nzXIJgBcdJ5w~0X??F(srP$rdjCl9 zj%CF4Bvj@k6qX$kBWki;OW|X>xA#h(cyc4mYR&ods)K)ef5~mtnrE~iyMvyE<&8N` zX)F2T{Fc-ONW4JFPwG=o68T_oJe-kKr!m(UNV}O_pfTt6{=;}t7(8b5C`d9(Y`Hi=R$ym!2896yGhmU zdnLstn*Tgs%YS#$DJt-zht_)bO}#VM{HklEajj{t2l!v?QM=<&99c?ZZ$)tJp6rRm zI1Q%rVE6~3JSuE8i-(@@3G&W z`N#ZYzfDPO*&RCF9;jx2KtFzWt{{$@+Mk{yx-4HxNtW#&3ic5|si9HNaki1M%D$-| z4)W~VzfX`(%<(ZR5?*syjGBUX{T8+VXj~W~z zo&9t;<7NNqsqOsk=g{Z!NHk)As(W*C3LVeTFF4iz{piM{$*gMTi0aIxJZOPJ;4 z#N0`4B7nL9K65oemOMD5e1Scz-ktPF>k@JCDdA3Cth7q_T4+qaIP{_I37%|d7#UZk z5Hh_oQC8+X`w3ZFn47z!tO&s;U?Q>kyvJUc_Ru>FzkbO|Kn)Z+L?rJXnVYL=9V%k2 zrL+V+7`Lae>2Kp&V*06}h0diZIbX8*@7?d9(~&;E-kWM|gR4|GM!W7j5dMT0n;uW^ z6cirS1tkoT&8eqBB`ZQ4sSt7nAkm=Y!#3GVUSH17R@5jL3_c1zejzE~*OHE|7zUJ( zeqI6jls%FEX`fbf-QEqM6^7yW>OX|0`?%b!RR~zBl{?Ixx-M|RV-#G@)CfkiP4sM9 z6rEnX9YRfnHe_5Vpy3+@kCK*cr6CLH1fMTfM+PhQYF$*H%lGLAL4tJ25*vLpY-*bQ zEUY+^9NKAede!2rn`)}+&$7E(zg~MWqt$xjYQ9}mk4Wo%8d598?ZRH3ZzB)*+s}Qv zwSAd)zX~(w*@4#}4|epZqtmffc#ZU7{EPL{uI3WKp^Yk~|J4i7Q}X9@`io`XiazDL zc#X9g<5Ti`{OML`)y(0gPe|!QS#PFmc3ls;^%~?pXjd-bwXt^b>e8R`kE!xk7ef?RA`#Crpon>uNW|E$fYQrlLxZo_oBDUW;O8|K zm0V^g$)Po8eB-VpcV2J+mGUsKj~TQ0ho?oByJD(L?QH}ldzhx%GK_9pE~WX8tr|bb z-?i=%9_!nF3od>9m)vW4WP@JgTVmncMI(7Q3j?PUo$&-U|~{R42IlyGIP>NKTGe;nEt}b2&qGJ&XdReZn15@wW(76gRQj^_OPkLtQvRiNc?yjs~{Vzzis4?T{ zi!Vg4the*8LoW3_*4Vo+)=3;sKHGVzWcD*lY*8-r_2aG|oqhb7dboJUGteYd3{)PP z{fQI)6%aXGTf~J0K$=}zIC$_rsG>x*mMssb*M^tk=Hp|!K-NNQoNKkSdqK)g^;$10 z3bT9hOvtIO^4Ybw$p8k-cg!p_0`8{9l7_hwO2&VIACk-tYd21&EG#^i8d;bQTUp1q zq18q7j*GSq3N6|*u~HyUh{%e-57|~H z11j}pL-BSk&PS6g%k>?gUT?j)3m~n_4R%OMWmxirB~r_8eyXdGec!dCYUqI4a9g)$ z6Z)w_Qi@thm1>kL=~Z*p&kLCNf{}vv`ch5`n&D{U#q++z0%lRxQ~v9xB_fk$)pd^w zYJ*C*mt9!V*jtJDb$))Ki;X$oLCM-)lCbN~ySXKX&-+T=tCoT;21?0Xr^RAX<_f0V za_)4u)`1Tlo>%)yhH+&HsO9XNSMvLt`Plu*U zf0nR&bGtQ3!#AXpQC8xWjP$){u419S=j2=?#BSU7vS0Z_kB0`rm*9*Hm9 zUq|_Eop;2}?f@!uY1#j(fqpPTcGX1BLW&xD$WCH)^|`Fp#ruPe3ldri4@<6?d)0?t ze~*;duHb2+x->o9*B86whCTEwA-swFRcU|B0lsD_{_>kOK*LPyiTt!lC(?s};c?!G z??)~vhfmIMoZ}uPMXAgTb*|ZRlY6}T!-wv;tWQ@2*$vw&Ghg#&2F;&zYPcSIc8K3S z-wc&Oj{0`W-x$`vc97qlB^bheUHePjqNsIu{jo6QV*Q3w`k?BQ4oX1}X zo6$*^=QaoV`0AxFy9>VN1JwY;p_s$!rB29W!!%O-xmD#Cp90=h*PtsaZy8(hu!~Et zFX}An+dG_6jkHpY@P$u@#k}^7gNT9t%i#MT=kRqwk5prOI5UF zX92_R9;u+G9~EO!qSQ;>Slf^nEsHM4kjy9_`u`+Q;GLpnZKm&bB~pm}HocbO{U4pb z-W3et6<93Wgs{Bbt}f|SHCxI6;cp8H;d7@h#f$)cgxs2P3Wvi_8}QX_$UJF*FJJkWO|!vHjv}lez%+ zpR~61pKJNxAj>zkZaG$FQ8+CJFji>bx%ZJWd12`b?YRY8Og(KfCsFd(o0OliI>LHR z4FWnkvhjFtoln%8uTny!9zezo>d9tl}yhSX4*znI0B=E60x$|}Q5q7o}UHKU`#XFF{sUA>g@6mZ_{-b$w2Q0M|cQ811 zsn`Cf!_r6Hy@wjL*8K`U28rAHkfj&6Gob;C2zzFvkye;RL$!bPsvwE4V$!4C#N*=| zRkME9!+S1@+ulz1>0kn8%?EoLOBe{IoT`f!;5F!nP>olH2$7wy1XLjc&bsS>&pYtw z@U5lEioLa_B^lk$3Bx&mLK-w>33e}zS$8=d?G+R`RzNC^*8Nwfs`EmNo42>dd`jyt zd9IpzEBeAEzP*_B`}em_tq1|!fJw1{T4%G;+xE*gR9Abg<~6K3OJJ+-UTPDd;rse0 zxBjZi+W{geTy9}lrs`F?&#>CP!h#Ru1hQUkXX z=X6ONQ7u3pTRD2;QcF5*;wA;MP?0u5u)P|kaka#>GhdL-w-*PJcL2%Qpu%mY`E=0Y z5W1Ho`SznS5^B}M?G-2P$}STnPqEIDbDBc05RRA4ed`9VyrBF9@p~_k>+Lv~Ntw zjTOQ+JA-2@6I;S*>*U+pgvjoeu+8qr{wgieU7%Br@v(R89$Pt8W5?lCVa5hH#}2{0 zt;Y*aD((VCZM^+fj+-L)s%X3}1TsPODE?x$5Df=&N3&LZ$vw;%$AAaWOe~b!m~>(1K#v&S8r&*PpdB)h5NxD4X-m?B~T^5m(U*5@n6153}ekqsQ5@ zK&vOfz&32jZOz>E2$Iq9ofr4_6Sc=2sTo?0JKL@6uSaMST52jGyfnRLa^+};Y&ZX| z`dC(L>Z)32ifF8tcDz1>exZQA7H6xTb?W2%J9dYzN_aldXHl>Cwfh{+naEXa9yksf^aS zk{sH<%ABh0_f6#FhjI8@ji*Q=DU+eTl~3oteJ))7CG3);U!H*OD?J_4kzS`4QIg_Li$bkC8VbyWKtBrbgGKMYFZhX)BS)04Nxuthn>b$}#ppLkTLfH1a;u)LX z#BBHe_IIF8qAMePVsylN`{e+sGDLCv(=idx1kPoDs*Mg>ildPjTx%rEUi(t-mrBNb9ECwPv(JEPw~pix0B@dYmikAS{F$ znfS}h=F6oXP@2ZRVXcMCRj)EmubM1&R!u}n%rIXT<=kGh@_!{RT2+@5!@ut()n6bJ zL#)EI&U!7r5Tbp;ZGYeWIsCQdL*)wip5gJ>MYl;#Wo9;|7U+1s?~>CX3)(MRBe>;J zeey{uzYUZIN85XoDcuUi3-31cMt?nnKi<|%$Sd3UyEDx42#5>iAI&E%HUsn~KzM3O zKHd4W`!R8M^tA4DGwCxkYECfxuF6f{#U1S!QGU^%@*LJ2n z%$Z4fIQ6T8Q4{rJr9K`WoyhPHOCFq+()4>>cf0+ivOY-b)A+GR4MidFSFGB!icQonwd@LJ#h&<^Ns?hFEp?jl_c;@HC~jc z24wEnUn$FHAYad{erLPHq$P=GN5D0n3EK4DN+)0K&H~M@GC|^eh0;X_-gz;f!oJH3 zNk?axpadS%{!JZ_2|VCC8-ktBY=x<$qNN0F%;^B6_CY8=&E)#a))H;Z%}TB#*~vXF z%x?7dm)*P>FN=(E%jo?|*e790ndHRxmhM-p6lDHv?hTXjT~Tk?6sl{23(a~GaPIZ z;u`+v#z7q+dMm$D^{$XL{LMP`J17@i3?2qGQs(W&t->1VUy__|iSXE^!i9 z-4zPS{`99symj<+&%5x$jW139>Wha~E418eouj1GueqIG?Xxj#N#@l}g~nc}6|Gji zc%c-nt1(cZm(`Z`OMx6=7Zx9I(&2FfHAUFeA^(LP(D?ik=yd4Y*C~8RLI1I+d;C-r z`~9jzM2}6}bEA_Wz%NfZp!Ig3mL^IlJG$@#45r@ZlG9Yn5$c=YF??z5v)h z_pkmpO9z}gV+QwZNyuuMIWNDXYUx4TrKj$ySHE)DL^-zu%AvD#m6~~ps@Kk#WAh7R zjDTXB>t(dN1u%Zy(H>aqXieey4J9U>tXsTGO~;D~E%W=+?Q8dCw&!OY-MGmQtc(u| zK!VPXyXz+N!)eJuc6CZm<~Q3|cz254XkIN;QzsUmEu;_M6U&Ou<<_t|-*Nv{M`dWrm2T#`D(n}pN$Y?)`|| zXxw*X7x4AhblTZSXA|G!SL%X=uy-S93qLKYbV=vhYoM`;aC+HgNgc9)r=spPdal6j zqrfK()09NZ9}7CX<5Sc&(6wrZHHj}&!>_Cke0iW+P~Q+L**+BYtiPz}M3u7UBKaA~ zFvUHSdi6y|6_e1zYIId^z2rXY-dZ199bYS(7xyf)Y4BG~cGeyH799+N4PU$Pm|q;8 z>N?CVb4mLZAs5z>e_TreI}xPF;uBdgxz(z%)2s>kGJM#uRTu6h%{nCE^{$^Wr3HB1kS(P^zc|oE zgANZ9JFN2%w9(Y;A_ZGZUe}s>CpI)DDNZb$k%J7&ueaw?L&GKEhkX~u<-Nu_@K5I7 zqsC4<#TRsXZL?ddA%JRr61hTaPx6jxzb}=)ArG{+g+C?3 zDyhAz);?wMc*^%aKEH!K-WRHH2_AKqR4iZ}T73W-PtyC>lKjEfEB@I|^>Lrqn-A~T zocXq9)J{%Zb^k=@|CX7?N2j^zw*=9zCB9r<(KvYS8(?Z`ic;^+ zr_OpU`B1$+92bjAlO%a9t!VqAme*GLcDzdSCQ0RmH~Rbe!QKq>Yd$Rg)C5)8p^z1e zH}t)x>5V>z+id;1?aFosH#Q7)+sQV|U-C(cLGv-yw27>Quw>gEZP1Fo3}0)xnqe{t z6%f!;VrY1^$>E{DMA__91$0e|ZBi-!2X~D7+$Ses{TJ|1KSn|Vj{jT%J@F@ab{C&8 zW7&^DfJ;z7GKKzf&2jm*rX+tCx>tXKW3-rf2UhsJY*Abx;ny{~)2f3T+JLF0VR zH(~SYmgLIpn#@*P-;B`*D?Y7fR#(@)ktIj`@o(Jv+1s_4Wj|BnWv5`i7IxvBi*O`Z zfP&uODNPj^C-(D$$=Z^#RSgP2u;}g5Uy-t_PK9N0LCGaCIp|Jdy*4%%D_YRQ_Z|4i zZo!Cs!*|xa6N1M@wG-=WGqvNmsgOqT5;uY50WDut&LUJ8gsuNRBrF=#fv-N`P&Ly8 zxj;dcveUKE$C{E)Cd_q51%pSI8bZ|GY0j9dyg2V=;4e{Bs-*no?Q~+c>O}Rrd~ct6 zT3Q1?p`XfcU2=^*oXmL;Uh21f>qNntQ(`Lsk(gWQ1`!~DYDkV<9U9ukD?J~WP}A@v zM{ydd1KXjZu+>C0H7H>CwWzk0r^Rk|qsBn(b}`Yy znMMcMoXqa@%;rke+{exgpZ>}>cdk(C$%#{C67Y!|;{2o$WnB#%+nGI{1-g!zTRI>3 zFS|#rxLWlN`C~MSS;4-`qc3Y_Pbu!unjjwJs}UXAs*M$1`we!s-VhXiWYcX1ZH|;P z8m^q*1L~c!z|Sht*cmSWFoTV1MPH_JBGRNU{7{D-;Md5Wmvg9qt!2Z`C|}|~R9f9v z({|@ok7q&-7WS%%dt0Cue87$QoI3hvbwu2~7R8IZt3xV8apjFGQa6)#bLIxDyr43x zf<@zFmQ=HK#sOJdkKx4!f1@dikzen$TPdu*`8!k1H1T7X&w;h)Vl{;eC3mx>qej-{ zwNfT$n99ZZj2>IkM4S>o`wjTKEW<;avohIRA(MVYA)u#Hd>?l4X-(uBDE*%Y7DBnV zYE~PwJ5jbDUcYvzov^)(G@b>@>q8H6dYOixKnUkR$Wv3sb`bIW&GCQ<CC#MZilFKCUe#7xap$f@`h0M{fj z{Ik;aPysC{dHWY(V}(NC@OYMBl=c;s*tH^u1cdm7c1vznEXHTQh0J{Vts8_$^-%DY zOKTDDiHI=T&Ipm1xKRxa`Os)lCDJ|dlGL+^_+;Jh>a*aJ5c~5nqp#Z@EhM%J5d0_! z^Rrkfhuu@J!a)0=de+hLm^fDod&=a+a7S*#RPMz;Hpk1e>|y_I&`X5FFRE;-9-SNL zFn$Vp%%dRIxHX5bpQ_#OnJZeB>SM05D$k9ubBQ1&$T^qRpIUX>GjNf; z>X2Gf_Q#}xv|q{ml+RoXvG(LcSasu|I-!1TcH#c`Rl7`agso+}ipAMzNVP)uHrt1! zi)B;cjDr}>rSBmKKFr~S(?`MYC4Oz(obGxqwsngtqJk(cR+3TopH>^yId8a{yBeN?t?PY7ThG%hd}olAQ$F;LDxjj1Bg^JgAOb zw3SSj$)NV|>n=iROMKpPnxE;y`E5V~?bVew+VE4mI`{>C6PbJ31{0LdKbBb>!y*zk4Y0=hC#$|n>Q$2!oEJKi=j3-MqO@nt z=()^n-})W6?+6Sy%`MhV) zp`!d_{k+*%M8vEj`Me9f?-(-Hb6^#C(Drgoj`QgcHW!TaQ(1^=x|T8vX-hvkQFIMf zIF2oWJ7m@~w<|z*UoT|6acy&&W{mrf*CX`FW1J6(ou3x6LZ+@2@uOWh*f)sJxl&_U)?%)3ShYR3X+iO2qw#x_&;uU}i7>)0FV>FSB{R2}*)mOF# zN%SWoZi#);n=rmG{=D0>c9h92CT@DRmv!pz9et;Cko7W>cK%17njPdJ+S>W2Kno(bCqoa7J$LK$~eH z-`tLM#{%t?IvkgDc~R;PY3cc(ogJtcR6U%iS3gl~akqfNjZk&c*GHtN8`Dj{Danaf zeKxApy+1AzIx3G^ix+xxQ29^scr|1f9IaJLPPxu!2EdJJ`^INGwU~O7CAFW>Jo7cz zYij?H8+K_pRG=oi&(vvOW8T)nc}02AH)>k4U3bqc1wOu}UXisEIUrgD;5}!U-1y=| zdnYp|kCTNEYOMiC>fk=b`7{f!4iSJj)_I91?s~u2quqn`JGJ@b2__KPZ^q*TFV}xaRiLm1vYLGBsE+F-Ak30@6% zd=p4&70WQHGivEnw*RRHz))TEs2q1p!}|99-TcuqfKGlpGfRD(=X$Q~ORX&3shjp8 zgf?GXxlAq9P~F_E%dku7Sz3YP<2Is7z~|&YZaYm`(#Fwiku-!S-qgz(da@YJ9o zPW;|K?DmvV_byT%$aZnC95dPgX(;^=>j2}%$li9!wF5QBF~VKPp9OPMzZ~D>(VsVc z;+^IM6l$~O!=^?v!MiFu0~eG-Q@(s{In*8Ed_SG*-fb& zx9dw*_tQ8y_==+J0A=c6n;@?tS(>p4xEpdQRs7^rw{Jta2P#6Fs6=>!fY%JY1yGEv zKGUep;y1#Sy7J6eBU-&>x04&tsoov&kGvL?7x^trAN8wrG?dqmkO7?F4G0}NGpnCV zkIUJ;QYRWt**ao;@8&oJ<`4ykMf>Ksq}_dMx6MYU0v>D zKEcW;<$wvF&F<*Rjgs#{)_b2-ZjATwcb0t$Lh0@;1zL4^wWOt9e$Oey7>IN|!G8Bj z5>S5x!Y|UhYAs1sBQBZ7CWK9U7rx0OowycfZY7GYx(?&O`(#O-%jZf4*wB(hu zY<-amBG6@+c#XcJHUTWY#jFyELyO%zKDQpVE6$+d@*Xq#x`iEBw%Ypxx);b&m2eEm z0g<$B!aRH(=jmderZGsMMY4hy!teu!SK)6G1_XiR`k%Xriu{+gIcJ|Y_^Ch47oGhQ znJJH(m$@JTq~Mo;pnm%Gt7)ELG$(#`+?-G_V|HloWTMon5b~1KT~5Qe@5A-+PqwYo znccY28;Y*kqNw@1u>J3kubB-JF$2~<0vlP=WqolVC!&=2)ta&Q_cU@}+Pl1+p+de{ zJ&$zh9(`v(G2KF2=y6i=i@e+TsE%uuOm=ns7RruX8Q2w?8`r~izsKfLR|$D1MyG|( z_6rwv;4(@AXWvS<_YN;ze+S<^5w0LRCz2+h@Q_pBIOT2964RZ8OM)u-`aO6&sDU%U zV5&nNx_>9MIaW*-0R3JC=!PpyY3}o9kj_5%+!Gm5Drw3kx1~1Jxb?e~DRtn1kUHrhVLOY%*ej*H6aN?=L zh*qB6L+g$p)izxYd(+1N?=)q~7QqB(x6#rMrrqoTW%04=vDk?k=Z{Y+_QDn_7g#YC zFS|OZwJ#h*y)Ak;*bf(X*X{KLjN1!-zH4_U-*zmb^yct$u*10$^7i~BRJ4VxdcjNF zLXu+~nZroB3=oLLn1~razz+Jc02S+FA!P2LlC~i`sbc{qv2@?ocyRMykZof@4ai*W z37AYeN7zM?!mymQnB2|%UlBxo#n{9fO9aa%!R`Eh*W3=Z3xctZe-Nvl=+I5Sx%-W7 zeq%n5$Jt9ANbDXn@5YpQSvP;x-rRmZIiT5#n^h4^D#H}8Y{1s&3IW{e=zR_H0&2Vn zl0NOm*}l^d+$vz<&`vbTqVqjxPrmcn4e}!Gvl8T<#z9vsYL$|kx%}B5><<bq(?M*KE@ z@suxetm$#;PB}=IZOAN-(`CS_biDtFso^R}X32J4$o#6v;(7P$QesI15J zCi7-OW-x+Ksw@9t3Fy6R{_?PR3TWHe%#&B;Eyltn9-ThUg>`@>NxBJY}`XN?e@KD|Nb`V_J&O1yw%BM z0yV+Zr=O1_=AntUTLmOW87fY&^izPFCV6M^D4878_uA_Y8<zzE(`aT%}cLpoiB!^Rmh3r=+t4O^a>a^=PC+v#8OP!PzL|I7M>o+Un_^%7cfIuVv zs1VF4WRfC6^8`@0=3+3H4BL&8jCt8Je81TFNixvtvzApZ?VB0~|E*3*Ube}w3zyTi z#PJyef{PgU&b$L8=$O&A!nh;Q?r)~|3#PB{-rmgHZY8%GL_9AUE_%kzV&Ct$Vr$75 z_(zeFQttSE$2L@@(uliv2U$wkf9~6>`*I0_SV0NVeX1e20{*^LjWNd-CW$Tf9n>*> z8d>?Z`MOC;RTaojdwAi)-cV**zkJbp<(m~_pDn672F}G*9-p*aceuY4Dr!4)@lP$2 z_8@qk#NXhk>}=XjZr*s&gW(-lkv5Al9N0CTmx^}WE=sSQ`VG@le)bd(i7rMH$=LE`@z2Y1xShIyr1@_ zRiS1eJ^&MtL*sz}C9k8q8<(*|BIEq)9@WyXt_!y))a{<;dHp2f0yz2{BrS9VFtDdK zgkbQ@PPaCL9;P%J{aAroVL@p`Ufa&5YyBP7QBnganaE& zbfvV+0!fG^-sdd;*v#p7mgYNa)9^9tCXFj2Ne(qOCEs^|YlxnMM`1*+(EV833PbKO z;;4@P%x@(|!;&rws)nf{^r-6E9#KES6;Qe(jn zx%iD_j!&SF=EXRJUV@wW5S}%FVzF9De8tJy09-z{-0Ld2={=*#t{fBq3<qMB<~r-@MXzrrB`tZtDdxytPuPDrlm$ix6(V{Mu-s?|1fyvn07wotfL93 z=mvp`?mE!OxLOtX*%ko+lr2w+z2OwU|7@^<0c=|fV_0#M#O4F6>L{^>GI^c&s$kB6skT|{78 zqdLL`FXSqkfJ%FB96LVKQ_AVs9VP>0PW)FS=~bx{;@3+fihHjP{6U%6(60~)1pQUX1O{dk$Bi(_oGZprYA ztPRzLV11;2ktzUb<;Rgf9uj5Ap%OqhBqg2Cz8mi7^U(vir0I8IOC>#>R-=2r;`SUd zKQSU|R$V{-!t6L8ptxlFi$j&6x>nQOYw_yVxKx)QcWv(DqK(iS9&PJeHfkIYC<_NzTP5yDsquopo@$T)w8#gDCxA~nn=l7TP zyobpkY|{FvQ_03yKE}qipDygpu5&-836NPM<@U2Z=417Hj3%pcjeCbBM(XF*XyE#I zS^Mes>R|=Dp0NsDg~u;}!;`!t$acJFa{U>{DuhyomF5-Nn9xk>bGAL{v<-F1X^H*D zsL=NPnHKRW4~rEyatOLSN7^V6;F^jk4_T90F$gcI(VWh#zf0F@quMM$-}<=_NCpO< zj&zAam1;cLKv;Cs7$E{C32H&2g6fP~=u%6bdm8(c>f?R(**9r%E7-)CEF_}FW2vCB zLzdKD@Q!6{?BEu!khI z`|AHHUHkvxw{|d=pts@|JEs0cOdcuvEQgkakQ-YXBOSRX-`{hT)Y@a2I!AABGxk=h zFlbR@(=%qym6BO-6F?4iZ0knz6Pxg9oSZ(?ON z^fs^Mb^Fp;&{p2fDG@9ev~-wE4(^S4$JIAn@x}vUiC%j{G;>!J1U`s0Wnp`TZRK=U zcV;BOBz0DNIV0^^WDDA|Vi|fQzC|x0O#c$RNQrVFG}d4Pm0-Scj?qVISMXZhx0_ch#(LMc+U1P8ck)-pc=&sbGjmS>|-d*KUw%~L?dIoF9N)8n!gP8UT=ROt3v?wFniP$ zuqoq=6c&#viaq)XX4`kf>IggI85bJJTk1~|un2h9K*QT%V;40iP`IVnm04P4M+utJ zT3h5gZzWSYu3)pfF|NpV!nyH*%>jget~SsvR#Bvh`RUgWZnkV<1yyqKAnz7>%b&Zu z!*p*_KQs(3{xEE?G#zMHWIL;bAwI7XNY#}TnLb~Hii+CpLsDO})KlI+KfeYPt+PMB zyviW#IIetLkanUrfv6kOO*=`hxp>jR?`6U_ja5=4$L%D^cel*Dh(o1tU>4Nkih)(m z?BT(hAhYk*_aAx$ql(4Lh(ugw7*beO7jW!Wfp4NX)rAVlQc@Hb;=6nCKzop)o(URQ zX#`f>Tu<3i2qsqpmh}vfz{jrCE`+*NnQi1S#XFh4r>#XSppu`?=R84amg{<1wGW^U zE+wDKa>|^GtcML=d-L&RrQ`98D-qk=+n+-c2d};Mi5o;ICRU^_9qQE0 zhvIkVz5MWTOo+u#cKTQ7jePCyWp!+`nV{zFj^0LNH@o7gP!-LC@jnvyaBP4z@KR6% z3+)eMfL&9b)?U5It~r>{=G(vgMvf*6By%4y!lFaBwC{emwx1n;UTf+zw{|)r;(@hE z%FKw_&J~4_>qv$&VZP2MDZgR(W*Fb$f#1ILuxbc|sjF9PTsvG$b@1;O>cm=|Nl@(gAj&&FFB+eKJyeNtKSFY9AYs7@pC8S1 z=QRs?20$G63Q89u%URPJT;QBFF+4E_n})Bh;VVFq`DGocxGUevNAg7qPz0Mr5=#B_ zp3IONku+K3wNiGjGukJltz8`}Pyc)$+h5F6TQG4=b=Ec4j<)EULoTt&^4B3!6t1MP zB>_}z5uI+Hj9OO~ZKP{VV-~$YdD9xP?fgOg#z<#yP0fH3F7d`j^F7~;n9r|=)k&{d zmf)G%uHo&f%2I4!wo+tu8D@WSkSL8UxO6nNMws$^>GIyI@IXCL|ERd;V_3Q0-n&^d zLEmN5;&^TQK&0i>k0(qEaIX2k4QeF8LiurF_9e7XAXs3-(CHT&=}pnhY5+#)Y`ObH zua&wYo+S9G2*Q1X)vmx`MO-DH$&VlYS4gQj!XuAd43|+j`lIx| z?ZYjNqcR)>{(Qq%OALsR`{#A&DN!xk7jNh!C@1QWZSv(I$eTU~b8B|Ucn z5G;ArAADL$un|UZ;h(3nL@~j+JjiwP-1pZAeJ+-E)*;hu;{kQBg`cgf_Uy)PDzIu}wfO8F zFy=Y(Jh(dZQxa6kOT9ig7d7l-XbqddXoX4_TkGi+5cd|!wq<&-dDkleClpgvfAzaB zYFQGIx|u#JZhxjuWV>WARq_~T8W+-%Zrjj)fBpr{OAc~$7B zZOV4$#vCSGh$d=QAMJhJWhS`8iz<0vZo`HbKOnTNU`p#k%4MVoxQ!x(5!oXc6dV@_ z&j$5mWBlhkgq5YhR;6kE3!(NUofPP3N&=A7sKCL=!s`pe?v_e-;FeSIOhSnyIp+IuAx2DJ~Uv&$QkN;XAb= z(*N+pA~1;aavHUaj~!L_Eh9AQqxJ^_y~gg&^kt^@p2}n)%4MC)+xu;S*Ncva(8R&h zET2z;6DmJAp*~TV7HYRqm8PTYf==%z{5K&lOCIpUe}|VPfYIh;_)c>b-W(A#5Xu3mX?v){}7Xh>0Krw`yurcH!O@~-LJRQZ~9O}2CE2JC^oIJqIWB!MdEzF?{+w+$a+_dR5{H(h8I@R$M;|@ zTL|r2wbKT&Rwzti5rKI7`_xN0?Zw>({o7@?$^a%RedoVgC5FaYtBey2i$0UFS%B{F3WOpaD zmw|WfM3&&HEw|BVpZ83pl0csj@PX59?`ma&C>THp9=YFl0UCPYdbEVF|04!|&&5)s z1`7eRpW+Hbj@%lyxPYcVT!2)*)+kgaad2$0!(>f~NPc&ZtFd<5+Sc#>@?l7t%%f<3 z>Ir-`QN;Sqsk7uUNpHuU#_Ei&IE3~OAmo@by55xT;-H&U_zsy%Qg~MZX>((Lqn&v9 zm`8;IZooMcibe-NM;Aug`W4Fs^~c#hVH8Y;3VG(NU-G!t-`S&D`hZ%}&fhxtqw#$_ zKl)x`FmnsCwJgqOEt~YvGHV?n1xgzW^s6Iq*2@ABPU=c36@xy=gj5q*v7;ZViIdp{k`1#6n~3?zbw>dkImM>Nr(Bu1mGt zsiO>WiYkapEH~h7UQFDBQWaq;M0KSF*uHz?3W8V;TklN31UT_B%?Sk;gEQ%cs`Dkt ziF^T1W67umf~1~-9YrVjZ&$eYIpK-*iy>s6KLrszv>s-$Rk*F4;z{Fv`Qg)-Y@7*O zMyuOuVRpcAFY29EMdyL_{Ai!@w2=PUX|fNXK2`eRL0AiGgr3Sx8R2soAi}QP5V8cm zC_f-GylbznVH3PaAHBqYsyg=e0jN;s$2o1u>32Kk zb>bLKS#GuDX-nFOy4#A z?X4ya^d7C?oM}jou0HUC16;QUSl}3)T#2#Ot=8Q(1GXf-gqRWI3YHvS#_(ydWg5IO zf@`!&_3VOzx_D=x)7ETrD0&8#vQA0lr}n|#=(Gy7gXIAxRpp!Y>N57e3L&*_?5TAO zRf20X_Ri{@e)&i*=E3`wj=Yt-4ht?~YrvIzk_)^FOoh7va6bRL>BeffH<-Zyc;#)` zy!B}M&g9fdnSQ9WRk<~tS`(1Bu_MaWIWZQv+PiFkG1mLerxXvM7W z1_M;y`wD_@IN#4IGJiAR%6Wk|m9QPuR)#8Wc811h0XSizarfr9|Idy8&#V4FiwioG z{D;qJ|DRqkY4Zu^k1fe9SpU@v2G}mqfZX@5*B2sAnIPzoJlx7^jYMpHoE`Qf45N*1 zWI)w$aIQV(az=xqcw$*K9r3=>Pl!+mxl-2w=*Cy%iZ}GZL(vKR?jaD4M~;F2*P+27 zk2d}2j(#EWGyyEJfWi6qrM8lQYtb~e*^7iP?nS_K5n-%|wgZnn&b$A*<+3;f@Ny zGn58Uvl{BFE~J01fAzBm$WB{D7S2&F3i=;yqYm}4kw;h<*WB0n(ftbBH$esVMkzMVB3~i=@$eUR|6N8^P z`j7qc5nlPNQ=GFr#Qhl+SW;VYVBu7z zH9sTa^9M6T`nH<*pZPYB0Sjf8!R0i`7O;&i`V%XT2mTY{V~~UNRn#Ae|Ha)ZNcbU0 zOa0=%c{!YA@zKnOqf*mSb*TR}7mna9BibpJSU(#OQ6rEC6X^fRpyZ?14~{W9G-4Hf zU*%7KCYwD!->o&=15bdd8oZqUx0Nd22=#ur0?uqeRnoLp(kZ|z2P#Oj)`$h`%R=CL zhVctD;AUrm@ut0u81r$rqyJmKkexlK-31mn*2kD{z9bX)Di?X`p9Rs_2wvP7I?W0H zMq|=@0|WxS4A#)=7 zXL2q<+Ls%1Z}ce>D4-@pdH7Ag!`@Jf_6S6><~9M3xFSi!zDjLQM5%&Yc1%` z(SZ_`*{VjT@`5fV^^oOLD|W6ul+mFo4X=&_maOHF>FC}hREC4vCSheP&+yN=Ll#v) zRE!{Wsj5*t{wu6e`A^T##5UoRe1jOjZ}kg zq;tM|@M@nRkz~^v#nC!NsNcTEkqvgV7vUz1>h;d4MvR>}L=h^F^zi#dNBieyxZk-$ z>bfWOfWDj27+v*an%cy=Cz+>p40wieE6A!bEhO(YvmAbA!sH0AfkBmof#wAz7h^z= z06x^P>(+M^=SBDBkq5xanJj~(+$??H7t}~vAuIaSUWoMc*WR=h23EKA$!22`zSu^f zkI=!_qjq<%2YbC2I>NvSd9xIUKPlb-%1N>{vI7SJjC5dkJZz^$8MduK1%ZU9#VC^K zYuXh(*7F=qb`i+K0#&mfPj2<(Ypvr`_1>Yts+|@%R|-Jst#GsZxP2up=mKTHDhAv8 z75&XoIBw5hrNF`X{NIn{-wGM0NAPnhd^jTJ7!v?)OU@_bYkDL7@N>>66zahJ$N?*U z*fyQOv`-Iu9JL*cYQeM-98!Y09do`Ql~-g5q>3W`z*RLf4>#^M*(2Y*w0G|C|pgFFI?C5 zKU$q8)XqXX*p1PtThoM5B*75tc-W2NIfRxm+5}Qd3ESz8!eEht<<42~!TzAoDPVnZ z908r5WCg`TEh3^>Kj=R4;p$sBvQ+pb|IcUrc^}*^kL48K3wd`^P?9Zsnk9@F6PvO2 z+p!LX9c{t{ITB*9Dh2xtf$-$HEW4zD5B&RDvDiH6-XO2BDgTPsD#nd>sNPb>sEMs< z8s1MjdkqFoCX-%oEdNaOO>oi^Wt%-g5|;2nZ!RVw`b5{B&yvyf^-^yxe9UQl<WU>4rc=sps0%6eIrn^icsyOk#;xH^Y!{j_rS$*7DG7~69_Uu3gCpmzQp zC*<3~w=D(1UGiBZs=WBecu4cu`bePqSCq4;y4;_~0Nd{$oxur`=LwB`0BSCs#&=Ki zrGmzB-u+W~gLo2u zKStv$_y=_DaZ#*&enh~$^3Xft*oo%&7anPXw|v~O=}`~($>q%bV-@FLf9DGRpe^WfDCZg75tb>dffCaBi{7ky%QV%ivE=U zZ*v!r;rLku&;RqD|7|BHfjvF@XDF1Hh{4`@wdpktr2(Zs?4T6JD|ay3OZVR$zCa>2 zy>H}~*LU=%#|`v8{ypM09__)7vZ{VXset$OsQcgE7ZLQnNaE93`@EsdBbf4Ey&PYF zxyc4IDlZE1vGP-Y-Xh6)NRmWp))i|K>3r5l}~!pl1x(Ia2w5|Cs6l({9Or@dgu-3NT~Uh+_`xC1QURE);d`aA6vsM1s1dNW*>g^CcqWUYGS74H)6M zP@p!X+VYpAzO=V_ZbrPlM)3jVB_^==jvMtQNc+EY|FqB(O#~zrtyIUqQ(2XJ=NsiB z47_F}*kJj${EkPeMXWUSE?o;ej4a!Y4K!_2(Op+sZB{@lJz4{=oQ*CeS^i0{Mq3c%lsq7tH#q124p#IPH$PDFPCtrC zkqP9nVaX?YzhU)Gn8T(<<|M&c=FzWS-T=6I;1y5KZ?{^6An<{7J(lDB&xMP>0b-28s;wU?ok-3zbMBO{ z8lV34zT>sAN~X%rlun?z#SLd78SZwYldlOL7D#qH2NC4h3FQv0vHGTlZyME-#A36i zo;6?KRZKrx$;~Ug-fLLtF!?5In!*p)ynzp9L3l)&44_y%e)^Ym)og@Z{Ck`eMC?Tz zlCO^i4w5HRqvr}vv>@t=d#L~?7qn7ZqlGj?$HpE&J7vtesE(8~IdlWL&+I1h2>+`R z$YS$*L@kA@ln+Nktm zT9=WBh=oM!`&c(1-1>&HPsr|w1SLS+Xx$e8f}^Uohm1NU1N4oZTHh?E3r@!?x3sDJ zJ)MIr&~)A$vw&jw#>yJFb(6td^oe~ccBW?>zwkoNMm;_`3i1+X< zIsE$>rgq-r1uzdS0AG`~wU!W?`M0Xm%$an4#jGiieU7uh&znseJBl+l^R@{*EPsY` z`gl0uJC|q>mn+i6BlbTv7+sKeZF0Qqosa;#P=ICbbcq^?j6ade=s#kb(C57~YTYR& zY=xJp&YjMrLI};>eSDRYG_0-wEVl{j<7rUxR=xl0&KFBRsIAejU!|Ze`V-V%7_!^2 z3ZfQ+{+JnE0{i0Gy7L;KSCFH50Uk(&s*|PDC>+)98g-X4p(PUoZQh=xI=B_&%9WMA z4yfoeXbidpQQWV!K)-fp3T7sraD%YlEUhODj(@XMI*)a<<0@knnwS<3FCl-XbRw*PZ) zfE63EUkpqm6zFztjTT$9KMt{_5Q@c?R(?Q?9Q!%rp(8^l?GKJ0K6@ZhO;Gg!1STQ& z925gaattFIJ14`P)g+qzDunQ%Y1GqtLFjD5rn>phroX2x$MEkL9Y*gK=i6`eRpPM- zQPhor_BH#Pq3gAK3rV4ZzQ0w_Sp7Y4xcNqhxc&%~TLSGWBliGj+I~B=1B_97=JLRo z7KG-^a-9fdqLkf#CgOOF=cN3ZMqNBhMDI5x#aFT~MkvI}BtW;GKi~dGu-7?LhVLW**$wK==uMY({2QzHCyFdT z6PRE$(PBrAz)&1N(F}~)3PyDFjU)jh!>G0N3RnT*PoJHoKKK%NG5G2Y1ERmS*{3^S zd6mi2zcXuB=Awa^&ZuX)^p5dZAttBV=eoktD2J!NBhaK2+TQwc|H&UU2qHuG2h<78 zSpd1>_e+0$i)Ma&nO9=$zA$yWr+NfOAE|f<*pMR8l#7he=1Yl?q;>lh%W;;fo$sx@ z{?2LR51|)jPk^oKEM*IW$<-Z^mvcA4M*sWo&1azMuT8cTDkh(9%2=$X0=uJlOg-=G zkzIkum(Kft|0_JjYi}OEj{mw9{--;GK*Y}7=;B;Q3z?F(LI)EpQKJh;55lhE+95Fensk& zppwr?|EJCU|La9MTeg|*ABU{O#;@F6k&;`jU!}D^M#%R3FJsbwOJMt-U*wY3^0eO( zVRp#Kkw1c2_TiZ=(6abis`qL&)Ju2{r5pHzWBtOzJjc7 z*j9RaNIfg!EM*P6;Eo{%YoxCm+n5gn{9tStD%(N<{1)~rd*nqZ+WeBJ{R*1BX-~Kg zo3ws;b(Wh!mgW`U_`$J2GeV~!yRG9isH;zl+Vw{1%YZX;s|I2tdNz>W^jgEg+B~l%&0B$h$&dJ1S0Rw2*(Vnx%Jm{6z5jFwrdhS2S z@)fKNl61ZbPA$alRH-Pt$oip;gMxQ|ODJOEWaOc4Q?KGFkRB$-4uMCWMN z!6!RfoS|Vf}Z6V)G6DFtmE9^#vyK|Uo<%vpL&`qSNTWYl<#5O` znn!mN+}{t_CtgBU|1j!?0LK#J=a_Jt$+rniKn`OmXS91XE`88fo6Ebl7HpRJo-0WG zjtG1C7r*D{GCr`Ldv6n>dOahIlJ)-J-bV(T=qK5%54eXa;~onur7K2@Npy6L+`q{7 z{P6qZ#-WhYv1L~kuD)bvU=4eBzq_*~@&32w-LBHrQUtFzvc9Jt-H=?0qQBq0wp!ae zg)CodKzk33*|rvPYdnY-Fu4ryb;-BT(9b)?;O|*1hqvcyg5H?MqqIii?}_l@rb?gY+UHDL*}gNwmPo&Nd$3L@9Em&Zyv;c; z{t7n}#UfD_c-DFwGgxlsEjd%^Jl}!2tJA}|xRbLqGnVrTL+y5ICMe0U>nto4Vz|Uk zo);g+A?2P6qJ{g`fO!R)sizV)w14K|^x{p)0G5OA^y7e)>q#=r4!vxHdy8)o`(fDG z>8LV!vPTo=6+G%dFU!I3clop=PM_NkJm#Y~zn(f*&y1Di_p!68k&0xI3oVtV-pO^W z>q(Xr;pVRyvB1u@z7houFo4A_ruM2bWgmTNP1b&abge}oQjL-|gyp$3f$;eolNKrW zRs2l_-?`V@{NnGZ0T9^o>2_xM$nLUX{}YjAxzWe@2Au|TUl%=q!`yo9G(lhj`25qZ zK?ilUn)hDgW&tcavb}4KpSZ=tR+a*gKEoWZxY8NcUnn6|WSTT?^UdFiK&GbbE==dPIk|=q$4`P!{%0`5jBuV_!DXhhN@lV| z)axr$>6hZ^PVR7x_Iz_8fd?Q-?0qkgpu{L<#*@y-ntE#st{Ku56E!}(*U}U9vyDVN zfNdkyb0P7m>DTM@ykf@je779#vDQ7C)ZwZdVSp`N7@B#wuS8ElWNtg|LT9zNG4ImU zSSQ}6hx=Xpdw1E-)`@p+95m(~sq@_YU{HGDY=4suirZFj{=p#I_tegO@7_}Ju-fj= z2altjY-WOcA+A}CjZ#btaLlD|I3lbC_ab&mM+GdVtdvi%-M++)iOpY_2?=-(G0#m~YYK*crzk zyZ-7fwOOoGn6TR>`(~wSp_D^)U*-U-4;7-uA$sR{h0XyW_%t@I&4FZFAwY-vWI)I5 zi>&36w+&YmPCJ$aB-GDaRrSp2qj_RPd2LsKrw2M9Bt4uKF=oZ~^~PPmEXQ_5a=nc8)rM*!^ay@Tl^IiLOC zSu+6K^2_zz_MSd4E$KI)rW!43i56fZqmX?Zc{{jbS>7Zjphtkmx|`!N(E+Di-Y&E3 zqm?VemgIJ~sbJOE3O>A2E|u}YL6XN46x^(aMr%MGKj>=cc+7ktR3soHk%yY`MnNc;|ANIpo_IH?@ zSoClgT>kokzXa`nQq;VU`x3eXA{t*Zuz=oB{H;h_{g_nj-OEFFOwd3owv^NzBm6vb zDsK}P@;PAL7DL+36hwuo6V;!$-WJkxgP=kgSbgm?#u`b~?g5GVt zNyL_yW~@;fV>BNFi}HQ3uQ6+7zK?{$o@_5`_d6VKK@&WY$dywRuyxrzAgiZsz|RZz zdP-L~%zt@7zEsZIn^STs^&07leY|KCHKJHn5utJo|306tg7YNxReu*!)!E9YLDkw| zPZwEcd&l^4BryUMmCi>weeH(bZgyK95&GJaO;Kf$?5yNCke|A*bQ*op znTmC-4i^t_9djvT&93r))s6;)w1k~LrG~@&H}7hG-E)lwwUDg5w^hn<^7lN)?uw}g zOC_|(jkYnM66om@oTh44!{Dko&vcGwJ9^Ag*f6-yEsafg`J;u*D0NR%(3GNf&Y?4v zw8w|BEnRW0gSRTM4{vQVs2_-43AT4+nZN`;b)~5M-uoGKp;`!C$msn-n?5n7mU$XU z?yrp3Q?s@z%+tbo-UxSjH=@Xr%0ZhdmwfQaxU>LFUTuNwL@{b^>??+W29c8;rc-umKgyL&yaAU~Uman&Jun4J z#oDeJ4JC6m%fTl!8%H2-cUBXGcz0)XkCj0 zkJf$TXW?v!a~>5r?LPzw&alZ|>Z1)_hcH{m%0?8Eo;5(Lgf#AcNoMBy(Q` zf8y24Cn2NbyY$$UfSZfVt3gr@yUq(f&z2yLNah@3hEd_&&ai)e5*BM0Z9-m@*yfJ239oGzwcPB^Ff z*G`^txW)b9wDrvwfjg#G9{5S*1yJY$%uDT@$_9fZy*wN_~kc^e6r9kC^9^8fy(;>A5s_ zI_(225;YjELH*v4Dnu&pn!67A%SM0~#`Cwx{H1t~h$g?zZA=@lbuMcZq{!>mwL2{* zaS(oFCLq;c%6#h38xUP%uhCRQi5iFM@M~^QTfCzdI+=MoTA+R4dBIIuM2Q%O=NLG? zE;bDUSF3LvB{HtY8Nha-8Jc8<;S z^DblTFHwe($elC4HMev^u7I%mE2!t1alFUfVCy#quOwdFDMVOmXC*Tt6qw5=U&ubJKiD8p&jDl zzYS@E`=I)SR^pp&JC_Pa47UH}$JL;bp;v?G8?1OruWUG_Mis;GR33=o2lyyXl?9UY zm~{om%tpq7u^~p0oC`K#u@8QTI-f!HZUtH}2o>OUgs6^U{QOp} z5rm0#w%acrI_jEuvaewKtr_Z-yPTUeFcNRvc?KO*fi-LHrr-Ohf1xM5}Wd}$3MwDZ62CYD~Qcxh82N`XIv7}kEt8>+U+wRi@S%J77*EE znBU3!7WpJy|I_;BPl12?T>UYELMY*Xw8h>cRa^a^$~Pw)nPGk1bWk8gFMF6?0dM z3TE{}*-d8P(*sev2xiG?Att(rZ9KR0O01klv%9NJl{F9fPz4 zkuD`l@1Qj4y-KfwKu~%SgwR6?Lg?sO`EB>P`|dl&J>z`*f8_)4u6Mm_&1XJy&L@n4 zl(i*G1*Ke?cagc%1|W=+kcI*`di0=@^i!QuhOlS1#RsUyzjM^&J1h2wJD|;@)&X9N zs|m`0V)C$zT+Ak(BWXKyt^zC9=Zi;J2i;!9@AUhQoY_fdCF_@hWgH0-rlsPn;W$sr zmwN7?*Nvg|Q_TUn?2Z_R;uUk(L&D5h5-_d@S2-z+XOv*MRSyn}K8jG6o`$0IUq_Ot zjF~-49_ihFkvP6+oa)i(Cj+Qsys9w;=L5wLO{PCQc}D11Wrg(F^>ldDT7ALzi}|Gl zvy$jox$M>cg!0PJa_8V;OrA*4+f7iuMy^L>24<)`K0tsd{&rpai|xYK_SY!!S7{)a zN&_g*W%^xuA9EzIdQv`P{kooyy&hGlZC)=mGLwXAFoUOZflA`_|L1}3IS4PX$GPMh z+iQ9(n^5z66l+$@7S;q)hNl(fc#3k|jy$sqUL}BqM~9p{>=sM_LbQ{)WC*@Gui3XR zMv=W=6szIaAd>N9{%Nfqj@4AB*2S3Ek(1TryM^)i^A<0nn5oiVTuJH_#7)4rXLGl0G zG3Pg8fDprvo-kWOg4^mrW~U~Gg<(0)$7?E+3MK_hF<8US{W+WK$oRdMp>w!IPdW!V zPn*a{6f`#so#4MuVI*M8fMf^w^LJL&~%6}j7*?&IdR?O0^b5qU6)9%aML!y5Rn2SdL{RW2im!{H1ApRvZ z|AOs;6aTTmuTP%WQ@pMb9^X%uAbS}pH-7?ZN$WQH|JSMZ)#O|iqP}LOUoF#~n0yXQ zl8~mT!6_{~=oABM5JdM=#$bymbMtF8)LNU!gzI0B*`Q3H+xPuBGVmTp=)ed=L7Ho- znK-6=BB4S47@(T@*E7dE{ZD@8XUo`sy+Q`EtEv9UU>82~QowxpXIXd%%Tj{3{U803 zBb9!AHT!+n7i~P)0R(jPtROSS<@eEwPcSv^i0wBnWIj*!%=U1=8A<2V ze6)-MK?GDXC-_poChu(mlUC94YSt_7cqUgXrMt^;pa|i_eHsG_Se$a z4v?29^_&WGcK!aW$FyTWIFM?}GM2Rg?caeZ=u(pmG7>xN&A6jQD+;%WGyFi1aTcP- zO1juJDnZ6)`=-Cxes9TO)1K?_eopDR!3^RCg}-0T<7s{FI<+1Rid*RF98g$e$4jZC zUTs|_q$-XQTacF~vcH!BNmPbaHc_gn**N=~PRY0JvV=B>cX&CEL4;a?g9k`>diuu< zaynJl{PZf!C)Ke(4zU+5$8_?%B{WuqX{wpo$UT>P2>$QSFx7~gnuNe)0h_hP2qqUQ zB74|Ib<>%lvkQ>#9m@kL9Xtufw5(tzr5&HAS!W8VsOLWJRVeSyp}{<4mUoR#UP;=H zllKEnQ>GXy|nz42JA%{)Zj`p@q(_wIo5pOqR3w_F!2K&$Z3`5@c4I2g;2ggV#SNZ*MBo{YRG&B ztf32Nw1fa((3A0CQX2oTJL|U}`C0+gI;y`D?Qz#BRGk!7MQ472gX`lZjuOt-rhaF5 zm!-I;dgHrOa&~z%WIX=*sGK$kQ$KT198LqL{g+n0$|9g1%=FA>vGxd z7hSG)2yLI#^li%NSS9vaSiDkJ(d7627n3QKJpQ--G9ZGpBY>%5`hk+612%Utw=!S)ky22~?nQEccA;RiIB1-Bj&V!lcq`RHpik zdlIb^^>WU2D^*~~x!@XLuWt`a2n3Kvrs(;-zYvdq5sd{78k=2kBM z*z@-04_FH3o%?&%>8!{re^!8}`_UgB+3vEKCuoUWUz+xXlpxVN+H39*0 zP8os$@=2B1n_sJ>thIh4r8f)sPm zK`Ig=bR~K%Hc%wTN*0WPd4}^LcK~UOaEXHXiSe9nFv_MOXw%hwx?$mpYs2I%HDK4R z^M@IChC^m0)q+I|dP<8$ki)EbD?S}!FKBEmGX%r+{j8*frh5YCfR6mOD($8An5)R+ z#EYDgjgyT_2RBw);W}an85y3_1Y!#``d0ljY%@uzj+mDpvVy@Mz5wjPg0tO zB&q`d)BoU>M>ov6vorOj=ZDjGo#~gm`>v@{N~OAXFg_sF?Ipd*$P0!CL>Zw3;zt2+ z$5rWB%RBlo*F&<8r=I1D#H;fa4GvCmkI>Z&iL!9Gwdo(@tnjf+H%y#eqA`2E&J($U zM2;IVFKDo6Q0*KjcCBg-;ylvsyIQ<^t@(#uJ=bOj$5D9i_deh%^{DQ&0Ov^{$YZ&( z|5)I3@As`1*ssiMWVIgKvnDSrx;q|@I4EU^Nma{Sh+2Fu7Ep6)gl59TRpR#R{1GnU zHPObDCz8?Sz0&VfwJKf*Nc}$Rq=P-4%y5mGjp3jEwTV_=)Kq1MvDca{`K-PKAQE-d zP^ap)&@Hmb$ml9E>%t-OLMUtIuPY&h4bZP8I>| z;^eT>o}qJ2(QAD-@trGE#CF$f2Vx^b^7)&!(2cLGpSWdnQ$yZOmwFFIwxcb7mI%?B z@IFYF_Fk6A7fWYrSBre{eLP>P=Z?n5I;Yeat8OejKyG}$*XiMAH=oLYuOs@CxY|pr zAhzGdFr3NdWSi8l>$69 z57&;XY`EId@vUt>q&ZjTA*S+7cPxY0+Hc`0(jRcEh4YB*rtel3s)YEdQwE_$pu!)S0{Vm@J) z@E4~SZ%q~QSkSH<(hKT8^g4CW5ybB7lD3RUKvO1^LcPHFUagyj`?uSvtb5mX1P)Gm zlh8c>EG)>Iu>ASour`x&+6R3&srii`#a6`eAtw4zouUOav@iF`dP0$;<0F`n$@}li zy(UDEV;FwRke^+ND)>V{&ehLp4W1f8$4UcV+*15yIf8Yg0CoLXq)imzhK&iZAyWA_FRotWQyGdV6NWf^A8zDMjD zGq(}hGBFjUfwCXsEvHkbnPpFs9f@LQAl500URm}X``$2RdTi~iw?Oi!?w`S4YdPZz zZ+TMnc3Pt-6|)OTlH)}Nbf(Cor81!LDFcy659AXce}e3*Fx`548#XDv>6{^62GXaAdXeL;$m9l4daw_W?g5!&&s+y}kAgAq@^(%4Mz!&?IC%Qbh;%&~`B z-u)&^QnuQSrm|#JO=j>2TJV;i)hjL38`QG$nz(Dpu64|n^K&&`fbG5B z<+f#+$wpn(qb%%tI^?F5*^Q#PwL|NI0r)*{JdeaC8Gcmcj-kff>9Y9R&aMNg10C2okg(zwVn8V1KSthYx~uiw&6KLe zpj_aU>7+1G*49&&ya!+xJac-#7?^?owCah>e-x;&J&bVc(STT^=H7UxF!C2(!!s4sp!qAB}P zWlIMtJB4RVm(UA7Z8aUzAL(QvB$7>HEI1xbX3D@sn~9&@lX9>)hx-$`B=OI&G={kjhEDYwJ$bfO;LmVaPm2dM! zkW+M0#XHNa+|Qu4kKX!WZ@?OU$2x_OkXgJcVjJ)=w&sV<3D>NV__zCMo|t!XSU;Gi zB8y_<0%iF9zcBIbS0P$-WWyE4PEnp%C5GhccB&w2-8af1-ra*Xlh`$T!w=k-i*PX` zW1eOdEswQ$_6jMM4A18(NGv5&7m|iN_*1^fDKEw%e+%A1dyA>E91k+G z3%ZV34m_b)HHIs})_QeD<&IeMwTH8bW!7#C=%`k)J4E$}=#gWM*EQRvjuIlYK+pEK zjvo|?o{4O@#^~sEdfP*7>*KIGmw{T^xB%X?51_pl1*$^b7IdFG12gD@lM#KG*k6aX zAFM9s_2ia6gr)H^FWiMUYg3pD#7h&HWEr$kBNnQk5Mx(%Aq zqRA?Oih+wD1P;(F(ke}{cV@ef6)b|c?4*DBFjK9&J#O;UuY1~Q!Zr4|9v}#j_7re- zhCX5l`(d;5VzwFKQ$5)`d1t5j*>0=|@_I^Y9upqqTO+bNcyn&ibO!8`&L7{W%0&~J zST$yd#2-$nV}-eBmWBQ#Pw|{)T16pw6+EM?L`ZJOZTunirGgW!7vhfI-ROO(!5#0x z!#1&B0S%z%_24dh($lR7w!ss%FD0owON_E;r&ck3@VUisPn!@8SDXoww>-+?O(vB! zk!e3^b-B?_b-+aM&k?CVQq8BF*!mE{N=^uqDLg&@>p-mK;=Xyw86q{l?3d~IbcvP~ z&z@-UnVs?k=!;zb*3J11mbSk!N#}wQ`VcEg!L`mXKL_NTNim~zn9dafPh__n@d96! zlDst@b8*-TuefmSIieGbA2(x*g{tD2zOLJ%Y1gSABY0`X-wDPXZaBpu(@~VIDQgaYakH2GBOzKc81Wh9}N+RdSSR#eyT4`48Bo(Q~&ENTY4+;b-mFqug|GL6HiuY40jv zDuGs!9M}L!!DwHPxFy5Eag4Y&vhog$drqF|Op4V}Q7w!3{XRYC z^V6^0s8iyu8+Pvc-ky8`P&Sh!APTW?)e$2wC1gF!QtD3z(ZgL`&Z@t+snY zkQW!CEQ&mF#g3?h_r}`MYX(O1+n!~qh8l35>OBOR4Au5+Q?L!w+%Ky}jgo#HG5l^| z#G@fjd&qJ8)#~M_Cf=8jw$#V?=#^q_%ID$wtijEvh$L$ZRzfQvp+fiq5Cp9TUn~MNX7|$`B?K-Oci%! zyA8KdHL2_=rTD7nr+Pr;uXpPmSaaFF{A|o?$F#|r^u8LWa8KzbrYdUd8)M`9q{%@A zR$A=bQ=wmb3N6NDWGGyvbyt@dleiP}^LO!FJkdi!qHMU}NOo1i72C(^**5(OsPXka zl5AsgxZb~fOtnEolg&n&)x-?{_C{4UJHBQ5`=j=+`@zjRScUtOk zecX{LhoYe4w@VDg5#rRamhM<*Y@wP1j zr?muLHu1kH%h#!!?r%EN|J29}#i`xs1oD@e%h=!ReScOB^KcWZE-K|tH^Gj-AR1_P z6LT-RJk+I19IHp%QOM0ve0>;bMV38hpF2nla#p~FOpl7_8TAA|M25->F~h&)Xm8Qd zA#odOL^paBo4~+DcRO+on_DIPoC8x`GWuFxrxtUnSc5Ufa$QdC1lbD4>Xi8C_QWFG z@Hi-V%c}#aR|v9-hei^-r)3^{6jY`bVaKaG0v1$xxZOmFgRJGX00Jwlnu#W^gY8c? z;N8DY%0N^d72+W1mpSVS9+hDKu-7I#SH2d z61767FIO{3e@;kmcv{HoNh7I|V6YmQEUTBZGcoVlboa!%eDq<}z?( z(l-R6S1;_;%LE(bX`MVj*`l%W$=G1^cT<@O-o!g!tuSf<#*lAC>5?7UzLyp)4WO2+ zvT8HuIsBX1tz0Svi7XQ}MJYAJrkY#**-Z`rbb8$dAB&Xg(l@KvPS7lz$2 zC2N&p=;C~$orngRR;L&n-~>}YR>aUEO`|-dO@sHz_)4BKh+$Z$rr*m=pKynHgvd?T zWGtpH;#mhiiUxzpH{rWqBJ%|}yGn9E46bC6aec+j0nz*f{AKO+29pNu>60f3%d7zC z?OqqGRh4EHI8(d?D|D$dP)y9*y3y?gIJKvu8@TWJe((Xdvk}dy`Fs>4s511NSA$JP z!5YLmU()B(XeG!Rm%s0mb>Eyvo7i9U^ty>KMVMU zC9*|^W?ayEe$sQ~uFQw<(Yx*SB+PwdumW9q9iP+NNM{7wz@3BaM{LR=jz#15t69J4 zwJ=C|qHsC-LXeZm21(8IZSLuQR{t3p2_LTI&?(N_1)Gj{X^dXg6uV9#NdGu3K<(U_ z9rtp!q1>+O!?c=?5tcKE{sP=^ONfV1o7jB?!uaM0CUokJFUQT!8w^{k7nOgMN=iC1 ziV>Pzph^MF`yAY#^l=@i+f5-v?FFcX?BHOkN8~3 z%>!`sBXRBnykbCxq65JrcFKFIrY zEM}REp_s|<=0N2{2i+DUAUQKirl|!0`uKfuTzgci-RG{=#Qo|)2;(KpQFG;h3xSzr zxnc;DQJOyJe3yEO?5f<~qNCeAoO@-b(mcK<)T%)FeRdlCJVRmE$Dp^Kc%98EzKAaW z9>oU*R`2PV7Iub7l0a28n(^TL)6nxf1-9pd%e(E!K14Eij>*e+>p~toe0xfk5{Ldc zr*Fd1PbFN6i-{d`B$b8Ll;#4tm$#wt^9}Q0QU#+w>Lo@8ujMFOMkH&4e4uk`HAzqa z_uclD`)R6`Ue`E>bDw~A?sf6Mke}!)fv^4wZV%I|5gJaPI8Mc!X6}D+$?YlX3Zguz z+I0A)mqyQInjndKeACC8PzLZ2E0_pzVRynui7Hm;btZ+e(pC!tZ^^XHuSsoRg7J2u z-&~})Sy~8n&g_a=9=SLVq2gh0E|*y!)X663+sK#*3kaQiP?LoC=U=mKrMaT<%&?{w ze##s7eo`j3$~qo@LU0|xbJ?hrA!qM2R0bv-va}pG2iT*KAre0KHI=cs?$3N^&k>kH z5%~-P&KIK(yOLD|-dI;+pf_h*s0=30zI^o|OyX6L#DmNU552?Dw4F-P5EoSgX(gR; zl5si4^MG~E4|Gi%VQkTFxn3%RfwWWkjh}sibLjkB8`*vDp(+*mu{fFt41dlmF*6ZY z>pq9d(avuKkW6A_BKx$XDv-@VB1#154Q;97{j@KmW)AU*h|sT~DrQ%32MctNH`_f6N(!OJhuMqvrWm=VzV{+zQXAnNC! z2eVD+ThFKKT0K^-OGmtA{QAZgJtJgXSJo$OCtIjMinXKZk`6y^IM%cfJjotdH+Xsi z8FSv~8K6g8WI8Guah60JzvQWDYDcGxidajv}1zb)GTph{R zop1HOFb~ojSf5*US!0j!zEqP|HDp!gu)+Py5)I}-X18u$I$IYU_)_Jy&>3dKB71c9 zjzr`B)aw>CmKO87cR>TArS#K>kd4HOR~$MQ8FTQ?dUn7)f~h;ls%~L?2<_RPr-Mm9 z8c;%JJnGTD`=n>R&)n(o1X$!Q;VLj(LgSB`gr+m$Q(4wnU zZ_PznuFgF_^YYc(p7(SHjxlpE^PzL*va2t*8FXh zp}`O=c_%*NVoTUDX)viQf`tkCh9p#{6FPQ<$_9JaWtxvNR77#XW%nx%GL-bOZ~@%vi~7 z6(t@1bag(@?`6pR$g(xx=~VV)adREa36MVKFF&twUrK09@4j?-u;KO2k&T?8=VD3u0}r z$(Q%DAzYPD57ibb^yBS>v~|Fg`@EtsfNp1}OC*`#?|&VRzL?qvugL^^XC$fN+bwH9 z@)oy)DBFJNS~D$6O}a+jpbQd^|NbjO!JAFifOM~k?V%cbH&q25PAd=)nARqrtotz# zxTmi5X%()LRR^*4C?tq;QS?$JCcxfj{s`I}%Db_KrulM^;>Mn^{!uukiuC?!wEp9gWH?+xO9`Q#aD{ zw?*1(8-6D*%1pxb5KMkdHRC61Q7lsJAeH9YzdvIXbaL;z zdt^;_iSvR=@4aLu_l^8gByA)bR_LMYv@z@}YqioKDw|)f%_U%GWRKK|a2rorlu2Tu zn9C6KuW^*6@M(WemhL0Ec|L7lKiSkT6@Ho=6|||=N^9fOvVPqhfY&y+@J_lGrzVAb z@0W+4vvq=dVChctWIx|t6ZofsfxK?W{M_G0o~EBBwZpl7(8&cM`I2LWDz@cT8p9rU z>07i5KM~>MG2EnkvMD-(STj^v)p(nzF%dE1*{-z@TA`Owst zNKw$FWKA3biy;{y-6u6!2XmSM%jO+V*Wok8K$n~fWFmhfA}J;HcI zZV$SWu5zG=_RE>_a<^kkN|tizVu^V8_B3hYkb95XA5zyW7APJXID{*DQYT{HgPb7#%8yBP`lsbB{A5+;i8d zSRWXjkZ#*L#|C-`nl{$m>=gP}H+BA54-@vOlW8$uG~2xqqG+$o*N$nmI`0mC4c}C^#1reysXYIX6bwSNLyyV&YSG#km zX1+3BE^jG$H2TswS#&vbQq+WmGaH0xztV;ZIg(5}r-k-UOB8M%%_Omh$_66VgDA+)ygdGv{o?rOSlqF|0U=SOem4D#cRa#rkpFj@lp2Qw#nN99MKj zRmw!Ch4|;;(+U)fdl32rJpgT%ZpKn&(eBZdOrQwKTw8( z?rV0)5w=nRZlBODe4vFnsnjIMk_^Nsdz6W|pZ(QhHPh59MeiQY-_T?KGT>z5I+d%W zSN*VZyyN;}a>x~yWZgzlp3|2?tee*~M<3I|!mhFDjdT$k6j3&Ek-}mb6t6YD%WtpL z|p>-V-(C3 z)i&^Vj#-SbZv-RVpG&dML*{-EIxOCaT;^SShiBVK-@%kN@0!OoYmDconyoJ_y;RNY z`MWFZeMXclg4mppz-eWgmQpcG1R$oRMw+!f;EBg%zRw5kTbas3T@f>h zU_1+oVK5?LMP<0qJt`?Z&r~I93j7l?d^@Q-F-NMj44Xn#m@4a|pU_gH&wGbn9u_r8 zPl&R9D-W(W-oFK8jKBZAnri?$%S=~+DJumss6d@{2h&exfqu@D6+Ej&>DM7L2V0-F z^-O~kah0=lKS~Fp>AzOkR(f-u4-ZtHx*SRy%=oo=Oj!?>Qct&=@J=C(@zJ=XJX2bx z!nmjWcZQj=0FLg0EB3^oGXqyLeP+E;on7>el@T5-(E=6eMKTI0D+#!lfb z=*mA8jPRI%v$t>mMVn71is_~DkttUAs_L3%mSCxwzepP6v@f;;BQhZR%YK+vbe(uR3EeM<}}C<1njfj02q%S1w)SJ(lo+)~UT+ zjGc4O#cyE`horXZER7S2j;lE$ESvNx(x{|NVTslh9auO+&Sp%Lm{mvbw|z?gatX3` zts{RwC_Pi#@aOTM*d2Q`oZ^}CP;tCqw+Q80ozKKD+d;t*f$^mj$nKWNZD{kQQQH7s{ zW@mPXUBbw3Njo*t4}tjf;p~tn-#_a7Ucm6hJ0J$rh^HW}&>TeWM!6>u=$rFAY+vT$ zUl&E`cWYA#+v+}z85l-E(U1(r9!BYuoku7bc@tHP7mb0$PQ!dKQw4lcT62ABwZGiP z`YUB7u3-c*au#8i_o&C@;Hcs9hb+@q%vk%8orT?Klb4D3c*|(X3t^&}SmWj6uqLy1 z8HvjbNFbPhcAscQHyG0mdoM=`92MwaeCE65lXu#>=%@F~>?*a21Qk=x@{aAW4adB{ z`;$a0uOVxq(uFqt4|Lm|X*I2PZrqXTSr^gv-uP8^4$lC=f5fF+wKWYPR&CYD4D=Be zrl{fak0*V2=q0x-#x^533(WliQ$97Y9bUxgPS2BX9wVKffAt9zaxQ!l2uT>}r9-uS z&(Q!@V5Wj(cY^pVy?cAEMb^eSVP8LUpV{ep&i(okQpLGre!n6ln>59pdFv*Ia_rj2 zO`U0&^z)iq?8}W{yH9z$+@;zxg0wC|`>FQZX8d+j=7<>swp64I37-22(2shON0nX* z8s2Fl^m`1SOZIcS*70po1n=vMufT?1*;m6qsZ?FOR7nu&FrV0$ek?Zk1mp5vCws&3 zOY4Cr1y2gwK_AB~k`ikTOo*d@*kqB?#_j{6=eM&4pA|V}SR2FB`6IBn`Hs;B2CD4+ zTlS^dCEDk(00@ zh}3WWWs~g#<8`(5ZIQ7HV`Z{o@-s1kymuv zQO!G}84U9rmVI8QKg-+Uw~;iWZcyw%G}914IVHXhEc}$T3mp%NL;b})0(C@Hqj@7D({Ll3HKSh>!}OqlOP<4CGKN&SlFy>dUpNT{}_;q*oV)P;vW4v5hpjoiV*-UIBS zE#<$p0I!lU_&}d^653-azI2bK;6NtnEox-^!6$1vbAj1xFQgV>1zI&;`@BuKI{p52 z3SoOZ0o%j-RFQr4ofrZ!<1)om5evk5$`ll#DrC+Iq#1!8lZ$M1HK9^7)Kg4I1Q!ck zJ#CFA$YGLrqqF=x$V~9`s_6qy*FBBnuDNw-KrpcDw^KOm+8tO2*&O!#PiJO&U;_Z|&2Svg(ALpDp~4q44|`zwrg` zAxUs_QGK6T7Ky+WO1;XyIB=U)Hc)9HcZ*=o0<%<|^qail@aFtmZ6Uz2V9xm=7M`B> z4_MjHR=sZ{7<&iQfZozr>C7xr*_1`A$Eb|J$+u;!qm{vE*}Wl!3sOe&LbJ1v0Hwg( zO$WSe$LC*1h%UK;R!Z1Ji1oGcFuc*hSyZtwOY&Q^9jau@eg=alm5qSxLs4Wtz&$Gk zC3H>tY5ixK#swqeEIIt6s0pmO-N*nWF7*6(_Yt>H#m{1(Noo*5;x2a$`c5*LAYv#= z!y;4?ZQ3l+hiih-xKFm|)KFD!ns3&pL#5pOYH2%#*xIdbsaM^lLh}%27mxmQp`zL?$9mY06_EkIJ_P|D z$lcFM9gTI*t+3KPTb73wt4vzqQ^!1^)~B}*Mh>K3bvrNh#l?M!3!$oGMgPYKrrdOp zJaXTQg?5#i;L0mk{^4r@h84W;t>?t5se+@Vtq_2gpm+VcAr9*zzGIk>{TeC+)CeOS zFEnC>49vIzqbzBWU-HEY2344LRT519MA1RKs7K;Q^ilU%tblNpCFYR<`37qs= z%B%7NCg;XSJnR1Y@zhTPxfgieXz0JW)2`NbCt*}qan!N)hnW6%$&p9Lv1NV0j+D9gs9|l-zJ)6waF|2;W zzw2RQJl%xf2`8@0b3we5!xDogu4?^}Ctn=@X;lIlaTSE_kCQi@b4+t~pGbt&`{j%h zCWc14FV}rQN8;XgT^l6$nhxcyZ+64x-P7G2Z}cGFGDWsxD4&({gW4$`+!BJEV(k98 zgx}j)2Y&DWKOkux=urqGv?bLEn!4v$_bu)r8Suqzio8H|(ShwNc-~2dRsA3P<=yjJ zF+4^Y?hyZdG8dR_2EUJBIyh~t$s!t#Ru_3|j1@MHB`YDbD(c5)CkJR-$-c=_SBTNK zmDudg^LHN;f_UeFPM_lM1yfRC_EA&LWK14~NUqA4DvU1}2>y+o-8DA5Yr#3a3PN^u zUSu0r**t<@D!av@E+~-OoDQ|*+g>ZmP2X9Xijef1_M1Li``va7Bt^x2j*F&0OGQ4Y z`}pXIjH8;G2a~53D=WqvlE~J$YFUQ{hjZ5wr8iZ6K%nE#2p%IhQWqG1&sgeOCjq%U zL^T}UyJiT=Lj1sOQ;WoKI%IXEO zN8B&`n38Tgp4C6uF^KFvkih?3U$5zMTFo(w*ao_o0_nnq zxR@!&I@ZRQU~W%m=DWHQNM6!fvR_#T5S+9VVvk2RhfOnQl4+!{DTj~Gq^iK-ZesMP zvePfz@%BDY>IGh;pubH1osbu_;`vqalc))VvjoVSOkWgT;T}sWe#LKp0`kdA>uv$= z+)&m7IfWH;G#3%5uxv+{d}#1aI)*Z)jFc*FcJ;9O2=;>*6vL;7W+hG>-A_R$+&gr1 z(HH3QFR^NxZ%$&SY+|M%({-0l*a1um0Uv;y!$6XD1mPZpJMH%V=*$abbNar>Yjp4- zT+h-Mw?681x)=G86mnIg$GS=`Hs#e!#KI+=K(@E{=Rnj(z&;5TE3;=S_oC)O_{RlF zXjS%LI zx1F{VzUq)!nl~o}re;6!H3_$wFYZCr6Qte`%Me#VSm(}yze~ixIJv92;5pj5V>X?$E0{zc?BtC96})N=kxC>oOtpk6^Y%44DaTHC4t zodhc5?DrZrRl?nB@IVgCEWFliPXK{qugkg{f3A(q+5af5L78N^QA)EHoLn*Wn0)c% zPmJ%_o&^YIL+Ev0A|D%?}`nEe^L-MLQ%8X@kA|@f5tn+z2^AeamD9Qe^C~sL+ z?NF3T2ITu}6c{vgk;Z>vsY6TJ$ynTJM&HYLFEXEUw=)%pt`K09^H`*N;tkt&eIL&1 z+Cg&Jfi7~{nb#V8nf>3$Ee71cInPF2X78-?s6um1-N!c%I7bsK; zC6(~>DM$Vc>bUT3LNcI76J5RLjSKYY2JTH!^QKM@md?Rnwqw*t&#+JQV_y@5OFIjS zJ~UM4ZGuphaxqYB{YWF6YgTdRg64`0gE8y>xXE|iQqX|T2!yZUpe$p2;$34HYKjZt zKN`n^!p3+~%G=Sr&F{*zcV-FmIG=o^oyj($`cejdTH*iBlz`dzRO`~y56a9PkGoBM z4Do&%hiMbUtg?s>VewsR5q=tI0j@*K_lGao$-GD!shm#LK@4P<1l2%7JXYE0Fj?V$ zpjP=EXj=vsKfm1$(~7?8L;dp_((t7n6;}y^PaRkLkj(Y>JHXozR7#JeO%}?CLGC!i z+!FK?`2+8Q8`%R+u!|m*5{!|3Dd$|KVbD*6|XaYR$NhFsQ`$HC}^=j^kK5|Z4aJ&5b`;@ZF~J=?i# zAC!TATn${h*v_|8=F-S=xK+&cQD~Ws#vz$X;DZ3KG;0aGX<82~kVhJs-=6`bA;&(S zTCBmEoBV6d)8w{h?ZG=X3SsHBv}r>n|O@IZ(5nuVQ8W;VjsB z&uToj_Ho7ox;AJ8&|-a`lE#D_h2DQVP^*2YM$55x9=*W_CP8Aefmgyit=Hh;&h@tk z1DKuNlCWHWtV~N8Hj~1`Bz^zfb~+p4@aQfrF>8uf8Zn@%+XB7L%EC%uvTrS-yN(CX zvC;#c<0|2n$ON}Uc3?&*51C`^Ls)%S&q+QYRd&dn;w>3}v-dgZbpnc{H_8Uvl5;$2 z9wHgeH-)`nCovD{l_U6TZ=MexSWoIBvR&cXT(9tclXnHx(Sr9CeU;WV%(NcH0kE|A8TXMhKYA2it;ylNK zujuox@SYMZr=<;ZFZSek`JJ2%i(uj@%qxo_7WE$Rte6E&f`9A(NW;fCdh?N+H@Z@n z8os;{_>h&qoq39wzyX5ly1mG{jKl`~NCMoENZOz2-(jEK^mKVZRn<1PGLUyG@Owvh z&5pNW@Y-kljBgyMedA0@Dnf+Cg-#PD(X(WisF`AKL5i3~m)# za2pO0KqmCxAXDXsZ{x-87lP#}D-BE*Xy)w5ksAtY=e@e@l0?_sQyt+SucVNP@RIWK zoH~4Pj!+u6=x6~W$N2g!uxi%j5!VV(Cc=8-WyNr@jZ@_&nV`9{MU_7@pH3E6xt>vh zw~F8dFc~(sXlxY-?%p2i`T+=!YW8+)4~*Qt!zh4Z-RTF26n?_-a%4YzG%?^=%)+Xe zRMyD(t2A#U9dXOW`sJL0`em5~!}N4WJsUgNJG|ifLAGhih)~R%X2p%k3!5?%qB8-N3#@c;2Nb(yAX+S3=Mw)FNry)a)*(MwL8ijgL)d^Sd56X$C#djV zPEc$f^K1G-!%w~56+w%5JoOv?4Mi8HsjB>ilIfg{L|{fNh!-}Kp$;yGZ|xjT!Y`JC z0Ok^Q^IA?BCH7LoYP%>C_D;o-wU8_M$kMunw-Q(w%1Hk0i?rVA>ZaA5-3=RzEdXUb z?oamBiMWTJg2z9$GZ?ggOZX~rx+y4potoK{z?+sF0=cl}dYNuLA3bTy5ro7KxNJmZ z>^HA{#PIQ!^jL(y`H3kuLOJ7rR`E(-Z7 zTfUNOTnjJS=ah(niqaV7?vJB$^#w_uPg&JNZAdp`S)lD`x~(Kh3E^7 z+GrwtCnW$1&=q81r(~DlDcl5xjmdA_!@=UVnE5_awamwaw^uE_0#zowy*k3%L$Ns} zR#Ve`12?x`ry5@ty(r))FQS^yqrwcxo=O8R!+lTOGamJq3-4kf-Q==D?{Mi?@*`Z! z#CJMCZ|3uQLa1@z$MwaVLa0tWgpVVL{@gLcF9A#umLz|V8GamRn4XZ;50zJ4-7E; zW^-hJh4dOo0emV@%4`b$TQZL7@$!`kFzHb+r`+Y?ri9{`g-?JO2Eh`iik~!Wgnv7t zX}gKj$1xCl`uWd4OVNDm+x{yNW*cn^{Tk~>$Vx3Kf}L0DsktyXCUU5Mrt7@TkwBCE z^S`mech!Qt?Mh?lQR)B4N29OzUlea~Oy3z!x`|JM2J-YJ33>YMF}5_gs*+}G)kY~8 zS)V>{1l?g)^15B=deK@$sc?>XUM=(+`rf7ciYQTKt({8IKQF?lH z#iU7Mo{l?fzO$rk!;-=B1AF=|5D|ErDbJ~h23VB!xH7BA#+dCB*h;!;4;<|pTV{MbSHIJwBh>w3WWAOcVjS0 zmdiM+5dCdoa2N0p+z;P7L`v?c6_^=O!DO;PQ|8hfW+x!w@@~Alop4BlPmPk1 zNjVLuZ|s6-^vCkl1~PCP+x4PUyjb@}A_bmVv@nl;NsQTG{4o55U$p_WoOP#tYQ*5l zjyTJ#z?ot0ud~kNR*gYfivhLOGHBM@7L-o-P$i^npq^Oy2c$Qa7+~Rh1S*Z{-&EQy zXPI(hmUIcKVXIhf{(P)gqjN_@HMr9~jO*QAI7*PfEE3fE=jiTAg}LHx#BdBPA>8f; zdR_y#fETRMy$@YA+&>9yYuiZmKo74?QtW{xb34`kH_>(J{dJ9$SeEMAgGuWQO6TSy zt0yAVrgs7p*KrfJ6`8mc-m_k_&-N#ai)1@*!Jg0pwYaT(xT9LD5`kd}0}Kl-flQ0l z1Q`>(V=FUinF#O^PFeS{hC{$#G$5Ms{Z~1i`J8A5qEREWqD{0(_hplxAZok6-MCvo zp<#3?YYMJesI?rJPxFcP=Z+H5#eZI@Z0(WfF@XaBm5&JEG!QknR+NcifXz~uUdZq& zAfOn3R~iwKHE=&L zV`Q?!6Ou$z6@}8?`lyt7i`hw*t*}yDV3)DS@L2};ZAYTY2AFmVMJWtuJDJa;(|-|$ zsmz0TKywgW)f=9fItns`+FMS)wxkX#Lo_;4_%8Cm?GC^=+_;YRCVKU2Kfsj8e-vn^ zln3mp7Qw{cJt#J+abtI_Yw87GDc3?)@+%&7e4Ecxea1&P6&=8B4^e(@c|?faN_P6v z?AdkgX@CAaBuRXUf4Dt}qEIu^bIs7R!Zp)s21q>$Zj*!=w48ug)uV{L+P?(GYcwGq z^_Q`^ZY6%W3fEEX$nsgArDYc_+j1kX#swSqBl2Go@aH?Zq{z7L5?0=)unVriegQY5|* zM;P5P@1AjD3?D={yNqquwwyU062{lLfC%Qa-R9-^0;OLLUfTVAvi)@XL0#Augr7HqXO! zHIPxPN)lyer_f=&x6E%rXW4!!Y=HL6azp&bOIuG-8ZpuX87^*o3LGbVYUNt<+#m9j8#tB0_{|$a%bN~&*?HHH#Mi#lFCA_ARGg2nWa5( zsa|23)z-&u@=W8fw4L34l@cE?vwNVN>v)v4#eA7-_7S?ll8JVe_WZV%VZw4}dGt9l zP1NgGup`u;LsS`{TyPM-UyymipsPz4exGgovHjka{UgE*^}gr36Kh zQ&GZH;}LP?5ouK8*#mjcEoObQKl}UkxA%Yl_y70bzuyMf z>#Mpsu|_(0{Hq8g+@$qcsoZm0?R-3yhh^QKm)|Ocy1Z(SVOEAzoI0WKvb0KiXSBtN z3M5NFB)(#N25Fzu;%c#X8*VrovX2?FF7|CP&UDgpD?`sgq2-+Y2DwjV>|2B; zF-M{=b|lq*PY2S=s?`%Q+!7UXx@w!|v1bE~411Gw+aA>>mlAKMJPs>pux4}SJW`|L zn`EH==?2o0T51=tE~aZ!G)`6{X{9Lo)C65AHMrs_{GBr9jkrz)a^KJ=_cdAeTZD`y zFi-Gc+and=cH0y3E<*0AGRsg9m+AtcGOV-~&wJUyBex3~zIz}-vtoaTn6~Gc1-4Y( z$A-l_NA0wD#Z(&!y%63Ggy*iCDVEkolXPqjjlOOk*V`3AH{RQp}s55d3Sv zw6j!S{A6$5Xcxkh+BLKpq?|f}=@Tv^962EKyqPs#N`@WOK(|J%3BdUQKNaE?j--y8 zbQ%34a2FS1;wBQ=&w3WIbu@Ve0wASKWDh)Y(kD=xy5rjm82O)8VjC*olCXo$#q}|s&}XxaRCCH26fK8;Px;h zlfkE|4Rki2kvEm#Cd87vu|wgaZCpn6hn3A+)O%dEti3w!V|*hwctbipaU$&)%`mE@ zFVuvc;A5422F>K<>pl2pEL1qA*&*3_2oy#H=(SdgRggMWp~$}vy_%k`zS66PR~B0= z&q-{*+nl&I%Reb$@?3?%Jin|A(ZK!ZK%CMoohTydg*HJ_fwJE4b*sRn`jZPY0AhnK zEh)GCY)d>o^?2*#r?&FQ+CjpC#49x(@?G!NS-Z7DfKrG_Z}&V0IQUm^F`Q7-Ng=!%uFRuxUOtfLdj1_ca zF{lq#{QHR3w{)k>oN3C9A7!{79O?2vLhibl5NwBn8ew2;W?@1tGFFOD*9L=6cQh9=FQ1GM!4PW9b1|KWk@i>80`OyLS=asDEO-k4Hk zf!y?&gOUPIo)DF!q(OlSOm9idet~F*o8jLY?HhgTNiq*-2BOe)!mETR!4eznDza#plk}s_BzlPPfjQq?3D~wCI6chED`0S}9F* zw&Ox1J_Vk_(uPY}zES(sB-@n=Ie5Dw7Uqwzo2ZwJgJUFg?ia}H<-CgH7y})+vdtm} z8}wxx=tvjH4@7vW5Z>DLQRV&BHRE*fk{RrL`u-7}zh?qt*N)*K1bwT^J9N=@KmB0P z-}q#tRB00APxe7ooqXC!pP5fg2b%7pL z)-pTf-Bn56^3Se-iylD9FMj2K{b@XWAeiX|*Kz0oeW8?9z{(`yBZl;9xUFBAQ zu$CNhsnQue0h@Ig_A+&`oS$|xUYZrFXFqQpEHeP1S9f~ z$^fCPw~<)g_TUR(eADu(3IRI&eK^7A@JLvi2+7dqoJ1on4FYk2%_K$Rx#cm~^)Mz0 z%7xfJo%DtbJ*II?n@;)kH#hfht`t!?S?T$)do13?G;F-)W{vvja-TA>o}O33^5n86r7Uvzm+oB>TZ4?13%V3+F9P(=oaxCe+Z;y literal 0 HcmV?d00001 diff --git a/docs/UML/Architecture/WeeklyPlanRelated.drawio b/docs/UML/Architecture/WeeklyPlanRelated.drawio new file mode 100644 index 0000000000..0e00a62c2b --- /dev/null +++ b/docs/UML/Architecture/WeeklyPlanRelated.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/Architecture/WeeklyPlanRelated.png b/docs/UML/Architecture/WeeklyPlanRelated.png new file mode 100644 index 0000000000000000000000000000000000000000..bfaaab437449540fc1354065ab7fb96c8dc1e945 GIT binary patch literal 38196 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 literal 0 HcmV?d00001 diff --git a/docs/UML/Implementation/AddIngredientFunction/.$AddIngredientFunction.drawio.bkp b/docs/UML/Implementation/AddIngredientFunction/.$AddIngredientFunction.drawio.bkp new file mode 100644 index 0000000000..7630fafd14 --- /dev/null +++ b/docs/UML/Implementation/AddIngredientFunction/.$AddIngredientFunction.drawio.bkp @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.drawio b/docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.drawio new file mode 100644 index 0000000000..214cb7526d --- /dev/null +++ b/docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.drawio @@ -0,0 +1 @@ +5Vhbb9owGP01SN0DVRInQB8htCtbV1VDU9unymCTWDVx6jgF9utnE+diwiUtDE3aC7KPnc/2+Y6PbVrAny+/chiHPxjCtOVYaNkCw5bj9DpA/ipglQGe7WRAwAnKIKsExuQ3zkA7R1OCcKKxDBKMUUFiE5yyKMJTYWCQc7Ywu80YRQYQwwDXgPEU0jr6SJAI9bI8q8RvMQnCfGTb0i1zmHfWQBJCxBYVCFy3gM8ZE1lpvvQxVdyZvNzsaC0mxnEkmnxwf/s2C8eRdz+1F8OX3gjCx/u2jvIOaaoXrCcrVjkDnKURwiqI1QKDRUgEHsdwqloXMuUSC8Wcypoti4ng7BX7jDIukYhFsttAj4G5wMudk7cLSqSUMJtjwVeyi/4AXGVfaBW5vay6KFPiuXrqYSUdDtAdoZZBUEQumZIFTdZ24uDo+xv2w2+Dn4OXJ+x3bibpXdvuHmauwotaPJGq6lMSRBKbMCHYXDbgCPWVTCXGYiybBggm4ZpuO2vWe6KnaksinnQiVPlZlS+vPFk1s7SDXsfCyJD7Tr6tS8vKSeaYQkHezQ2xjVAd7YEROWqZOgAuLZkI68pb/3Y9I5WO5ZgRBeQBFjpIVc8bcT3L3R8oYSmf4j2B8o5sNkuwqEmiYOUIlXRqKoEIjaKAY0Rkbi7K4pdj5TOhbPq6huScC5WoyrOuNNRIxtueVWlLzxK1b/VeQ9EdqTAXWIYS7B5opIRTZRnUrQD0HyBPMK8lVZ4CsSqmc3pHZpiStUPGmBM5C6xMk2r4ocQOua48/ASUn/CiTimMEzJZj7pOPZ6mPJEU/8RJ5icKZalQI/nF2blXFzUD3+keTrdnJKTj1ey6OCcNu7bA7twfZdfuh9w6VkpZT8EbtLzhRoIYFyELWARpNUV12vZqpTGXrmmX+X3KoLLOpJ3vvZMz6dWYjJXS+wj9knov/Sy5GAtOokBT6PgqcNF6R5J/wfGOsjf3PO7WlhrYKoEzuVv9CDvfRact7yEeqNx2bHkvAbXEqtbhslpZVSqVXfoJGRw8DZvKIE+nulr1OkZG292T3LTajmm7dnfj9nvwanWGG9GWFwfojwxj+D8PTdfb2OaND033L1m9Xff6U5+aM0Jp/lpEeAZTKprvUPsTHJsbxK6/I7edpvkT/gMMy2r5tM82T/n/CLj+Aw== \ No newline at end of file diff --git a/docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.png b/docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.png new file mode 100644 index 0000000000000000000000000000000000000000..0a4785e065c79ed271f0089c6854dbd6df952668 GIT binary patch literal 12223 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 literal 0 HcmV?d00001 diff --git a/docs/UML/Implementation/EditWeeklyPlan/.$EditWeeklyPlan.drawio.bkp b/docs/UML/Implementation/EditWeeklyPlan/.$EditWeeklyPlan.drawio.bkp new file mode 100644 index 0000000000..7630fafd14 --- /dev/null +++ b/docs/UML/Implementation/EditWeeklyPlan/.$EditWeeklyPlan.drawio.bkp @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/UML/Implementation/EditWeeklyPlan/.$EditWeeklyPlan.png.bkp b/docs/UML/Implementation/EditWeeklyPlan/.$EditWeeklyPlan.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..96083cc5797316a1993046e118740741903ba54a GIT binary patch literal 60921 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

Zq98wwfL0PfHr%D5mw&wePlhTHbc=z! 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 \ No newline at end of file diff --git a/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png b/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f01a6ff2e062afa98779e0c4b97247295353b7 GIT binary patch literal 64996 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/UML/Implementation/MarkDoneWeeklyPlan/.$MarkDoneWeeklyPlan.drawio.bkp b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$MarkDoneWeeklyPlan.drawio.bkp new file mode 100644 index 0000000000..89bd599e96 --- /dev/null +++ b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$MarkDoneWeeklyPlan.drawio.bkp @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewIngredientFunction.drawio.bkp b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewIngredientFunction.drawio.bkp new file mode 100644 index 0000000000..9cb80d2792 --- /dev/null +++ b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewIngredientFunction.drawio.bkp @@ -0,0 +1 @@ +5VhRb9owEP41SN0DlRMnkD5C2m7dOqkamtY+TQYfiVUTZ45T6H79nMROSAMUBqs27QXZn3Pny3ef7xx6OFys3kuSxp8FBd5zEV318GXPdQcB1r8F8FwBHnIrIJKMVhBqgAn7CRXoWDRnFDKDVZASgiuWtsGZSBKYqRZGpBTL9mNzwWkLSEkEHWAyI7yLfmNUxRUa+KjBPwCLYruzg8zKgtiHDZDFhIrlGoSvejiUQqhqtFiFwAvu2rxcb1mtA5OQqH0MyM2nHxDGH8dfxt/vIRxcT/Pbvg3uifDcvLGJVj1bCmK14Hrk9PB4zjgPBRdSzynMSc711uNMSfEIFk9Eog3Hxi9IBautETs1D1o/IBag5LN+xBpcVBZWOia0ZZMH3zfyitdy4Hqeyb/JfVR7bujRA8PQAWw5w4PYKl6eaSmNOIsSjU2FUmKhFyCho0KbGhMp6KUxJVkM1NjpZXMQgmK2Yupej5EZPxTj8wtfT6XIE1qaoZpxoB1B78s3OkfICyorCZwo9tR2tYlQ4+1OML1J7QpjfI5cHKALv/wd+q1UurYKWI+KyAiUcbIu4hd+feTtdpSJXM5ghyP7oJjPM1AdSdSsHKGSQUclhNKbJJJAmU7FWTN8d6x8plzMHktIx1yrpJg8mMleGqno3/VO/hYx6eBLxnfY4s2iO1JhHkYtJTi207yihFNlGXdLAR7dEZmB7CRVl/60GOYLfsvmwFlZIVOQTEcBRdHkBr5rsPEyZgomKSnJXeruqrE1eeiOp4g2kfWcc5JmbFruWqYeZrnMNMVfIKvqSYGKXBU7hXXDRKep1u4waCVk4HfKdd0cW+Ua4e25P6pcewdV67RQShmCP+75ly8SJKSKRSQSwtdTtBdthxwKK+52uRzgDVR2mXTsKT05k36HybRQ+ojSr1rvTT3LziZKsiQyFLph4bhevWXZv1PxvOMSeWR162sNbJTAG1W3bgv7+y86rzaiI1NqU1Nck4JBKzv94UluTX0Xt3va8NBr0hvcbpxNje+mdcj/zwbo+S+O7N4N8I99r3Tr9qk74OYvwt/vi85rHLcPiBPs1RntZ+4BDOtp821eHZ7mDw589Qs= \ No newline at end of file diff --git a/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp new file mode 100644 index 0000000000..9ab21a8d83 --- /dev/null +++ b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp @@ -0,0 +1 @@ +5Vnbbts4EP0aA9kHB7pa8qMvSTfbBNs26G77VDDW2CJKiSpFxfZ+/Y4s6krZsWsnKNAXQzykKOnMmZkjeWDPos07QZLwgQfABpYRbAb2fGBZY3+MvzmwLQDXtwpgJWhQQEYNPNL/oADNEs1oAKnCCkhyziRN2uCCxzEsZAsjQvB1e9mSs6AFJGQFGvC4IExH/6WBDAvUd40a/xPoKiyvbBpqJiLlYgWkIQn4ugHZNwN7JjiXxVG0mQHLuWvzcrtntroxAbE85gS2/jvcbhbW8z9y8s66+/jxPfWGo2KXZ8Iy9cDqZuW2ZCCUEcMjc2BPUyn4d5hxxgUiMY9xyVTtAELCZu+tmdUDo1CARyDFFpeUJ6jbUBqx/WK4rgn3SlrDBtm2XwZaBXlV7VzzgAeKin5ayN37HzAL/5p+mn77ArPR7VN2PzS9k3jJH56iZiaMrmLEnriUPMIJiINJLkLEeAI4NQ1IGkKgzsNppXgfR4JncbCbM3Zz+CBf8oXXhluOv+aT1964Auab5vL5tjn6AIIiHSAUuCcq+FA8Ews4RIdaCEEnWSQRK5AHznQOxt24NgxHBVsAI5I+t/fvC6za7QOn+BjVVpbpXBuoCGPs7n49tyUpc9zZsbhztUkzazr72v4LGxXkHdioXMiXyxRaa1AaZNtYkeRnpPuf0fb8dp4oVdZKL3asdV9RfkYq6CUiEXhbn1MQd/FKQEBRT+lV1h7/cW6+PDG++N7MA6OVBFq+/Ly67SO1bLq9WaCr+0wp22W6lZLzrKMkd6mI23rtsycPQJg9MrSoYldL8sMsYvd0CYzuekLSKD1MwY1yNF2HVMJjQnZxWaNxQKyhD2zmkuApohozRpKUPu2uuos9LDKRIsefIC0qaI7yTOZXmlVe4KAwtJa1vz+541ZEXEdrUGZvgyo72cUblHNSf1KFBWF3OnDnnQBxIUO+4jFhzRDptB0Uy9FcOu16OrJ7qNSZRN/4Sky6GpOoLUBl3cVJJq8G1uhHllu06TOF9TdaV7h65heodWcVNudt6trQtEe9sX+junaa172Mp4MNlXlAh2h1PE8BXwtXZ5i66cPZ2tLlg21j8LKhOySDF/vgsTIow5m7N78d0aF3ETM39LtG51T3tt90XcwXmbqc7Mln+nt2SMex2x2yr6z3dUjHeaW6buqF/dItckkZK1+GA1iSjMnjs9I8nePOm4ipvyb3tU7TvcBbcu/HAz0DGOfJoQS4FSSCl9W9h5lTPilUwlJsWYalsWWXzDTp6r7fXYytHlvtTpcoHiy5ZBHmp1fmIldgl0bkQrZp6v0c0xSlgohqYQvceSfcbm+LaBCwfXHpsx5nhcYpVVqFxtNCM+qrFcYrReatzPR5rI07gnb6XkJ01pzXYk2vryjmiMgHSFOygitsNWig1Ui3yLnNeFTDmrSbGm0qvVQwg2WeAykqFJPlfjeaW/1met/ntK617nU9bdd8SDVHRPBMN+SM22+fiLS32OObT/285Fr91/nJz0s4rD9uF8vrfwjsm/8B \ No newline at end of file diff --git a/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp new file mode 100644 index 0000000000..6a8ba1ada7 --- /dev/null +++ b/docs/UML/Implementation/MarkDoneWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp @@ -0,0 +1 @@ +5VnZcqM4FP0aV2UenAIExn70knRnktQknZruzrxMySAbVWREhIjt/vq5GLGZxbhtV3fVvCToaAGde+4iuYemq80ngQPvkbuE9QzN3fTQrGcYuolM+Bcj2wQZmgpYCuomkJYDL/QHUTNTNKIuCRWWQJJzJmlQBh3u+8SRJQwLwdflYQvO3BIQ4CWpAC8OZlX0G3Wlp3ZhaTn+mdCll75Z11TPCqeDFRB62OXrAoRuemgqOJfJ02ozJSwmr8zLbUNv9mGC+LLLhMnyn1cLvd9b8/Hn5ze0oOHXeV+t8oFZpDasPlZuUwYEj3yXxItoPTRZe1SSlwA7ce8abA6YJ1cMWjo8quWIkGTT+J16tnuQDeErIsUWhqgJKV9KMAglzXXO/mA0SDCvwDwaqXlYWXyZrZyTAg+Kl3qO8N39O5l6f06+TP79TqaD23n00NftwyQVKIg3T0FAY0aXPmBzLiVfQQfx3XGsSMB4QKBr4uLQ2zGrJ91K/kNolVkH6sT2ezzwWrPS9mvceW2PMmC2KQ6fbYutJyIo0EGEAhusApvikXBIGx2pG2KxJLJloHJ04pY8rNHu2rWmmcNkjiAMS/pR9sE6w6rVnjiFbeQS0s1rzUBDbWTt/tpWSVL6aG/FZCtqkaIL7a2LhgcWSshrWSgdyBeLkJTGgDTwtjAiiGeEzXtE9rDsJ0qVudKTFXPdZ5Sf4AqDiisEAj7rGyFvbPvEsH+1zh7/ONVL5ow7b0X1ayXpV7zk5zWNOkpatzpq+kQBo9TJUqHZRiehncvOqBrx0PiRYIYGWsWqkNiC+DFasQe6IIz60JoEhYDDFFwIQocSCeRziWGKyNqM4SCk891bd7YnTiRC4PgLCZO4GaM8kvGbplk50CqMSqJqjE66NSpZxDIraSlL/aW0hIYXSkvmUVlJhROArUnPmu0ZiAvp8SX3MSuaqEpbq1g6c2mWo+igmuH1GiYN61JMWhUmQVsElHXnB5G86hmD9yiu0iZJbAsgtuXYbxDl2qxyTPa1rLNk376OBrUG7pwl23XSOWs3J9tzxclqOjxVDYcrQ7KhMpZJH0xm2wp4TWpDTa+WjtCbF4ZxY1toHC4L28R1MK8eWQLGW9KGZfH07fOIcrhfLh1bA15eTXrNaQyN/6b/z4xrmqiccevSRF3GTW8Yzn8QrCaKc6fcBWVsyhmPR7hkgSMmu3ulfjzHe+cZfdgpFetWi/91pZit//K2G8f4+CrHn4y75+d7atfcRzDOgzYHuBV4RbpeTJwkyExYii1DMypsoZSZIl37p8SzsVVTpluTBYgHQi52vF3UdCgwZc0qFMKmZZmiUAr+RlL1+XwXVIqCVBBW6csBKnei3c9rK+q6rMkmHY9sR2hY1/bMYlfMMqiLE2e4L6q1yq8ozI9nbbQnZrPuQFNlzbwUa9XYurtZeCRhiJfkCrIM1OKqVa254wrjRTVzzm5ytCj0VMCMLGIXCEGg1F8+7Fozo746b7qP26/VG01TvFtok82lrxbMUfkgC0h5iYbq/Nj7Kcuof89P3k9BM78qT4bnPzigm/8A \ No newline at end of file diff --git a/docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.drawio b/docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.drawio new file mode 100644 index 0000000000..1948d0d6eb --- /dev/null +++ b/docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png b/docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png new file mode 100644 index 0000000000000000000000000000000000000000..c81e221dc88cc4e32926524183ea2d4f72e84ed4 GIT binary patch literal 47574 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/UML/Implementation/ViewIngredientFunction/.$ViewIngredientFunction.drawio.bkp b/docs/UML/Implementation/ViewIngredientFunction/.$ViewIngredientFunction.drawio.bkp new file mode 100644 index 0000000000..9cb80d2792 --- /dev/null +++ b/docs/UML/Implementation/ViewIngredientFunction/.$ViewIngredientFunction.drawio.bkp @@ -0,0 +1 @@ +5VhRb9owEP41SN0DlRMnkD5C2m7dOqkamtY+TQYfiVUTZ45T6H79nMROSAMUBqs27QXZn3Pny3ef7xx6OFys3kuSxp8FBd5zEV318GXPdQcB1r8F8FwBHnIrIJKMVhBqgAn7CRXoWDRnFDKDVZASgiuWtsGZSBKYqRZGpBTL9mNzwWkLSEkEHWAyI7yLfmNUxRUa+KjBPwCLYruzg8zKgtiHDZDFhIrlGoSvejiUQqhqtFiFwAvu2rxcb1mtA5OQqH0MyM2nHxDGH8dfxt/vIRxcT/Pbvg3uifDcvLGJVj1bCmK14Hrk9PB4zjgPBRdSzynMSc711uNMSfEIFk9Eog3Hxi9IBautETs1D1o/IBag5LN+xBpcVBZWOia0ZZMH3zfyitdy4Hqeyb/JfVR7bujRA8PQAWw5w4PYKl6eaSmNOIsSjU2FUmKhFyCho0KbGhMp6KUxJVkM1NjpZXMQgmK2Yupej5EZPxTj8wtfT6XIE1qaoZpxoB1B78s3OkfICyorCZwo9tR2tYlQ4+1OML1J7QpjfI5cHKALv/wd+q1UurYKWI+KyAiUcbIu4hd+feTtdpSJXM5ghyP7oJjPM1AdSdSsHKGSQUclhNKbJJJAmU7FWTN8d6x8plzMHktIx1yrpJg8mMleGqno3/VO/hYx6eBLxnfY4s2iO1JhHkYtJTi207yihFNlGXdLAR7dEZmB7CRVl/60GOYLfsvmwFlZIVOQTEcBRdHkBr5rsPEyZgomKSnJXeruqrE1eeiOp4g2kfWcc5JmbFruWqYeZrnMNMVfIKvqSYGKXBU7hXXDRKep1u4waCVk4HfKdd0cW+Ua4e25P6pcewdV67RQShmCP+75ly8SJKSKRSQSwtdTtBdthxwKK+52uRzgDVR2mXTsKT05k36HybRQ+ojSr1rvTT3LziZKsiQyFLph4bhevWXZv1PxvOMSeWR162sNbJTAG1W3bgv7+y86rzaiI1NqU1Nck4JBKzv94UluTX0Xt3va8NBr0hvcbpxNje+mdcj/zwbo+S+O7N4N8I99r3Tr9qk74OYvwt/vi85rHLcPiBPs1RntZ+4BDOtp821eHZ7mDw589Qs= \ No newline at end of file diff --git a/docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.drawio b/docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.drawio new file mode 100644 index 0000000000..9ab21a8d83 --- /dev/null +++ b/docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.drawio @@ -0,0 +1 @@ +5Vnbbts4EP0aA9kHB7pa8qMvSTfbBNs26G77VDDW2CJKiSpFxfZ+/Y4s6krZsWsnKNAXQzykKOnMmZkjeWDPos07QZLwgQfABpYRbAb2fGBZY3+MvzmwLQDXtwpgJWhQQEYNPNL/oADNEs1oAKnCCkhyziRN2uCCxzEsZAsjQvB1e9mSs6AFJGQFGvC4IExH/6WBDAvUd40a/xPoKiyvbBpqJiLlYgWkIQn4ugHZNwN7JjiXxVG0mQHLuWvzcrtntroxAbE85gS2/jvcbhbW8z9y8s66+/jxPfWGo2KXZ8Iy9cDqZuW2ZCCUEcMjc2BPUyn4d5hxxgUiMY9xyVTtAELCZu+tmdUDo1CARyDFFpeUJ6jbUBqx/WK4rgn3SlrDBtm2XwZaBXlV7VzzgAeKin5ayN37HzAL/5p+mn77ArPR7VN2PzS9k3jJH56iZiaMrmLEnriUPMIJiINJLkLEeAI4NQ1IGkKgzsNppXgfR4JncbCbM3Zz+CBf8oXXhluOv+aT1964Auab5vL5tjn6AIIiHSAUuCcq+FA8Ews4RIdaCEEnWSQRK5AHznQOxt24NgxHBVsAI5I+t/fvC6za7QOn+BjVVpbpXBuoCGPs7n49tyUpc9zZsbhztUkzazr72v4LGxXkHdioXMiXyxRaa1AaZNtYkeRnpPuf0fb8dp4oVdZKL3asdV9RfkYq6CUiEXhbn1MQd/FKQEBRT+lV1h7/cW6+PDG++N7MA6OVBFq+/Ly67SO1bLq9WaCr+0wp22W6lZLzrKMkd6mI23rtsycPQJg9MrSoYldL8sMsYvd0CYzuekLSKD1MwY1yNF2HVMJjQnZxWaNxQKyhD2zmkuApohozRpKUPu2uuos9LDKRIsefIC0qaI7yTOZXmlVe4KAwtJa1vz+541ZEXEdrUGZvgyo72cUblHNSf1KFBWF3OnDnnQBxIUO+4jFhzRDptB0Uy9FcOu16OrJ7qNSZRN/4Sky6GpOoLUBl3cVJJq8G1uhHllu06TOF9TdaV7h65heodWcVNudt6trQtEe9sX+junaa172Mp4MNlXlAh2h1PE8BXwtXZ5i66cPZ2tLlg21j8LKhOySDF/vgsTIow5m7N78d0aF3ETM39LtG51T3tt90XcwXmbqc7Mln+nt2SMex2x2yr6z3dUjHeaW6buqF/dItckkZK1+GA1iSjMnjs9I8nePOm4ipvyb3tU7TvcBbcu/HAz0DGOfJoQS4FSSCl9W9h5lTPilUwlJsWYalsWWXzDTp6r7fXYytHlvtTpcoHiy5ZBHmp1fmIldgl0bkQrZp6v0c0xSlgohqYQvceSfcbm+LaBCwfXHpsx5nhcYpVVqFxtNCM+qrFcYrReatzPR5rI07gnb6XkJ01pzXYk2vryjmiMgHSFOygitsNWig1Ui3yLnNeFTDmrSbGm0qvVQwg2WeAykqFJPlfjeaW/1met/ntK617nU9bdd8SDVHRPBMN+SM22+fiLS32OObT/285Fr91/nJz0s4rD9uF8vrfwjsm/8B \ No newline at end of file diff --git a/docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.png b/docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.png new file mode 100644 index 0000000000000000000000000000000000000000..874373a72aee5cdaa60129e4a743a5ec0d525939 GIT binary patch literal 21910 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/UML/Implementation/ViewWeeklyPlan/.$ViewIngredientFunction.drawio.bkp b/docs/UML/Implementation/ViewWeeklyPlan/.$ViewIngredientFunction.drawio.bkp new file mode 100644 index 0000000000..9cb80d2792 --- /dev/null +++ b/docs/UML/Implementation/ViewWeeklyPlan/.$ViewIngredientFunction.drawio.bkp @@ -0,0 +1 @@ +5VhRb9owEP41SN0DlRMnkD5C2m7dOqkamtY+TQYfiVUTZ45T6H79nMROSAMUBqs27QXZn3Pny3ef7xx6OFys3kuSxp8FBd5zEV318GXPdQcB1r8F8FwBHnIrIJKMVhBqgAn7CRXoWDRnFDKDVZASgiuWtsGZSBKYqRZGpBTL9mNzwWkLSEkEHWAyI7yLfmNUxRUa+KjBPwCLYruzg8zKgtiHDZDFhIrlGoSvejiUQqhqtFiFwAvu2rxcb1mtA5OQqH0MyM2nHxDGH8dfxt/vIRxcT/Pbvg3uifDcvLGJVj1bCmK14Hrk9PB4zjgPBRdSzynMSc711uNMSfEIFk9Eog3Hxi9IBautETs1D1o/IBag5LN+xBpcVBZWOia0ZZMH3zfyitdy4Hqeyb/JfVR7bujRA8PQAWw5w4PYKl6eaSmNOIsSjU2FUmKhFyCho0KbGhMp6KUxJVkM1NjpZXMQgmK2Yupej5EZPxTj8wtfT6XIE1qaoZpxoB1B78s3OkfICyorCZwo9tR2tYlQ4+1OML1J7QpjfI5cHKALv/wd+q1UurYKWI+KyAiUcbIu4hd+feTtdpSJXM5ghyP7oJjPM1AdSdSsHKGSQUclhNKbJJJAmU7FWTN8d6x8plzMHktIx1yrpJg8mMleGqno3/VO/hYx6eBLxnfY4s2iO1JhHkYtJTi207yihFNlGXdLAR7dEZmB7CRVl/60GOYLfsvmwFlZIVOQTEcBRdHkBr5rsPEyZgomKSnJXeruqrE1eeiOp4g2kfWcc5JmbFruWqYeZrnMNMVfIKvqSYGKXBU7hXXDRKep1u4waCVk4HfKdd0cW+Ua4e25P6pcewdV67RQShmCP+75ly8SJKSKRSQSwtdTtBdthxwKK+52uRzgDVR2mXTsKT05k36HybRQ+ojSr1rvTT3LziZKsiQyFLph4bhevWXZv1PxvOMSeWR162sNbJTAG1W3bgv7+y86rzaiI1NqU1Nck4JBKzv94UluTX0Xt3va8NBr0hvcbpxNje+mdcj/zwbo+S+O7N4N8I99r3Tr9qk74OYvwt/vi85rHLcPiBPs1RntZ+4BDOtp821eHZ7mDw589Qs= \ No newline at end of file diff --git a/docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp b/docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp new file mode 100644 index 0000000000..9ab21a8d83 --- /dev/null +++ b/docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.bkp @@ -0,0 +1 @@ +5Vnbbts4EP0aA9kHB7pa8qMvSTfbBNs26G77VDDW2CJKiSpFxfZ+/Y4s6krZsWsnKNAXQzykKOnMmZkjeWDPos07QZLwgQfABpYRbAb2fGBZY3+MvzmwLQDXtwpgJWhQQEYNPNL/oADNEs1oAKnCCkhyziRN2uCCxzEsZAsjQvB1e9mSs6AFJGQFGvC4IExH/6WBDAvUd40a/xPoKiyvbBpqJiLlYgWkIQn4ugHZNwN7JjiXxVG0mQHLuWvzcrtntroxAbE85gS2/jvcbhbW8z9y8s66+/jxPfWGo2KXZ8Iy9cDqZuW2ZCCUEcMjc2BPUyn4d5hxxgUiMY9xyVTtAELCZu+tmdUDo1CARyDFFpeUJ6jbUBqx/WK4rgn3SlrDBtm2XwZaBXlV7VzzgAeKin5ayN37HzAL/5p+mn77ArPR7VN2PzS9k3jJH56iZiaMrmLEnriUPMIJiINJLkLEeAI4NQ1IGkKgzsNppXgfR4JncbCbM3Zz+CBf8oXXhluOv+aT1964Auab5vL5tjn6AIIiHSAUuCcq+FA8Ews4RIdaCEEnWSQRK5AHznQOxt24NgxHBVsAI5I+t/fvC6za7QOn+BjVVpbpXBuoCGPs7n49tyUpc9zZsbhztUkzazr72v4LGxXkHdioXMiXyxRaa1AaZNtYkeRnpPuf0fb8dp4oVdZKL3asdV9RfkYq6CUiEXhbn1MQd/FKQEBRT+lV1h7/cW6+PDG++N7MA6OVBFq+/Ly67SO1bLq9WaCr+0wp22W6lZLzrKMkd6mI23rtsycPQJg9MrSoYldL8sMsYvd0CYzuekLSKD1MwY1yNF2HVMJjQnZxWaNxQKyhD2zmkuApohozRpKUPu2uuos9LDKRIsefIC0qaI7yTOZXmlVe4KAwtJa1vz+541ZEXEdrUGZvgyo72cUblHNSf1KFBWF3OnDnnQBxIUO+4jFhzRDptB0Uy9FcOu16OrJ7qNSZRN/4Sky6GpOoLUBl3cVJJq8G1uhHllu06TOF9TdaV7h65heodWcVNudt6trQtEe9sX+junaa172Mp4MNlXlAh2h1PE8BXwtXZ5i66cPZ2tLlg21j8LKhOySDF/vgsTIow5m7N78d0aF3ETM39LtG51T3tt90XcwXmbqc7Mln+nt2SMex2x2yr6z3dUjHeaW6buqF/dItckkZK1+GA1iSjMnjs9I8nePOm4ipvyb3tU7TvcBbcu/HAz0DGOfJoQS4FSSCl9W9h5lTPilUwlJsWYalsWWXzDTp6r7fXYytHlvtTpcoHiy5ZBHmp1fmIldgl0bkQrZp6v0c0xSlgohqYQvceSfcbm+LaBCwfXHpsx5nhcYpVVqFxtNCM+qrFcYrReatzPR5rI07gnb6XkJ01pzXYk2vryjmiMgHSFOygitsNWig1Ui3yLnNeFTDmrSbGm0qvVQwg2WeAykqFJPlfjeaW/1met/ntK617nU9bdd8SDVHRPBMN+SM22+fiLS32OObT/285Fr91/nJz0s4rD9uF8vrfwjsm/8B \ No newline at end of file diff --git a/docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp b/docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp new file mode 100644 index 0000000000..6a8ba1ada7 --- /dev/null +++ b/docs/UML/Implementation/ViewWeeklyPlan/.$ViewWeeklyPlan.drawio.dtmp @@ -0,0 +1 @@ +5VnZcqM4FP0aV2UenAIExn70knRnktQknZruzrxMySAbVWREhIjt/vq5GLGZxbhtV3fVvCToaAGde+4iuYemq80ngQPvkbuE9QzN3fTQrGcYuolM+Bcj2wQZmgpYCuomkJYDL/QHUTNTNKIuCRWWQJJzJmlQBh3u+8SRJQwLwdflYQvO3BIQ4CWpAC8OZlX0G3Wlp3ZhaTn+mdCll75Z11TPCqeDFRB62OXrAoRuemgqOJfJ02ozJSwmr8zLbUNv9mGC+LLLhMnyn1cLvd9b8/Hn5ze0oOHXeV+t8oFZpDasPlZuUwYEj3yXxItoPTRZe1SSlwA7ce8abA6YJ1cMWjo8quWIkGTT+J16tnuQDeErIsUWhqgJKV9KMAglzXXO/mA0SDCvwDwaqXlYWXyZrZyTAg+Kl3qO8N39O5l6f06+TP79TqaD23n00NftwyQVKIg3T0FAY0aXPmBzLiVfQQfx3XGsSMB4QKBr4uLQ2zGrJ91K/kNolVkH6sT2ezzwWrPS9mvceW2PMmC2KQ6fbYutJyIo0EGEAhusApvikXBIGx2pG2KxJLJloHJ04pY8rNHu2rWmmcNkjiAMS/pR9sE6w6rVnjiFbeQS0s1rzUBDbWTt/tpWSVL6aG/FZCtqkaIL7a2LhgcWSshrWSgdyBeLkJTGgDTwtjAiiGeEzXtE9rDsJ0qVudKTFXPdZ5Sf4AqDiisEAj7rGyFvbPvEsH+1zh7/ONVL5ow7b0X1ayXpV7zk5zWNOkpatzpq+kQBo9TJUqHZRiehncvOqBrx0PiRYIYGWsWqkNiC+DFasQe6IIz60JoEhYDDFFwIQocSCeRziWGKyNqM4SCk891bd7YnTiRC4PgLCZO4GaM8kvGbplk50CqMSqJqjE66NSpZxDIraSlL/aW0hIYXSkvmUVlJhROArUnPmu0ZiAvp8SX3MSuaqEpbq1g6c2mWo+igmuH1GiYN61JMWhUmQVsElHXnB5G86hmD9yiu0iZJbAsgtuXYbxDl2qxyTPa1rLNk376OBrUG7pwl23XSOWs3J9tzxclqOjxVDYcrQ7KhMpZJH0xm2wp4TWpDTa+WjtCbF4ZxY1toHC4L28R1MK8eWQLGW9KGZfH07fOIcrhfLh1bA15eTXrNaQyN/6b/z4xrmqiccevSRF3GTW8Yzn8QrCaKc6fcBWVsyhmPR7hkgSMmu3ulfjzHe+cZfdgpFetWi/91pZit//K2G8f4+CrHn4y75+d7atfcRzDOgzYHuBV4RbpeTJwkyExYii1DMypsoZSZIl37p8SzsVVTpluTBYgHQi52vF3UdCgwZc0qFMKmZZmiUAr+RlL1+XwXVIqCVBBW6csBKnei3c9rK+q6rMkmHY9sR2hY1/bMYlfMMqiLE2e4L6q1yq8ozI9nbbQnZrPuQFNlzbwUa9XYurtZeCRhiJfkCrIM1OKqVa254wrjRTVzzm5ytCj0VMCMLGIXCEGg1F8+7Fozo746b7qP26/VG01TvFtok82lrxbMUfkgC0h5iYbq/Nj7Kcuof89P3k9BM78qT4bnPzigm/8A \ No newline at end of file diff --git a/docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.drawio b/docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.drawio new file mode 100644 index 0000000000..194dbdd2cb --- /dev/null +++ b/docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.drawio @@ -0,0 +1 @@ +5Vldc6M2FP01nkkfkgEEBj/6I8mmSabJZrq76UtHBhk0kRERIrb31/dihPk0xht72pm+JOhICDj3XJ0reYCmy/WtwFHwyD3CBobmrQdoNjAMXUND+JcimwwZ6mYG+IJ6GaQVwAv9SfI7FZpQj8QKyyDJOZM0qoIuD0PiygqGheCr6rAFZ14FiLBPGsCLi1kT/U49GWSoY2kF/oVQP8ifrGuqZ4nzwQqIA+zxVQlC1wM0FZzL7Gq5nhKWklfl5WZP7+7FBAllnxsm/l+vFnq/t+bjL89vaEHjb/NLNcsHZon6YPWycpMzIHgSeiSdRBugySqgkrxE2E17VxBzwAK5ZNDS4TKWgr+RKWdcABLyEIZNmm+aP5YISdYlSL35LeFLIsUGhqjenESlIoSy5qoIyXCklBaUwoFG6j6sZODvZi6YggtFVjtx+O7+nUyD3ydfJ3//INPhzTx5uNTtw8yVeEm/lIKqxoz6IWBzLiVfQgcJvXEqU8B4RKBr4uE42NKtZ90qJxxoVUMBbIrNj3TglWbl7de088oe7YDZujx8tim3noigQAcRCtwbqJgnwiVddOS5iYVPZMdAlf3Eq6Td3rhrV5pmOtk9gjAs6Uc1MdsCq2Z74hQ+o5CQbl5pBnK0kbX9a1sVSemj2ozZp6hJynlVmxc5BybKyOuYKB/IF4uYVMaANPCmNCJK74j3fyOynWqeKFUWSs9mLHS/o/wTqTBspEIk4LW+E/LGNk8Mhxer3eVvn82SOePuW1n9WkX6jSz5dU2jnpLWrZ6a/qSAUZ5kudBso5fQThVn1Fzx0PiRYIaGWiOq4HZRepks2QNdEEa3ThCVFhym4NIidMhdwOQlhlvErs0YjmI63z51G3viJiIGjr+SOFs3U5QnMn3SdFcjdAqjvyvp1qgSEcts2NKuHqjYEnLOZEvmUa6klhOArcnAmtUCxIUMuM9DzMohatLWKZbeXJrVVXTYdHi9hUnDOheTVoNJ0BYBZd2FUSIvBsbwPUlLt0m2tkWwthXYf2CV64rKMe5rWSdx30s93wnUAtzbJbt10tu195vtqdbJph1+Vg2HK0OypjKVySWEzLYV8JrVhpreLB2htygM08am1DhcFnaJ66CvHlkCpp+kOVXxXNqnEaVTL5eOrQHPrya9ZYuGxn/S/6fjmiaqOm6bTbQ5rmmeySf0plGc2nIXlLF8S+2RBU6Y7J+V+vEc1/YzutPLinWrI//6UsxWfwSbtWt8fJPjW+Pu+fme2i2HFIzzqCsBbgReksPqPoEgd8JSbBma0WAL5cyU6arvEk/GVkuZbk0WIB5YcrEbbFdNlwJT1qxBIXy07HGgUxakgrCyLxeo3Iq27mtL6nlsX0x6btmO0LCu1cJiN8IybFsnTnBe1BqVf6MwP561UU3MZtuGpsmaeS7Wmmvr9mThkcQx9skFuAzU4qrVrLnTCuNFNQvOrgu0LPRcwIws0hSIQaA09B+2rZnRXp3vO4+r1+p7Q1M+W+iSzbmPFsxRdSMLSHWKPdX5sedTltH+nF88n4JmcX6eDS9+hUDX/wA= \ No newline at end of file diff --git a/docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.png b/docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.png new file mode 100644 index 0000000000000000000000000000000000000000..aef52b9aa62ce0e423631f399fcda1a86efa2784 GIT binary patch literal 21838 zcmeIacUY6#w=N2prD0h}KtV*hfQmrqO*)}hDS^By z-!wEd$F;T8uh7uY)zHw;-h>_oPilmICxU-yeXeM#(iC)@ouQ$Dn)@Oxd_4l3UEMJ> zeBx@o7f`+$!Irr?h#0z4L11)snRDGBPw z04a$J;E9TtmpcZ9anN=3uQ+y-HfzR%)I1Knl6XS@(ldCv+ z+xrW<;z4mSgs_Y-7?l`84eO2f0HriU5mLekVM#FwSz%FGS@7onn45-}sIa)OBzR_G z?`-ew`fvIpPaETF??RojrJ01kriD9FPx1;{$jnm4LRvMDI#nXZ+s75ii6XUs^-iws z8|a0hK6b(oT^+$tfSiy(+)l3cF5dPYpophE7$K#m5fGV>D78t~KXP_)lXR7lGW0dD z@D?)gl=U&xH3OB%jYyiiJ2^_}i)k1kL_KjhXPgTXspV<^anQVmlPlH;hX}y>N{e}c##D6-vD#|tZsHa?2ycv~ng^Jb2Fll8 zL(4x-kN>{w1j7nzcE2u1#}e@U~cTLChD(`&_D<2Nox`$ zJ+ZndoV&BTBnoXL4N6FBsH(WTdj|M`iD|fl2Sg1|0{95jNY%kjPezt#kJNH=08b3` z3>imIPWpb5bR=N*6)LyAh92dD=5tLRFi4b)8} zOm$H%-k`B7x+o_{6;-`Jq&C{XgDggSBS}kb6DLb|6FqTBJ&cB)wvU-6mf(i*M4Gs3 z<4po3fhYnk)Nt;q_GbQg4NWOGDIc_EyRZD52AG7XUQGcfh_mkBh-ASn~n)+GesgQT=kszG|L=FY}0jygmOB*9EZRpN@S zs<(t6QbNo?*B32|Am{`H;LXkSRUNdw4cx>{UEEO)?$S;egp3RxBW}kWq4k|q+?~ad1SwM|ac``*xulnep)XF> z#ZARW%FIzz-^oXfAcmHfz#4-&;3d_J9o!|oR6TVOI0p+^dr=>A6O4zO7(NK?C56=q z^mI4(2ym2C4Rp{AH1xC71-3v#TSLOn(p=wO#lT3-!$3_(S6aeN+&R!N&=W<#=xUgu zOnhWL^t4PsQSx5*Hzk;=`gkF=aT0nc&?gc+)6+D-$>?JPFy7)AbE2n=n290A$PXpz zDT~5cNV%B=NjjN{xp{i&p}f&j_Mig6M8ym(iSu((^}$Oz8=GRyJw-Kw0)Wz9vDCKL zM7bIgB(%_1FkUzxF=GQKB+_2o6su;gferMKFwk~&(#Jaa8ydS~-HAwVAB3fwhqjb> zkff-lIMG$dRa?`ItS=^p8b0D?lE$9;p5i7>8jfyGDg-xTAkj;d;9`Pw^z{MjNlyoIBP~#oN(S#lzQ3EkN5$-%npwJxCvqwfEIS>7pGl7CPSM<`$-w zPFk+ASTj#`LoCMB9B-h5P_GpQ2xGH3rlA)HFGHm zZ(V(iq&LdMDL@?IBP;IjX{O>Eh{TJAVCFE3CTXJ~E_ zU|~S;MB1C1>Pcb@y^XbuyaVlJ(UyLi0pNVmATOtsvzv#jJ;BgJ%E8pZSkl|W0~2WC zjPP>TbQJT{ws6pAOfTud_4>idTM^6jykReGTMO-8a|$;o~js8 zRf4&*l)k@_q?D+cnYcdM*H6>S$HN|DB8~F!AbQJsm|}5`#sRWEI1N9QATtSqx4E~T zr>UBsfrf!G(a_t)520st#nE5e-v@y;(KfbMLCAuAq$=i(_Pk=@B~CPy0N=dHYv?6y zEUFLwB}>B9B*?+TNW&-Kij#@Ho{1Jp*T~62(g)*Y>h7xr-g|1u$aqTVcsN=}Vbo2) ziK&V;Q?~$;@K+%pR^s3U2ImO%45J)q;QJp4A&$(a)AgaD;iA!2S1}E+C1o(onSTpC zF#Og_rz8Iu!+dZH%k{0bb^3w9`HrVeZ&{^1vITED^TwN`9zB_xyl9x`r_%I%TFY7N zW|{+!<(K?@OCDb>w~WUh%8x%g3cu3(sXoWzxeaL}rIWPq{rl9uvUnyC?=dD%h% zQN{05J{?;jwppDDQ+o=XftgdG&lW_*#7Zg-1|!0gPCJg|72(>R#3`8#V#i-o;{^_V=4^d|-#V1~RcPp75%n~50?@t# zk)S^1qu?tIgo}n2s!T(72WD||`qsI7*J&wVDQ^%LY1KuV{>=lJ0#xyGN$ z>LQZV7AW8UH!cB(1&r>Du&A6Q+(3wlF`|^!ndE`E=2$(&6qz6M&zR4qBcGp_#3B55#_ZbR<<~=OThDcGuX8}Tf)tdKoVECCimqrYHnbiYdBdk1 zT0LP|DZOl*!bMVmDX#`aaD2Y47i9nRZpigyhIa(rh;3q9sVDwduCU5rFjvI%8jV64 z_rui&9lkB7AZNh%1DZ9`1DD~EkD4~u$~Kf~x@T#FB-F%aZY1k0!_5^Jn}uk94+(Wv z)!a#{g19b3(&Y3VTE#{?^&AyU{>A$`{e*E{&IBlX6EmHYX5{7CauQN=u6N>hh2VOILj- z4^gu!I`e4^f$P2GvqP$MiN6ure*?KM6#wZuJ(G@FFsZz+eXtz&S&c#AetF$^qI~=B zZ?8(jIKp?A+<%rNb=#JPUEcWaGr2umi1&l9+)3)W?Mf3F2dP4jp6RxN$M!kfe7=do z9-B`GtK@&U>T+$8wxN0HvQ~AQdfN~kzHO) zC3vo1wA6Q|NAFUW|45+oKnccqeQw~PGPC`qq#PNMaYIWh&aLyayz8*%I@!8wHji}A z*%E_ZIcE@IUOGT)PP#Z`l$S$e10IQCbSk|1D`{JjIPnEKf_T<;E4cvuNX zlM0HSJbg2Z{(dXDZ?1rFV1O6R=)H+6tm%DiS=xNb_FcbThFrP8cu(P}`sK6)5z@=~ z%PB&670brGB6Hk7t|_BttxCVNEgfb#rOF9A4Z4;;2|t|6xL6DwXtHlkV4b`rJ@V1t z0aak_$}EJwPj9=m(Dhht@>#m47{ld7<=R8?fy+*%4oz{H!xr$WUIRKI4t!B03roK1 zmuIZ3y6U9mi8gVj;MK==5-dCOEFbmnCntqSz>kEgUWEY-kj_a7idIH|&HDaHPE_Ki z#r4iC>^CPwQ4!-s*E)tN7!9|&2Mgr69k zNuFIlTL`ro5Mq`es8I;p4XE|8K5M54y*aJF+RQbl0o_c+TSFYCpn(D}H%Z5v#1GEm zy;RZ^xe)hha{SNp9Mjd^G4A8W-I z+|c04+a$$pY(+Ybr6^~*X1P^R_DkCyU1T(+hZ{UT&5?(WEaQFdD8)>5X5pngzo*jM zs}~CPtR9NI$Edt|h3gwV5M*5ZhXR}G5_YQ{?()5zjVbx^Ch?jQUK|Viz>DNz`<;x3 zB~jI3d)rLJpdF+S0rl))M>6G-<=yhBA-0!&j6&Rqgovaq=TyVo8pUa~;-*5``$Uo2 zO^4c*`00F|G$QOglBV10ZDeMN__f zsru6YA%ki7v?aw_+fSMyvie*+>UcVB z&r9n3HO*b-zf(g@8#HngVcE4GbWT#NY%Wj4w3&SamWvkH?!Tk{%QXN0@{GE@Jqc%y zymRMH(b)zz=%Yt8IVpd?Fo-}tm#cn;E`drSAB1uLh^7gDRP|F!1oj-9wN|ue^m%ye zc}`lY(jTFtWx85RFC+VgnF=WQYkxv4u1AYE(9yxX)UJ{S%Qg1L0Zc11py?ix^FDkm zktW{A>%x0(Dol&O0dvu(KEv=2WP>Vm$ zMqdP#)KA^#rlHl1=!6*^g)M3TQ+{0G&=Iu=GbT!3{Ke=WZ@o7+_CGi6X3xZ+%D{~`LyxS5B*iBUoe`(&J80Yc>6 zqU!oVie1=%wcj_hr^~q~&Z_+j$Sw-f5#mQ)T6*fN##x-~-e_bpbjm^Phrj=eB{h~w zAWf4qR6@I3-eXW=W$^<;`YA#4`-~%IKDzSc78L0hJMJ28CuGP(dVy25o?V`p+GiI& zdJ*+&IeOy!CEx zedsel5DCLGdp#+&P8`8=#UVGpCGyEX0;X2sv5oO+9A}AD$o$)>w6)p3soF>2NFMN9 z1k)Gm=HGv}ITk-q7hl~-M49edz6&5QCvEzV-;$nmSm-Zye8|~n8|<-uQ0&-}RujD8 zEPB%4Y-3?GYvClPobUN5g#Y|^Yb}dbitV$6Jy*9V*}XlLnI)VDW}hoDKU+Eu5WWx0m=0Gu_P#Z8Ij+`#+}I9c=gA zf(|PLuR9&2JVGyt6z&8RLASCyQej&6XtKDq#23`rA(2HuW|!c~=1*cbPjNfl7`5>q z#&}kfDt7x->SUPUf(&r$9&`0%Xs;E%=G*1vkGuntGo7_f!WHYJJ%{QXuW}ya!8mA2 z#q#Y8ZB|VVu>z<{pgz%k;$R)CZd`_Di#1lyde<`7pP`(l?Zy^{O?qF-FeAgj3yuIo8As4^FWW06z?1E9S>^zmL6wqGS`h zvjpHZW4NWH1eF%4C&SoFgKzXLt`BCnpN2(5z^>LlKEd_lma;_-iWr2{`qYs(JW-By zs`UTzOn-8JXF=&_f+r!RZ*XYXRPcu_P>wl1c(EX=Kmx2}Uf}wG%Zkm2gS;Rk@(sFM za7-WKQ+KGtZY?Mc{pcsycq420uav&{Yu3b6k5LDa&{O`t$k&7Yq!YyoN59wYj2yIl zDiW{n8A+U3zErwi;Q;Ts+i-#o_FOl@{{cYd3XqFTP}J&)ZJI$Wr(UVU>+rrZtVoQy zMd*5ImZV6{>Xq61N{hz%_fbbayC|-(t^iQ-Fjq6lxw?4y zd>B{9_Q-*XZ18Zi_@F^y3`+JHSBNm!mg1h@-{>W5#D7!CK`F)v5Q!UTVoo)GkmdD@ zhFlWYskc<$8_KCUsObUm$LrR!*|~?-pGVGJ7Pc%oC%=K~92~Sk3uaDir%B>UY>a?I zFG>HHn@i^tH-Jd2Hk%k;d}6f=j9C~P2Y@3eQTdqs2$x5b1~IU(cKi2S!t0ne&fOnJ z2Hsi)#+)zL6rNk64fcF<5M+G4Rk-+6yLV#_zyLg9bt@SQPSx+com3poH0A}oQ`x<{ zQnx;Rvk`5+x~(|Um0W#F37AZZQF*S%rPnQpC$tHZvKdNF6|yMR`;{=143rk`jb>hL z!W$CBgFp$ZIL zXqnIFs6>%|@!nd+kLFwJkGa8pKk_alz~#j`L_7D7L}i(rJ{vvK>aQ`}=a6umiqeIh z_sYQ?0bQK*1v9OjqP2A;3CNFr=H$cU^ewPuv!#G?)8tfM3}VSaK}J6jgI{f%S7h8m zDxP<#Q?uB{s;yRyOeFh!TGnTA$qamU=1~0YGpC|q5z6{>?b4F8J!k2@(Q^g8D$T`U zA?u_e7vZXD9-r0=d8vgV6N1iL%M%xu+IUW)`InB+EiwMccpBiN>-3&UdG&A>&skF@ zSamVrutD_*ZJItgOaE4p6X` z%4%RINZc=qROW^B&v-xtGlICY2WHrn!rpbqSaxg$X>&)Zas|<~3w7tE(tO~Hm_9Bo z9bo<-Vp6Y=_`Z8Ec?}*6PFxRAz;!BXx(2}7pr+0r2K3n48kOoFSkj}z$}T`Ys}PwH z*uOnb&7jA2GHvryzYUr#-I4m^Zu!?CzpA4w=v+>;jk5Rp=MXCccMtTH{w5X58-fw{ z-%#ajA-c18EcsOa0Rb=|jz@?NE&8flH=d*r;cQAu_&Ku!50rt=dLqchHB+jx}` zGpoP4MGs*Hw|9Zl>N779{7N(=qUSHBbuuKf&=t>9&HcX!b}NST8< zu1^~(bDX*Xw329Yq-!4Ku@{@SyODaHX|Mh{|2u#;g2->Zhe6Z=Qqn^PXF-_8Y>GhSKmUJz*+-K}$ z1~`B}!LE90^M8Y!;Q#<8K=yquKRuS^?7yj;DBYN1!t?tWc%A+w{7(Bi6*1 zjyl)~~HbADp9l}AE4AfLGH`iW(I#dDf9}*Dq-fCfc_t@ns=<-G6zw46ha+|(H zo`A{C@np(i3hpvVT>Im~%k}_rtB4iPw4*HW3fu8qH5xh_Ua(FDm}B9*;G%Ks{KM-x zT-m2e(eh2VQ_1ap1nX~f>|fw6n47Ztw%4v20nI6eq*}?P%bi^yqrwdzEeHlm5$eO@ z;v1mT`lZ8eG;||ipfzB;B9!Hy;)5P0za!hgZ1Pww9s2##Da%}?e`w*4ZTtijfd8Hw z-Dk=qPP``TMJwz_fEp{hU$y=MK#eAke3>uPl2!jNPQ(eIs4DQQp7a;lW$rP9M$udR zX!7DmohMr}F)+;5t_Eg010c|hu_vWJr~+N29p?gyb28Fzw)deVt`{=F)S=7;2U1dJ z)K5LgqKt|L=rUOl5y}E!BJy|mANgufc2CFIT;6~7Roc0TX^*?Yp*J-tuYMw9G(m-r zkj?ez+oe(XJHR?=WL|BU<)w(028bPYUM=G7(_=#J+&{pLx$lC3+|kSkvN8D2Oh;zK zD4MzAkMl$z<1a%>ukVi}MEzp}pujKdcbl0apr^=%M(iIn?dG)M_WSFLLxgwhgSdfN z;1NoCOLi9JAmb@MsR6~MMkeRI?KS7N2SS#?`r%QB?+}kNUqZYx&u`tS*jpH`mabNu zE(RD{9M}6gGo_$zKL{Y{!=<=BVSuV9=eANo03dIBb7|bNU3w%S_aVYwb!I(R@^)AX z6})FOxpOkMecDaF+@7U0IyX`yj~55P^3svz(+^s@ckhJNZGFZ&D=v{e&oBg7%=%C7 z%MVkvnU*DY_DW-Fj13&cptM``5crGud)40!h|JVYrs2ej-Tqnz4lq-l^S$tzUTOF< zq)H%w=U*9X7zmBzK z_aC|rV5`USUEcC42NsJ(&`9vLb9?F?db0uckfkP;Tf0`oRWgjt4BK`sb^XHcbFjCO z{x9gc_U#qQ#iB86u*~&geJB9p?WD?4&w@8&f3Gwg6>*X;j%HoMo|3OCY3#0S3 zanMQvecjBLJQw+~sSJPH+AqNq$tdR#j2_$gap~_@=WBQ7U)#;7jonj{08S#;ZDipv zJM(BGYN=&i6VzgsaV zb?MC1Q;zj2?NdJ=7jUly%j4JOCs=@73? zdw1g7fJ;-^(FUQw(6GwfI|Fpnjnz=WmTYO_lk-m1m>aFdTLowOmd!S;JmqPBU36BS z=uUj1(%5ZcsE|x=4aa+v;_Y^G0+&AtfJt5*u(55kAO>Svyu1A1fx94UeAT0yK$B$9Us^j2gYzd=oYH{?ohjQ3!kbhQX|2X%du1lAcII<_Qcc%5xn_6vQ)TM?Wve!LiSKR`|$I13&-{d{?da$flSxN_S@f-h)- zM1<$KJR(E~PCj%gVILin9Qcc*#ApODJz3l|yMDSJD__%;%hY4gSU9XeQX09sBNV5# zrJS~F)toYHKd|&Q&UVJI8CD#;_(NsoVP^`8 zg>wb*^{0x1f8Jm@Gw}A*l2A@fcwS#K`m8RIF!3RDJs@uQg2w9Mz*l1@Azax45!2sF z8^jJ%#u^{_Df{&6qLP-=b2q!^mZD$E*YNy)Qdk(iH#<33+S#GBgfEPRB{P(Nssmm? z?*>-$t)j2lv+M4!6dc`>luvek8N{1xzGn!#o#ihS_OalAjT!8PJ(^5t|Dhu%9+|Gj zoi4Bb)PQO%nOn9EUHdj*c@^H>%MfUz{$lQB+W|>5c7L2H%9~66ZBy=?qyJLVRfw6lEsx)sxFEfJ24^D8P+Ke0O(!z>B|*89UI(#%&| zyN?E&sw*DbTpz-_T(eGeOd!5{A9mgtBE{(>zop-~6rE@g_l6zBXz<4@&mC5v94#}N z^A9GlcJbfx&j;0zluEjNFX@M39`@pQ@{czyEPtyI!cEEdmh5kr8HRc;eabAp2bM{{ z7Q%RlVjhae;`LVtGn`~OjMrNDTPM-Ym*&?Wc-Va#nKU3eBNM82?GscKpT27oYzh69 zF4J*&MbEG5N|x2vY{d15U;tJ(^kzhz=m!7N#Ibn4-aJeTmC(F8S{pi<6E7^5_sBbL zs})u2@Ib__fUyo>Tw#ILW0BmzLfzK_P!(AA6lR4S07fp+!fR5jy<-D`O)SBG3|Oey zDB*PNj9ceI4rQMY%4dqP!_Qp33dI6oAbGzi_9g%f zaqJ9aP$0nTwLO!U?mrs30lD|ZK>l;cZ<8#s(f#$xZ#0@38ec0;gQk-~Jwf|iV;B1S z@S01i8T#UhYS{$3w2YCZ@fNnvmvb^w&M?H$a>1m5(7$i-RfW+FHX(6G?7?M0pDs0sE52qH)KU^xfP zAyqD60FK@)YfF3pK#wJVxM(SWoerjzLMic7_wGmTAJ+kzq1TX`IYvtw%PF7L`yul; z+3%<?vdQ><@T%f)@Hjmr|mKPx}|lOBHw$A-oyB(Gf&K z_n;rY*IBSiXo2hu%`#&Ck@^T&Ogz{y1tE-|5tNZiyI;1wNdxKOqm-Drd(Imw18xC+ z*X|g|sVP^#!II>dWD+Th+10^|uI@c_RTON-!wjFB;Ot*_hTf4BgGS?b~mlu;jN zOX{PDm{PjxTJQE1en4MrC?!&awRvv-2@cIX5vMAPc;q;M$z5`^WJSO!&>X(5Yz=xLOx(jp z!zm-RA77G#aNQQBl+aB%_g|{=e^XWdSJfjKY8|#UF=;irZT_^v#@%;+Ybrf-XWg&c zFC>}&x!Do9vhz!{zn?w6@e@hs^tO!A~sSws6`Y!w7Ak*9jm z=T3vadLbPnKOEjQqJ^%G>4LS=&)VeY;k_;07s^zS~=n z#!~kCZ`u?;SoL%{KvL!`{QR2_XJx#&J$Vb3aE6Vb^DeX3K z`L^N>tKy89i6a~VTtnK-#qR*ne0>1^JbbE~l2(rEb1u~8G_kOec1TE>-lX6@OPGbpKk6{NFp+?{(b|zGoyb*LA zl78!G$v3h;e%yR@(8g9Uf;3N>8z}wU{!qL$!&cBXeoG-_v&gdOstUgjQf7!)k(J|d z=f!Y0NvT>;iYJ2P>D@j0Y*weu1lLzqx5^M{1eNeL*Il@?@-ePS1y@QQ~`>lx+<4H=HbaC47l7(}R6Y(~e9^ltn2!)pp&-U#FBI!nzq}2noXP;b z$KfuOZ*Z@MXN1Cn59L(4`E{M3Bf+1Gv0QkkwtA7vo)J!wY&`V%6CS}^#6vsl zp@bu*9a+rCjJY5*?fIO_^CQ;rBMadNI|CK~VhWla&5a$gcL_4&?~iv0A`uv54{(;B zQo-tePK^1emMAedT30vq@j7W7#MY*NMo$YR+a_@TxS_0uL*(@7O0j-rqx8DM3_Vn- z3fA+@$P7v86`JK^GRoFfapP_0!-=+(l;6Lda{SBi_NV##cZLRXk2lSJ$upFm?addr z+ZpUzc4Ta53@eRNSnmq&W$CuMSaVvf{wQsV51yMwy)eaH?71|>d`$_#4tw5+Xp{5u zd)60*L=mLRgcEk=t2;lk4(|JurG*WhymKa8wWPZ@saN<(|KeYC`qa%W^-yB_L=t6l z-(cb9czfb7sxZYcNw2SG}6-$A^)-`)k1 za{ckLwcPTfGN#s15hirUhnZq*^DJ}79w@R|10JZWLUi2UR7^%!tkx{lgoG% zb!D{;NKVSKPCRA6Pmv-uSjU2>s+Kc7ucDXXxLHjcYUB`FIXj(di-#{Ac~_uAQSO)9 zD%GB_n71cndb>i7yUl9O0aneuP&VXHlB~~UDru;)QsL6L%8w_IvJC_6gqV@L^@s%- z$^y>HocPYE%GE1(+wpj((!o1&j4CQWQm#cd&d$TRj?|!;J-FRHC<%}1EKZNPsW{Hn zWn{w>G=82Tr;Cw1DS6VHe!qLl34XVGiVtt0rMC!wZ#_Q7$>6bvC8fo@pX%3dRLdg3 zu+N3zHH7;|jIk8yWe~0Bs<h#db-cC+$kNhKWzpFqIf za#mv91A)4SLRJ;0Kb2l~x6vwi%B;GZ=(05X@>M}=D2Kr+in%EZR=MOh6qkV!2!GOA z!<(cMe%{u9*l!^8RFB&H0X}RceXH|2YAN5%<^=1}ZYw_4vKfHcfXSQ{roY?=i+OQk z@N(}}{~%;)>$TB?d!L%JxJOD|4Ea5GkcJ1HQk|I!@^-uN4HlVJqFo0o%`qcC%|=Xb z4f%Y#D=iq5bXL}(0K~#BC#}2W+U#|;E@Im(W5SnP9-PX+pf^SjVFsB8VyA7Yd|!~g zR-ehoXRh43roCs~-ue&q!c)`BEqdQ_k;lLBy z!j@c{^zWfvY9m+Pa35eG5`Lsf-^_pFF3EJ zY1sCctV#KZ^}Mq9>U|!>#8gpy;3bamna)BG9=2FQ?ZR@cE3ct5+dNmE>8F?A@HJ}> zEUSqg>zWTw-QL^#4kGrJA?v3Nx;r?E@8BxJNY%`hBSARkLU!E9yTHj8d6{BSse?*` z&57*kTLON!d8OoHiDhMzac!NNjW_+r1*;fTq({uee-D>rGne;mN8im zN>}Zb<}80*>hnlIKHHmX3{Q_5E9PC&OyteCD9-6Q5vJxNl9R%xBt#Kn3UkeB&aI~> z2IYFa#Jc6N(x^Gjod?m~#Gv@xc3|8Y=;5k7SCBEEJoAfeOPsXB zF2Co%!;H_<=`^P8j{a>4m#@eN^rFTLZp{U=p$;ZD_Ep!6M{#t~i=PE0~IL`BuUtdZ{p0iR`ybdj3Gk;@29F3%q7oGvZdC_dt~&j>GXz2BLg#m2;}7 zA!KQ+>1k3lv^sjy7VPc|wDGA_9I59XGoemb(zP&DS-64~uG?MKJ8KPmy7`Sgbzg?U zpP{bDUwXcN$kY66|F9+D3K0uVwu!VDE6YVq`7c&;DB={X=ED~S5SrdoYlzePq`7on zyKedvE#I{^Th4PqNWEGxYD>=v`z+ner!~-X124)Ls$b!dj)auTH#_|Y%;8JrV+N%P zJSHcxJl~yA<(s$n8#R|YGgC-PAKXVhZW93;b2k?c`!Z&*z||d0j^Ybsg@`$xQyjWE z>>)D$y%qN$c@EKL;JyUaCTLb32<~kwnYtaEW^L?Pw{b#!C*}JbNR}Pu4Z3MaZ_%hu zvF#2HYL^5UvroJIqiqE_!cUWi*nk`RQQa-H^>f2sd(f zGzsVQh_@9ak~pQ7!v%v#1;4PIyCwK}SVyI=T=r3kkn>V0w&f(g7tWmdwr=6l{VkCoCQm*UtT&&) zYt~Okh3bCiz$}v)+`@vGQ%2LN8Srfl^D$S)~aYkjKpVr2fqPv@mq#Q)-W-1Be&6$pT z>j6;;V%#o)Pi=o?ux$}o;Wb25P1bM}gCcgmW@BVdCN^|RP5ou)$9bpQ}d(kaaKu}rrrX@~F)&ed>;3xj#t=Cvm z%IPGS*;YPQ5%9}FLL+Jfc_C4-lO!*Iv|{xK$nN2r3Qdv2#cZS~cb;eQE;(zbwglV2 zP9g@i@zd>iQgMjqm--!h$nz-s>j8UC5VFqTuC0T8e6mtMVWzrszp#t#bC#T)rTLtR zd?sEvZK=FChHFZ&O+vjmQaOq$3Ki6h91Y!96&mg7qN5au5Xp0@+v@vMp?S~D1lQrp zX^&C#<9_upn^nsPHp4bx1U62$6uFGXgqX78VX=STr166p0DeGhMOYb8AF(J)WLoNS zISV=SQWwN?jXBgG^HDCEgM{K)e%jyJ>48U^a8y*$_CG`w5pvVcBdSYiGO}{8Ci|zu zCUh0CW>dzPIl1v}X1X(U$P6c^D|HeVx<%yF+ID*hr z5NdSfZ>`h>9WV-kQnqtMQUnOzzx z5iVV~*(73s_5S0+L=AmYuKoi8`+i3?!@TsfA4{I@o|Q9RWs#x)jHB}Ccdv9K8o#c? z69Fw=+(G#=p1<|*?^a`9w?WRN1;cA>g#Qi^F{GHW)?np$VR-h5s{8qiA$}KvJbVl4 zYPc`E1wd#WDP>QhfL|9}SOEoL2C2*bB*iBMF3lYjKi1c@v09aoQp@!tPMLgg_L*Iq z&SRrqZrO~-F=jvs&AiK)==9@kp=w;tbjLr}#EhiINB0|?qbLv}F&(Iye^`3riS8i@ z`|YG;N;}fM*SHJbQ`$MvL14;0G1h_q(#;)|&aZb+%!tL#BUhWzh{hY!PY?fQ!eYnr z7fvhqUIXM9Cf9~fH1rY@8$3aW+9ic0wI~xjUMVWjhS`G_*M-=Cf*@?}3US;-a8GFf8z+G*PP?n?)$!#Xv3`M={ zpk#kkCerw2k6%BPlX4~^LYGp)Hbpz9aFJSK6FzRw4raz4RE7bH`9EnyzUC_p#F{GQ zDm}(fkTyg1Xf-6AW|)O#pZMLCD?};s5>8nNbKN8PRn)sqRV!_sALRKVc7fOZGfxk5 z{kTij3e4SU!4S%XSi%|uEP!<}y2;@&KrZq>oO6=_ImIc3DqrDy>UKY=@?GR@{vZeB zE4PYmBNvHuqZawrqw=bNa=oZ7@UF+R)BaX&p%)|uy`Y7@IoH+oJ$~Bn;koUmoG7W!M7ZhA>q>ZTMqr8w4o3 z;HPH7O+V0&-*oo_N|A3+iVDAa8f9)nwX`-95uLf>PwU2BnCV5PRA0i`47N#Us1DV59p!Dsmv}!GEa=*)RCN zq$)%ANULr$2?+^U{o*KP398<8n?fU>Q;w?)H=_hOV6Ug$e_!*mCZBR#*Ba=dWy)0F zpX&T+9xm!eFv7m+p#h3R`<&kI1=%a7It`U1P&^qUjk6cuE|!xGu53i?UwZ849(c9< z1g--07A{-+MZ z2)RY1Vj`g&AeH#2zm1iz%22$_3tp@L5hg#6lcNBdSK~)LxVwOD1zwvG;ZwA=z0_^6 zrjT>c9Tgis<&@>#_QDF_cR zq_?qzFvS5N?Kt(>Zry= z2V#oQyIN2_YDg>gu_%c4G4fKT8vB#i8u|uM5B>D-?>F#MB3kyE@&15%Xh@OPlsI#9 zv@!%t6@KmxOotj-V^nhlLC13%l&La)(0l_B3kWHuo!`5mPYJ9wBr-1m3R)ILS{*Kz z5{^egLD-B}i--F@7o`)v=w=Z6)B>?Q5c}kdPV(aZkp?20lE&Ld(V8aa&#Wyb7fgonyByfT$S=FOmbS$2fng)=Po_D=vounm};$efZj=YGx+JD($uV-*8E{ebn0|9INx!7~Z_`n_zOB)8+65_=>WTyqV z_N0r1Z?#SCEri#3`?iDac^~>U1AoN<`5J}=nW&Y2eLMz-MZS#hdR17P7CRiil@k7` zY5s`fVq^r*hf`oTO3;~2rFV_hb3)ZYJep0Lhh9xPdyZ!{>tHKuawK>`@?f{~;1TI} z>-;>(HYqrJTpU!w&|#+1?*ktS1P!*h2d$VIM4em-P)WK%ejc?$gm3tVyZqV$0Vc9< zw(b>ZeC?L={%&6wsc(5oY3q~W@)YO(;?0#Q&BU{xvcjj;I9s#o)_SeBR)AY= zs&h1KhqSx(&?WPsl2Xtrc7HcPyyK(n!D^n;=fWg5Y2mssvh#Brc(xO#7W`(SVMV4}}Zo>aEGB@(t2zqlkK8Im3XC}Rn|r0Z9cfpH9Nw}=f|l@-ya)i zo?MY>e?X42>i`RoT-5!%6w(?uQU_!p&7ioM4JTZvewVe`DBx``8o2!HQ54jsx_<4b zO>m9f^x*8CYM<=_OVxUi@ig;a9{+qpU`R@dMx50*3z5-LCKz*TUZJihrg zQ1lM$F|IH^yPN@j?%99`4b8Dc^6vsvtyled#o|AY1pPIQ3-b7q*2Y*p;h@vHuJXQ} z8wE8ZBH&rrPqc=N-+Hs&M*`{WeHf$a4P`4ZBab`Ij}X8tJ_@S_WUhAi{-XCW5hs^| zznP(Kz+tw4Xp+HGL?oek56E;$G$7Y_u*)6_;xjT^MduwXaUO{7D6@_A;m&|yC50Ml z^Z=;-CDFNR{p^Bip*XvNt>j#ql9ipC;hQ&y4@YfK`J<6E{T0NF+b7nCaO%Sw9)Qgn~ZYI@t*}84Q@iY*=WE0Mr-cuvL!J zH|_zq2VjL40JjIASHv;_8umLH=%@g&gdiVk7+^xcp2I28X@DG#D!qvD<2D@}wf_I6 zGT`Z;yaU?*$(mRMjOp2%^10hQ6fUhD0U=Cf6VuQ=1q0Ik+3;qCN;D7Tf&i9rnGR?( zf6N&HJqafD;^x0&Oaqeo_bVX%o!jUk7_FGx8RA_E3D=L2&H#*d1d6B(Q0uG*cKymB zSHOjkL06Ye!-XJRMk#=W{U`ZFdDUD)^Me7Ej7}wKliAH&3gBE@_0A+VQt0&Q{N12M zvV7&h42B+>{(R0v<<}CzXrFkmRLw)g|nm-_^`^1C9KES3Ikpwhk z@*4kV6AI4a7o#&H$z2})cU@8#3* zOGv#8$T5K+!2&<`{h@~jZ(S$SvE^V-oyZ~g)Cw{iE~p)~g35rz62G{69oGaX09|BO!;KOy9!xg%B&y><@|q`1xQ1v{&A>T96G;boqhuBeD_op>F5)x8 z_qUFHs@tEfOM6vNb+H-{j8ZnN>$ZQtDxC!k?D@C*0D!d&tc~sskCNVo4g2+B`ogFD z!}6xK-vzFe%!<2o%)Q;u3*XKgSThV;zNgUFgnAn`^E74MI>q8wRm^(M!7}&dw~8Kv zWtp?#ODy4cZ0e?S;)4oCy*?bboC9o+nYXpz*COV&x2Cd2efA0uwhK#Vryltjbovbl zrL+vVWDWc5O{U{J3c>+60z;V1uXOGc&`a&|2?b%Ofi;Hk%?}EFD3C+C72eG1vTAKt z>1jg@ZBG?d=sTFi@AFshM>2$DPi+I|>$kaWGPIbm+Bwb2+MVVAZc)n0NU+x~>YY}} zrl(s1$zC(SjUQY(Yzu$L^Hm*^>D_vPwF^Ayv>@;v0Jg(umdyb`pd&teQJlM1i8hKf z0>p~XZwTWhvtkCtSq!1mY6EM$nu)8{WPDXJdy|0^2=Pu*$hqpU#UJl?t9FBXo@fuO zaUN{83>=V7bMExFl!PBlYbyPI8%B;z9*k7t?F>eDyvEE3Y-K%@~Hu?QC>p$Ojj6rb!C!Y}D-y)vZ})iMtrAFMv$IHS4;u zIKh%|7S2nm0$e}o03i@YJA!nBUK&;fH|0%aA!ZR|*J2t_kfOOKVOwo>9gQLk&?2bu zA+Uk0AgTC4p3gEcnMk16ebK`5h331h1lobE^6HF}T4^8|y{BE?82Eod9{I9LhA8)K zxR&ASVB-O}5`1b}$l4podI%`WSD0cMuflaCmabD%#4fb54+C$sivvNn+w z_ggb9{=ouTAkR>`Jb_7sVpcbK>*aO#`^CMNfsOo>0$^A?3<-=<84@I@mm$*#TwZkG zJVMgaGIIm>77QCtv!ZYHgq8fOGT^%a>?%CxJh0mp(8Z1`|NV2yUhF1YzyHhMHv%m# zTq-B`L`{7dt ehkNmW<}IVum8Uy%qu>WpX|$0B>IJG-ul+Xx+NA6N literal 0 HcmV?d00001 diff --git a/src/main/java/seedu/meal360/Ingredient.java b/src/main/java/seedu/meal360/Ingredient.java index 9241923f6b..fb1a41d201 100644 --- a/src/main/java/seedu/meal360/Ingredient.java +++ b/src/main/java/seedu/meal360/Ingredient.java @@ -8,7 +8,7 @@ public class Ingredient { public String ingredientName; public Integer ingredientCount; public LocalDate expiryDate; - public Boolean expired; + public Boolean isExpired; public Ingredient(String ingredientName, Integer ingredientCount, String expiryDate) { this.ingredientName = ingredientName; @@ -27,9 +27,9 @@ public Ingredient(String ingredient, int newCount, LocalDate expiryDate) { public void updateExpired() { if (expiryDate.isBefore(LocalDate.now())) { - expired = true; + isExpired = true; } else { - expired = false; + isExpired = false; } } } diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index c82d1ceb23..d09fb32b73 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -40,7 +40,7 @@ public void editIngredient(Ingredient ingredient, Integer ingredientCount, Strin if (this.containsKey(ingredient.ingredientName)) { ingredient.ingredientCount = ingredientCount; ingredient.expiryDate = parser.parseDate(expiryDate); - ingredient.expired = ingredient.expiryDate.isBefore(LocalDate.now()); + ingredient.isExpired = ingredient.expiryDate.isBefore(LocalDate.now()); super.put(ingredient.ingredientName, ingredient); } throw new IngredientNotFoundException("Ingredient not found"); @@ -83,7 +83,7 @@ public void printExpiredIngredients() { String expiredIngredients = ""; int index = 1; for (Ingredient ingredient : this.values()) { - if (ingredient.expired) { + if (ingredient.isExpired) { expiredIngredients += String.format("%d. %s (expires on %s)", index, ingredient.ingredientName, ingredient.expiryDate); } @@ -103,7 +103,7 @@ public void clearIngredients() { // public method to clear expired ingredients public void clearExpiredIngredients() { for (Ingredient ingredient : this.values()) { - if (ingredient.expired) { + if (ingredient.isExpired) { this.remove(ingredient.ingredientName); } } diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 2899dd6257..c862021db4 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -371,6 +371,7 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { return recipeListToPrint; } + //@@author jaredoong public Recipe parseViewRecipe(String[] command, RecipeList recipes) { assert command[0].equals("view"); Recipe requestedRecipe; @@ -395,6 +396,7 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { return requestedRecipe; } + //@@author public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { int recipeIndex = 1; for (Recipe recipe : recipes) { @@ -413,6 +415,7 @@ public Recipe parseRandomRecipe(RecipeList recipes) { return recipes.randomRecipe(); } + //@@author jaredoong public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) throws ArrayIndexOutOfBoundsException, NumberFormatException, InvalidRecipeNameException, InvalidValueException { @@ -544,6 +547,7 @@ private StringBuilder getRecipeNames(String[] command, ArrayList recipeN return recipeName; } + //@@author // parser to read dd/mm/yyyy format as local date catching invalid date format public LocalDate parseDate(String input) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); @@ -554,6 +558,7 @@ public LocalDate parseDate(String input) { } } + //@@author jaredoong public void parseAddUserIngredients(String[] command, IngredientList ingredientList) throws InvalidValueException { String ingredientName = null; diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 3ccfcb32dc..bbba91b0e9 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -114,12 +114,15 @@ public void printHelp() { printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); printMessage(" /q {quantity1} /r {recipe2 name} /q {quantity2}"); printMessage("10. View Weekly Plan: weeklyplan"); - printMessage("11. Clearing weekly plan: weekly /clear"); - printMessage("12. View Weekly Ingredients: weeklyingredients"); - printMessage("13. Give a random recipe: random"); - printMessage("14. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && ...}"); - printMessage("15. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ...}"); - printMessage("16. Exit: bye"); + printMessage("11. Marking recipe in weekly plan as done: weekly /done RECIPE_NAME"); + printMessage("12. Clearing weekly plan: weekly /clear"); + printMessage("13. View Weekly Ingredients: weeklyingredients"); + printMessage("14. Give a random recipe: random"); + printMessage("15. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && " + + "...}"); + printMessage("16. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ." + + "..}"); + printMessage("17. Exit: bye"); printMessage("HOW TO ADD INGREDIENTS?"); printMessage("ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ..."); } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index a3ed301b97..87db683998 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -31,6 +31,7 @@ class Meal360Test { private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; + //@@author jaredoong @BeforeEach public void setUpStreams() { System.setOut(new PrintStream(outContent)); @@ -179,6 +180,7 @@ public void testViewRecipe() { } } + //@@author @Test public void testDeleteRecipe() { HashMap testIngredients = new HashMap<>(); @@ -195,6 +197,7 @@ public void testDeleteRecipe() { assertEquals((oldRecipeListSize - 1), newRecipeListSize); } + //@@author jaredoong @Test public void testAddWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); @@ -795,6 +798,7 @@ public void testDeleteMultiWeeklyPlan() { } } + //@@author @Test public void testClearWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); @@ -821,6 +825,7 @@ public void testViewWeeklyIngredients() { + ui.formatMessage("penne (1)"), outContent.toString().trim()); } + //@@author jaredoong @Test public void testViewEmptyWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); @@ -838,6 +843,7 @@ public void testViewNonEmptyWeeklyPlan() { "salad x1"), outContent.toString().trim()); } + //@@author @Test public void testListRecipe() { RecipeList recipeListToPrint; @@ -968,6 +974,7 @@ public void testRandomRecipe() { assertNotNull(recipes.randomRecipe()); } + //@@author jaredoong @Test public void testWeeklyDone() { WeeklyPlan weeklyPlan = new WeeklyPlan(); From 6f42a9c73e96d6d2a58ec3a9e8ff0b738e46d2a1 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 7 Apr 2023 19:59:24 +0800 Subject: [PATCH 171/252] Add manual testing to DG Fix minor display bugs --- docs/DeveloperGuide.md | 106 +++++++++++++++++- src/main/java/seedu/meal360/Meal360.java | 2 +- .../java/seedu/meal360/storage/Database.java | 2 +- 3 files changed, 107 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 10c33e581c..d6840905f9 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -601,8 +601,112 @@ Given below are instructions to test the app manually. 1. A user input of `bye` allows the user to exit the app. The app will then save the data for recipes, ingredients and weekly meal plan automatically before exiting. + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | Saving recipes... | + | Recipes saved successfully. | + | Saving weekly plan... | + | Weekly plan saved successfully. | + | Saving ingredients... | + | Ingredients saved successfully. | + | Bye. Hope to see you again soon! | + ---------------------------------------------------------------------------------------------------- + ``` + #### Ingredients 1. Test case: `add_i /n fish /c 10 /d 10/10/2024` Expected: The ingredient `fish` with quantity `10` and expiry date `10/10/2024` should be added - into the user ingredients list. A success message should be displayed. \ No newline at end of file + into the user ingredients list. A success message should be displayed. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | Ingredient successfully added! | + ---------------------------------------------------------------------------------------------------- + ``` + +2. Test case: `del_i /n fish /c 5` + Expected: The ingredient `fish` with quantity `5` should be deleted from the user ingredients. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | Ingredient successfully deleted! | + ---------------------------------------------------------------------------------------------------- + ``` + +3. Test case: `view_ingredients` + Expected: The list of ingredients should be displayed. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | Here is your ingredient list: | + | fish (5) [by:10/10/2024] | + ---------------------------------------------------------------------------------------------------- + ``` + +#### Weekly Plan + +1. Test case: `weekly /add avocado toast 2` + Expected: The recipe `avocado toast` should be added into the weekly plan with count `2`. + A success message should be displayed. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | I've added the recipes to your weekly plan! | + ---------------------------------------------------------------------------------------------------- + ``` + +2. Test case: `weekly /delete avocado toast 1` + Expected: The recipe `avocado toast` should be deleted from the weekly plan with count `1`. + A success message should be displayed. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | I've deleted the recipes from your weekly plan! | + ---------------------------------------------------------------------------------------------------- + ``` + +3. Test case: `weeklyplan` + Expected: The list of recipes in the weekly plan should be displayed. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | Here is your weekly plan: | + | avocado toast x1 | + ---------------------------------------------------------------------------------------------------- + ``` + +4. Test case: `weekly /multiadd /r chicken rice /q 3 /r seafood paella /q 1` + Expected: The recipes `chicken rice` and `seafood paella` should be added into the weekly plan + with count `3` and `1` respectively. A success message should be displayed. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | I've added the recipes to your weekly plan! | + ---------------------------------------------------------------------------------------------------- + ``` + +5. Test case: `weekly /multidelete /r chicken rice /q 2 /r seafood paella /q 1` + Expected: The recipes `chicken rice` and `seafood paella` should be deleted from the weekly plan + with count `2` and `1` respectively. A success message should be displayed. + + Expected output: + ``` + ---------------------------------------------------------------------------------------------------- + | I've deleted the recipes from your weekly plan! | + ---------------------------------------------------------------------------------------------------- + >>> weeklyplan + ---------------------------------------------------------------------------------------------------- + | Here is your weekly plan: | + | chicken rice x1 | + | avocado toast x1 | + ---------------------------------------------------------------------------------------------------- + ``` \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 47e2510f50..32e8b63ae1 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -250,7 +250,7 @@ public static void exitApp() { ui.printMessage("Saving recipes..."); try { database.saveRecipesDatabase(recipeList); - ui.printMessage("Database saved successfully."); + ui.printMessage("Recipes saved successfully."); } catch (IOException error) { ui.printMessage("Error saving database."); } diff --git a/src/main/java/seedu/meal360/storage/Database.java b/src/main/java/seedu/meal360/storage/Database.java index 9954ef9a58..5a21c77c42 100644 --- a/src/main/java/seedu/meal360/storage/Database.java +++ b/src/main/java/seedu/meal360/storage/Database.java @@ -147,7 +147,7 @@ public RecipeList defaultRecipeList() { } })); - defaultRecipeList.add(new Recipe("creamy Hummus Pasta", new HashMap<>() { + defaultRecipeList.add(new Recipe("creamy hummus pasta", new HashMap<>() { { put("pasta", 1); put("hummus", 1); From 0ca2d826cea24760154d81fa9f325bcb3ff20697 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 7 Apr 2023 20:06:59 +0800 Subject: [PATCH 172/252] Updated expected.txt to pass check --- 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 9d3811c5f1..a26c8f108e 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -101,7 +101,7 @@ Welcome to Meal360, your ultimate Recipe Manager! ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Saving recipes... | -| Database saved successfully. | +| Recipes saved successfully. | | Saving weekly plan... | | Weekly plan saved successfully. | | Saving ingredients... | From 35db58184d777441472c70bfc7ff64e90a7783c4 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 7 Apr 2023 20:32:07 +0800 Subject: [PATCH 173/252] Fix sequence diagram Fix return arrow not at end of activation bar for EditWeeklyPlan and MarkDoneWeeklyPlan --- .../EditWeeklyPlan/EditWeeklyPlan.drawio | 2 +- .../EditWeeklyPlan/EditWeeklyPlan.png | Bin 64996 -> 65512 bytes .../MarkDoneWeeklyPlan.drawio | 2 +- .../MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png | Bin 47574 -> 47689 bytes 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.drawio b/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.drawio index 89bd599e96..ad9b6a7151 100644 --- a/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.drawio +++ b/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png b/docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png index f9f01a6ff2e062afa98779e0c4b97247295353b7..bf3bf3d0674e6f333dca4960df3222924ae91fe1 100644 GIT binary patch literal 65512 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

7;|k6yNV=Z18P|Mp@y znc4`1Kni(>{kL}Be56~$UiT6NNQ|#W?Ns`6`G(BF^J!~g^KB^FPM0UHA9nUZFP&hIVYJ> zKYa>(k6EmU3;m+>QKHE%ANTBaW17CeI#s7_TS4aj8I6-AopVdmz0}$u&Tw+ekrZLH zp&hi?Ymh+NYo6b6<(_rZp*%KKgaODeQ>syOYwAs{7uryXdWT`iU;hwFeR!hx=cIJa;d{R9=-gqE97gx>GJ3 z|It~-&H*6jug3aP)$@1n4=HEwRmYv?On)M;%@+7mq7(1Q0|Cu0iHrVRJYPR2z4+3d z9_cO5ghXyV6a@zM0=?NcF2f0QVK@5L34gi+Ab0V{xR|$ALTSZ#zMh&8OMblmQU{Q@ zx{cN>txH6P7C`8;oeHwOj>6J5lMR%ATJmI7!I}Hvw#;psQl=7>}Ah#ewTJ#8OYiHq+i0%*+neb1za)X*X+E_!+3>t#%bZDWonjX=i9d zSN>oGcXo*G3z@j{cmk4@0xnCswYZV#en8e{Qu5l4a0mT6PZA^I^!P2S1(HCbAUDk* z4eS-wRZL9`yL!7ShqYK{T{+zdGh#GB-Z+u+$mT1}`ZG}K$6PQFam(qjdKnxewLvm0 zq8xl+=}sPo!cA4o1Ox&XTY1MId!Jd{= zuUmAc#V7LCZ#I%*E8F2uNIg4@PQWo`dkVhg@*h-u%yXxb@{aRApKWfRnuG{8?Kn8< z@1Ifn08d)l;iQY#_Of7G5BTWrXx4mflhZP!c zqh0d6U2MO+nAV&bwqLZrF-eg+^<*IL+S~F0=+Td!`TT~tsjHg;<6B?+aQ^bZlk+J{ z=Wr=MWp@C5`azUWU+~Lt-$vf@K(u~{rN#Kc8%_noO1pBBYP(RNxe{iB`q}XnkMH@IWD?y`t?jQhyP%Z z51CcoVWBgp{&ZC-qcUVTi8N{MGrvvy_qQ~|u(G?q-Gc@$q`A(m=8YMr%g!8|o|bMl zO5QXjJw5H+%$(y*OE3k^)J^lPw>k2H#gTO;{uqn?0h`E?i_%;rlcfjJn|&+S)xmGQ zQ#rm9J$-6J#e`Au5|E+k$dhB%O7yzj3n3sONRO@WT;oK3)hYJOjcaw~*9iNaQ?OMMV?=8O*vm$?!i5;UZ9);g zbiiEfmB2l^V*fFz08Grp!}Q>Hbi>8vp}4(|8=rQaGi^RSnHIs3KXQhBCa>bV)m+Uk z+m2rA#53a~0P0bcAD1bE=<4!F_ZjZ;=}Sr{HdwrACjoiZ#oxXAeV2&Xj}ObMB4oDZ zH{J;vO$8!zw)P}T{_tH6z48Zf?vZWSyXnr1G}&hQPZT6{p7-t5rgB1K<*%!Cn^(TY zN}lR936bN+%EQZ zB~F~i$G2?Wr4rbu{jx9-0B1^oh?Fz;Q12PPxq1FQbuFm43BWTZ)z*&7{CN*K7Y2M}bC=cEjlo^)hnE-z=e$8mNd_Ey)sl1=o z!k(I2*}2)StSe~^r1tLj-DtUjoa>_qwev^Auim0-^21B>-(#HLMRvaLe=fvTh6n0~ zD(l(|G?Pl3`?lSek^O09k!K>Cv$d$c<=8n_i)Yxk>qk_~fZCTw0fL*kLJRs~x5}qV zn>*8b{D!!(O_+G#@PtCvaOHrbzx6}LnV-WNc#SXObyp-?r-!*>kG4^Di#wa&Ym z{lyi6ioMlOH!hvags3}@!Ol<1NRH}UBuX~~Y8Ky`+R9@Vz6q2+bLh<4%5|ihBfabJ z8u0so-&rXeDxN8)>2s&uWU3mj!%G?`P&J8$p^oSCG4y!)(b?_0ms~S{jT>^zz~v!9 zzT5bRnvmLHO$z9IT$Zp9$vyo3m-~RPVWX8&qb`|9)(CDX+zRD%|v(|=q)A6`B**XUY>r_x*8OK-qgQ(H`>nt6cUs)em` zNE>^*I&+t0bOXFmqwy9#p7Beu`qJp>&H;KOpHRC+?SZeCdEY|D)v!q~d5FhKd!k{E_q!KRIk% zIJ$RrLH-@JCEZ|g-#116Js5mYPMc45&Kc0!iMBq`smrLvZEmUY(#o0;-C2OgOrXO^*Z9NTd^M}v7u528w29?8^_VZI z)YX=NbM-R-f1x8Sr`4#YSaNsc#=j=$WnQ9jFWdjjWV^(!^oz`y!MVvz8uzpA2bpRA zy54&C>*qvwP7?3?+apc)6Hgt}-Jq?Z_=lqxGy!|moaW@sycxD|@aur##@B=38Qp%9 z7B`ojf<`UIg>7MpM?NbLCf8t`txIWXKz5H4mBd|pxH#6yty*>0KbIWV5~kfedHL}1 ztpIG(bZ>5L=FAzF@^k6EO^PI9G*Qy4^@gFJ|GW&Y`OqPD_wuf+%83)ckkQ2X-Rh?d@#9tAAr(~kJedFl{UNv zYC(E`_VQORP82k}F101X>xP_gpkw*)U}8Lc#?` zZ`lX>RZIEs3PrWNXX+=$jMyg1Gr;mCFTOhmq&o`F`WT4{W#mO{!yZK*I*#l-`yhp0@bwz-OPZ1{!Q6trGtgA( zXHmtExs2bTB;a1a%OAec=r+fCS#v2UUgv&_3chVrGxNbrugk_^+GuSE#b5T*_9kcz z>^QBZuBlVuA4fo0*czz>PhJ_81OqWLycirGpYLNl48WWF4F z&NyY_PVqsv@8Ml0VUNdu_^jrvHu~Ai|ID1acS&=+BC{ep&Tg`Jm0wbIt)^Hl0r4oK zMW+DW9#-OB^rRsF$Fc4mUC#%c+~|GESI45(O-<&ly)Ey$*K2NcCTLIM@pd5itpU8> z+U(Pvi4pVB4?A{bPaJL?);nKtutJsTUOdwAtmY}j+NW6{RQL*c4Opj{)Jf{2pgO1g z4Pmwi3tMm#xA%NFqBOT``+MGYk?q#K8e%trxj0cazN_6jEAE-g$8)DQh!TKmNdgvh zo=>-w_nnZ>37L5zn11IP$n{@});_*IF!7p0S1@vwUC~u zDC62~g$~RIs=3PNZxLOWW%IiPXTQFPjUnazz?;RMOP|U-Ts0l{J$%;KZN%e?Vcvdu zT9LOn;sD@RUX%n9a^ZIoW&3xD1304bmYwW-Q$Dw7EwtmP>fx6Pw3xE{X3w5!*7cl$T)oIy=3 z%%$|M)B8AKS{_GTZ5SHQyn>s!$OpiVpF70?UvlVPRaqi!Gwdv1vxn>7C-V1Pbpq$= zq;R36cf9h??cC`cTQ_jypx&z9K9_5x+T!vY@DC36F1wapl2$P{x}dInbM6!waPx{9 zv^Jkv;SZL1obVp0JoTtA9hdRvTuKa?CnZw% z$^u2nqgK+VU;YuJ)3HysJknrimmN&KG(KI{q#y8}3s}PV+h6y4c58%=wcj89@-{w- zSOECr>Ccr@yBnI_=D>X#Cqm>dPJL}i?12Uy`8L@Iqovkq7quNYzO$w0P#92+xp+$p zC*2oPy2>Yp7PUQ&-1Zj05Q@?P)b|_uV0+VTV_y@uO%5^H)xsF9Jlhi~`4gy0YbtCp zlrhOVhp71ePOa$yCZ!QDhzF3GT}i_#=Z>wW(_$umJ|9EDhyN>=fxlxZ%~xI8X# zHu1<~UDcQgtFN_hf&MV5qmaH2du%M8b=*?=S#lMKv?r{(jZKAnD=^+-3A?DL>@=+$ z|6zK_?B{l=4?xK`2L;rY+Y8TI!JAH*J>FtHL_oLE^78UO2~nkHmrsvM&go^j{s{b@ zu*fWU|10#{IeBP5V0s&E&#b(!%xlpdIXL%DEk7{KR%YH{wq{rNz)N`{fR02P>m{I4 zPHz?U0P5-R&j@B)wd~RB23@!NyuSJevGTlm$^j)?aoSvIyVSKs=A$&|p6{r9ugohA zpGdidBO@AH6HC_V3lTYs3lWR^(zd`ec=yZ=iU1^-^RlGmun@^-Zfoql%y^^I;=x?RJ1V_DZz zr?W^|VQ!QoX2~NhVH*Tpq>NtfbAPhTQ(+}Rq#l5-Tyi38|6dT$px!l8q->Nh$}rom zboR4-w0P`!Nwt4SxNY()>cxm__r}RTn4OJi_YmP04iS6bN=^r^DlE0XRsO(R=t}23 z01Yg%MYGqJnf7e9Smk%vyh9JhAs6%9%NswHvhLG8HwgiSKJoL=U8?&XUqqT96cm(1 zm>NT3IVNI4Htr~zI2@tZ(Xh8K<%q)6kb^$iy!%(y)ayU1@3s)}qAWXY7e=i`3VHt< z#FS&l+_4aUCbf<%pV)1Au5IxM4Zfi~Y;`f|k>kT;Va;2`!V?CJ+aLBkNrySu+F_fj z<0-A_<~zFSGXTRpkyrxK@y7~*TI9-be(#HrrDUMo8mF%ZpojleYke1d6Q=N6;Bn@~ z(Ut<5cZ+`5N)i4!JuS)TOyzz6)=D_Jye`r~4D=x3_3(mnNA@OoO|d|(v%T(5V&MMm zvzA-g;tzI!*xPj4dfo*mnKON3E zg|c3i6m-;GS3+$WIVo-ZAR(-#f---8<5?NiEfdeH9 z&lCY%QXY0k|PGT`nJGuMr+(=`RS5Fq}fo%p|v*Men z8poa4RMH_GhC4sg_oCse*0|F{6X3Sfci3v;q0K!=2m z^gT3a{5So2VqDVXx+LN7U#@P<{L9r7tT3Puj-9}Z=d0|rRJ>j@`%gu?-n|qt#m!9{ zwo2nnlAf!lCWgFMUjzaS^2c1f*VO1Hpz2AkHH4G4x`EcJyH{uJ{n^qfsbMG1c1v5&q@bsqd>86paV z)dXv^{L9w>1%2LZtETrKC{*)R!iMvDMY(q@9!5tL#i6INVu}H|!@SDd!Nh#}L@LGG zwKJvo%I5A&j48V|cF*vOnXvq{og+!iZsjYai@Z7LBfeqivVThy1@GAdRBMy6d$05; z59;O9rqPlDRX3-Bkr*)S=Yb3VF?kTDhqO~ZkGuGH?pMC6@g*r|)39#kEd)Rnw-~af z0Ap{{^(S9`!@qmJagSi0(LH%7A;^PSyGNGUgf8zrJSxS+u!jy$oXEsLrV~BFc`XIs zCbt>Pgr^Hiyn%?S9}rZZ&wxAh+G$Vt)qRfkncp_gBgL7ro^5Bh;)NS`7X8#`-Q67; zYDe404*gMRss!4Zc8=pypo9RQJxue}o^*0kKGwUxH1P~S~R=AX}CRr>}q2pa|`x^Oj+bV;-q-@MwO7cKlVe2x93`n zssi*5UGX|p>#$$_V3sL>bltKNBt86tbnRCQl{u$(XKzv3-|egTGp;bbR3;`&tj$#} zy=X~gf5ZOoUz%i0hBkJR^FZbsG0c+TRjKqoVfI1>CI%I?A|@cI8=;o1tA_Q=4^{J~_^ zA~SC<>+Mw@ndSz7yT7BVCrbXV&_Z9xV1C+pZwFH#(I)Z7xRnoR{AxV=b6~yDC{}Jx zWi{&#-*P!MMqUJdKd3Fg{Bl#H(XSz+k6MOlKqc8nY;pal>p4t^E=7!)<}1jD(}ezC z4%{^eCEL2G+vbmYcR2Mgd#T_q+MYz6nziilIJF_H=sLZn?d`#a*FZ8TSgIm$=br?^ z=O>9G<95eAf*9$4IlZ3@9F%|7Vv$k$Q7)rs&BX0tPxQ$I-GmFzbMIWqQj$G=pL0d| zx?N^A!nD=~>h#Cpf+_!_BX_Ide|D^4H*D#)&}(1kOc7W}ZHC3_DPt#*j< zBXYUWH?c^G_+lXF9*Qq9ikZ+^1qoBm+XwZU^A0+92)pie=1g7M$oBQXT(^h+Rf0eM zHR(FZedfj?q3w&Cm*Q^$Ktn{xW)aL$65{yspTPNg{ ze9gksEm1#S#Dz-|hb0BqKOD~Uzb{1n^CpKbNwZ_}i81_rf9F0a06dJn9AM`ZK$jyH zm$RlMfD*zD)j#DLUWbgIO_~6eQ{3z=H{l++yLHv?)fkubXp&@t|C*?hy#F}!;Hm`> zJfR%2?^NI1@zkOGPCU)TKO3<%HfHz6zfR@u=l^1tNTer_o<2f5BPpmp7Bi!C2q<;1 zynA+squxuask1gE8(slw=cuAX#Gjx20m3ONR`h$3x_XYUY1bHG{Y<^$;XX;hx`h^B z#C73Zz9vX1opDLayOKomKX&xqe>TRWVm8-TX;yF6Zx-i36rDzg1F$;ZyaB`XcHwbU^;VK9?(MIv`-02N>E~1reBGZDVr5t-XHpmq1 zO&AQzvSd62WSU#>(LpDo<{wA?k4d6dz-*q8Uz-O&UdVbeHcXPsSRd{O4mVbRLQ&;; zEY5Nw(IHCQ0MW9PKn3gx8c%euoRGBlc(@SQK#er-iEAw-t4WWf_3#Fz($2_13-azH z*{$zcGOYeL-oD2~#x#NGm$bU#3u3*uAmNTT>4+{Dx@9~A(gUmx=m7J z5CGVP>ncq!$dA0go?p$S9x(GQ%|r?_TcJAtHd_owjGdha@+a--v_C#OtqJw*o++2e zT?e*t`Qn|=Y?vd-6grX~Qt|lyVg>RVwZ4Ub^bq~-l$gVevcu~4>wKR3jxwbKpm!*E zu#MycIMwp;LY?yVZjFu3t;4;Iu10^Nt}mK~HZxuEW>7HasRFvx7epN|!40eKk!qj) zWv?omK?^pIw4aj51THR&64Ixi$QvY<{pY}+M-Qi<>SD3SL^A>Bt9d*Q0wYcFo;ZOH z!iCRK?7G(_&AKl*Ono8)c(!H%Pbri3*I{#GrDowrE1(&^(X2p9^iPfg+s$O#qQhT4(5V6*ACtZ%#te;jHlg8Tpv{$Qf2^{1XS*(eg zi$%Ap-$0uz{kuQ}*FrCrBmexHpOJ|b#Msp>vE{e%3vvC1zK z6#BxKQ?4X*N;6MOz3UdN`$d(lrbPT_dC0QjJ~Jn3s0TP&CR%2olZq#UXvg$}{8NyX z4y7vJx3Vd~zc794>be602UxWKfVGe(z{(wUchDOGVD@?5N3vB9NMl`oz4nU!jrZ3X zj-=Ucd#f@Q92MKzDWSnR26rABzYz6P$CFiO!1zFxFMkXbR5pIfc-dZOK?TPZ;1TpE z_MsB%=%>@PasIj+w^;@-yD0$SaH?%OjX_ra)P!isvym7$-~F;6IZm1v63)OAoM?8U*5_Nk1ep+zEzOUc;i7(q zEV5dmnAz=9IP6oNIwLf~=tLk!S_DGsKC&G0h!8b7L@zii^!(JshV5^R_%XhQsp*iqiWGl5`;7o;&@801e*R3j7W^AVw3M z{$hDcc9Z%2jv&izY?z`f`6pcYHs3FB!F$oOJh=9%^jmC}|JYZ~**3=Xrp|S?bpJt~qG% zJaBeb-QETH@shpUG(bXIr|l|R0pUogqKKOZG=4EH{QZ|~Zn zw(VSoP+ts>-bfsaHEf7Uw0%ac951gp)1f*V4wbBuCF-3PHQW;ngr-|jRNiY;+rqq` z>Df^XsNFVL7PA*f#u->Z&B4_skN7Cj&!I2siV8# zw~hh&{M)3^xQ9c`5pYV#wY`nmoeS(JB1*0~(Rz!4i{O7$S1L1lfaiiOL8MCe!)RUG zc@foPDsG)YCy%BVXTD0hAF3TssV%KZ?LL>9E6H>*9+-_vJ~ZyJUvGH2Hc>EH_FTlX zq-~{c$H4vYtF9fg1T`sjY~+4Of?6eU4~s$pPvl5v2+9QD%?$zEUZUP{zMtoy$NP9= zdpA>ZD?4d&3N?^?>hJFgLrPCI7^<73y zkfm*KkgbM~gSwmkcJk4Z8FEc(KTT=@yt~B-vC8oRgE|DlEF5ys^oI2wt}zmI&)-UJ zDiES7B~mt1sTU8;!}|bQEXQszD|4L`o^5bC&Q%FQpqW~)eo?}5k}fnC!)$Zc;)dsV zBsBYd$~dB&MYr?@)}TaqavNG7q&I4@;n+&^u1CU{!;%+(SUo`9YRgtRuAP-wDMsxz zF&q~y?t=O!at*-S9ru1r0-&lj+}?{mAq;j5s3KNKsJQENIJ)9hDRG>}aFo?S!hovu zKBz31Oc0}UISN0|*NW(Km|tFVsaw?F-fch~G`N7@L9H>M`kW3ES3EM0gc!^Wsq`Hq zC5|Dh-A3*0ijA!iAFO~*X#wdfeK&O!KTA%vNg96m``lB5%OW&pg!W%aGmGs-PR|W#YOHrU^3a9r51yk5z z_yv*v;{(8{(f8UFuAAvRT6M1jKZB}HJ`k~Lg)=iq%_cZ3t!Wy#zK6bH9Cb8aFo{}0 z9Z4P7Np^dUtw&dWn?!+406z!t)X6reBVa^j;9tGBzG%Y28uq&EDxl9r0Zed7n<1cg z@SqMoHNMxtRW(mEdV@M(qp3p|C^sn5+elJ@s5OVkesqR-g;NO1;5W{>52T%m!J< zdG5z}?@?KsU-T!0d{rUt+zUo-7Lp%n67m5NXCIkMfLi|7m~S%ApnC5t(^PuAG~Fv6 zZ}QJdP+gJG=B*U@&}JvMM8iu>`&-#ifspY&PE+gPy=uSLLLhgz2PjhM#57i1=w1M4 zfYyXO-J@)Z2`!xRE^ z?)x)@gVRW&(bncJx`M8A+n4o)DDEA6KXqEL&Dmi!lAD)l_ahY<_PyQe&Umu6Ed~*I zK}cjqP^~N$&qzQ}TA_>hfaCwquWSw>*WSEpf~xlrEH|X?2NjLLLN>rp?T!i_;-ly1 zFk~`})F}|=73d|54Rw<3o}MZKRdFnUZU<%Im&KK_lDE_EgR(`9g12vegbx%S5XAdy z-@?g~x%F6>n+6Bnf2aQx;ngdD*BqA+hcQL<1L)SC5&hY%ZO{kqY|Hh^9)uZ8j7d3b zi|eFNwfi!?0FC8%^YJF_%hwDR&#>_CF_QLcQQYA=7cntdhW|kOsm@jbyDqxJ%dYs; z1UjujB^&)+ppUTP`-ud1f{hg2I~5vJWLlR7KoUHiw^@y^(5;?V;a9Z=nHt|QP2IpP zgZjR;#y9q_>*5QBK=YV#5p?9n;%=z5a@P?&AA9Dj768!KqA~z|4NP29g83=6EZ8V0 zuu-6SDI_=+b6&a{K*Ash(5$&5hrbwi(cHRj9ya6kqn&XAxwE?qUvj(Fr#oO_YJeDa zTMvZi%NNYX!C7702F_;FuZ4zo&MRa2l-?#-kHNZp_m`$^HMo*OV~s1Y;7ejZ`oP;- zWdI%E(OmVt_)HX6huZJGJZQ*R9o$vo$GQnfaR8_|R%LG#qtN|Aej-k?skx4`AX7QE z-=0N63X2sV8~5Es(*DadV7*<~{-fT6?u;r~d?V4JOf+f@;U$sSj2NnR$aLcSnPE(J zU` z*{eL-1G*?0KK&%LBOAH4D7lb6Wg5 zbl`^23*hX%70wh2+S*A98hPwZR-EWICnmkC-E53>hw08A^sZnJrW(|*j)`OT!|7CjE7g7&_c4QQd=tf*^gE%6 zV$2MOan%CqQk#XTYge3rbJMl`6$tg`jC-YoE8)>6-LFUjjEwBSRT$$N6(;D# zMMEgkIEjXtJje?c%sh^A2^VD@KdD0kcAC;*-R?y2izLnr?a6BlhEnFPt?{N2#f#3d zia#!pnhRlnemWa0tx&w%E>hv_afA#C1QigL%Nj+gXjF93%L>-3gQ;x(vNWDx<=3ts zE8H6gD2|zB*ot6b-FDpGM-s0GpsAr*C5qtPAp(cTV~fW)_^fgt;99J{G$ot(TAXKd-AW1pp+Y7N$T>q`x`#Gh>$-MlAIB@t6p|T~=T+pSeJ0|9ZTZ%k>)YurC0ncbrh+ zTPRws%+2%wX1y~f{R~~emF~B+q0W-AQVMQ1fWUa4$3fzcT(@({5GAS&s*+!Wnvz(! zHK4CK{XJI=3zS^HuH0X}QY(3R^)ytLZ6W}NQno}iNe?}x96^daDO~R0 z^wLQ*xka^?RrxZhG~MM7P1))Y>=Nimy<5Tud>3h7P{Yw?OOJSz{px0X54vNS01#IH z+-3z&N+wkoyuPXm7%EuUY#Jvv3RYU&dzrJUTk>G39p+zIcM)tVX+~lw zG_eeyw!ep^F0Tse>gzbC$m*d$;bi2!;OC%4tf!Z5im{WjF^AB8jOd!m z8NXS|IZZZELm`+jC?^d?CO(x0;PkEY_)+HyoxXqS>Bi&v;6p2rauS!-$d0H#MD!%c zCw{LWRNedg3YH(G-i9Is(#vSL!S)M;(pVr7x>Oz`PmL~>%LOv#M5qU3wfjF%!r)mI z)BWy3<9s0UMdO#(aHJaLZ$Qu?$$#wzqT_`3Q;)Af9sEHB3=hUqmKcs?2JF59H^Hb- zXj%lK4TgO%ph?ti^c{Nm3J<$hx;C?th{V6hO zx?U+zbcYT#D>3gWbbLnxcqEp$^WZnZBrbH_TcVrL2_bypiO$yPZo`3(%!;{EE2M^b z3Sei@fzK+zgC)7pM)uybO#j+KgYe-2uh9Ie_XfEwt#R~`O0VccyN%zS5)iRe`ZgDNO&VMtjJ9YHEn&X)y=rr%w>#|JPN zh~qo?MC%a63YZXIB(;0f%9X$(bc7@KZxIgiFcOWfFem-+E%$n{0Rz)$NVd@3VwXTG z-pkb6m~%i{|8M7j>y1G4mTzSDDW(!2OqN#j1K2J~?y3m%Iar0OOG&!WTk?!Kksci? zGAN#cc5*6UGeMaCth%YtDkx@Ob+_;%Ljyeh@ZS-hcM8nW!>_=_oHeqF!hmpvg6p^+2Z-OJ^Dy7#r!KDi6gURi1~W*n`+dX-LeW zRIzc>3)(;_*RhNWPqnytf>a`7Ou1!@=_gnaGE!`(I^5dI`$g(v#L=w>MR^TV) zj3%vyy7ex5|8L+*n>8Z&nb|Z&`>OHkpZxl8{awifGWzgXAce0 zVL0C47P&Ot!ZguJ7v`xrb`a|Tdjso3?fx$fUUfQ9oUAx2>@X9e6I5k7c)O7dnmP*R z6p?5uOX^l;oLw6dd+voxS1-#;LzTCna^l5zV0qp(KVYCmTig}Fq(CY#3LOqps0&le zD^-$9(HznKGI~^tyhW6lZk>AC)ypbaPM1Q7+2wDbT}Uu4OCw;SDnv*tOzJBXvwk}l z@k9hii_##Bw)+Xj>&$)q7q9cv-sG-?{zvEj54QtiWw75|gwry(f!iJ64~7FVz@L0v zusrHbfs9WFnVvB-H7jClLGkksW5^a1{IGxzB?_h4Li;LPS}zPT#jDl+W}s-ZzLcy~ z0$`NDw}r${Xn|Stk>y-U z!x#iOsXVPjUtKZCsMm{Z-_wX$Uy(3Kj<9*KX`ds5vw9R(&(QFhv{M9H5sdg*qjS!m z99!uWeqiSB`&`AyKxyZ;jGp_VC$}vcO`;QWIdITpkcqPZ!a$jMGk9*QcRcu#bD!>q zO6e!i*AW0Y)-||+d%g%rY0TtfaW_GN*`*>hYTR@1>89kPqu$d3quR-0E(HKe_3pg! zO};VR3hUz8l~EWxXbof+$!dbbm3Eajt4lC6u5vRSH0F2^CNL+<9 zAhO0UKhL)|g!Y9F0Y^%@$KXexUiBXFXEm04kTj+sP$IdgmSi2{H4qT}3IZDOj9xTs z3umZwhEz}*V?3+@qP=&${JJyii+LHPwp+I$eGRCIwLb|U5|UTsq}(>m+3CrDESEfX z(U7pBy6s99#48WEVVOwuF2DEF3zx^#l2HNMqw~5Fdi4gB90ZeIzsGct)dX}n_=D?! z%%6<+2mMH;9upW}J5aJ&bQ=@lbR-ZZKrT7-9j-uXC|+ufaemi=4*^y2n_Fa6J@{KE zoy$ny7FXqBIO+i6CAiMe_80{WBg;W_3R^1auvFOvWwDqpfS9wiIRTN`F|BC_E%)d3 zB!2nlJ!Y$`gRPdMA^c$#_}V4&xEP5>E`zEZoP3gB!sd~Ta_zIQM3g(v>^~#ond2JmmUQs^{sEgap|nSDAg}a*kcYh8 z)w$L1Y38jioUh@%8PC@L?bVKb8~4uID=*Fm-`a{aNle>l z!vZuqdPAl5PjB?C;B>otrgm_^ECUW#kIxRZ>CM>?dPJ4BU#4r{0WhxZQzq67E_PwH zUzG1}WKT%JM9jyWA~o%fX+<73;>sKZ^m<){B=%}5a%S$s_dv<2=8;;<70bc97J-ZR zM7;+61+}(>ye5T2 zC&KK$cf|{-u@(%4!(y6JB*m4f2XfBGjSf}Wr=8>Hs(?gN?eJGaWyz)FPFkF^N6xfy z`pj{kZY~9RKaI^;ZFN-4idBQ9`~7CSFBJia<7#?T65;!kO(aqyu3|U04>9G5rrjS0 zA8|o|XQjs?fKi8`x#6c20GP6?AuB};rI$|Q4_-$fpG5k4rMtACZ13sUR2Md?ZJMN? z;bHE)1N9>ImR%aGG?RKoAYS82;jFf?7yt7x7~jA$=SGS3h_=T19_S}H)>%Ag4LLs} z!>}JAfn+%T!LSsz$bYa8RDoQYPaH@A_17L+oDpr4By9FbF~DP|73*3a10d826@*XZ zBPrMQbcyaL3wZ_cR|#ND@;MmGacw zAFF4-W_F;n>R{&7qfa8_Cv=>o%USGI6B@S53u8gYKP$kg;*{Q%<-5(p`o+yhF&fHS z!SR!|^BM8h27}25U3z?+%PX%pSb(6>!D-Kt`zk|+qkzVzwDk$ry}!lM&gnkTRyQvz zIlsofgGlr0IEpQl)A?wBv;}w3aH)bPhOeoLE(cHq^Un+}p|dyl|IXe{Pq-}%X1D5J zRF;~v;Jd!hgi>nQRMIc3fK9zpI<DQnUIPY~j|u z{s6NCsEsq~v6X9B9#7vNASgX$G$cd@TJ0`?Rxnd_D}4${bzLbXU|M0XzfC_{=~;** zfcaIYo;M<|*tC@1i9GLOhj01ZbVr}J#ZHg0Z+pa{XWC26rpjGms!r!B(1cou(*#nc zPM?zi47l%yS<9Vq21B0?EJ^t!yKg)JXweG0^;{}QAmYf- zW35F$?~|Irh;jUArO`l!$_YUD5DFL$_(VnUz-u~fF=jopzMb>Lr;2f>XqWs=UG*Q^ zcs13{oQ%6P9b(}JMq`Qu43mkDJ|rBJ7M(>(Ngz90*O$gd=cpWhxKtT6P_Tt)Fp7KF~AE7)czO);f@INX)O~ly{AO`}VHXxS!0yq$6tC;i)0&i>J=mlB>?C`G_& z9QXOL%+bhYu^qSnV%Ts_3@&vPZtCDhj(tBl})fmt;P|H1+c@~k?hk&rkA*83?u00JWr<4wc9 zOKRUDBf?Bd``%h!D(v-FPw^@6VuFAIr#4${6muQmFz+`D1Y7QVQw~WsmmgS{$FoQU zABMTqHYETgu!bzGji+w&4yWpYO;Rguo{1Tat2V@|F?gct#B^P*@uj3|M{wyxxas?O z)9V#uslir3;bwmN89;X`FEE4p#i$-ND-fPik37>gVs!T$g5PQfV=+@%ybs^8|yQ47#FKp(^Ma{xFU z^?8k!g&W8168^;-**cmgogK`zV>N4CU)6mh8Y>mwjA*q0_ z_}ViF>W)NhHv2@)6@X~QJqAJ6FCo637Kb{(<^u#r{k}LPU#;>m5X;)IKiEnE%E$4y zUdxPa-RMbzbu@CIpq6^#?Dy=^+Ks0#-M4iMq~;~Wu1Z(;Zl=S;c?uuAns#%ds2LB5Oy?eZ zJp+;YT=OHQJifhVL33DJm z5oU7nFylC*Zru{(SToZP9TRQg@uk$`o2AQT*!tV&=d4EnAJV~&V$CTYutM8L#WxIQ z6$D>5z$TuzIBkoju}y#qwu516^r&Ou_=~5n@wUtmy`7`dS6060GuhmpHd^A|(L80w ziw*KP8cmr$1b(hPw&&)!eRo2Ke3+4TpJ_%iK zY8Tof?6=SFiyDO;-Ph9=WPLJk*Hd`BP?%%nAmp*(ns~CD_87hcR_04GJ zZv>T&uf8q$2RRfqXVp3`SqQQn&`=~vv=94z^7JGgoz66|UVhcJ(Jj_vyC8#_)b`1% zno)_ucWu!0iae93#;3BmKpQvx#4NvLcDk!%wNs!+*mz^sjPao5ggp}V?$U7Efm{xN z@*%vFd(C;}?YoR<8cr!aZ@S7*%q2n}jpwOWsFcRrK)g2WSC!F_w%mWz+r|vcDxKlO zDO^HQkhNhEWq9I4)gC%&xKfHWoz}=5#{vbXn3}$gC(9*52F&d}Ts1us>tZGlPxZX4 zL4CAm7g586U)aWmdu>8Q@?FRI>Ym2Fb)g!g@fC3w=eAM*XhWMu*S?K6o0E}G9vTjs zN&!ye*0vdg6mf?EpWL;bKKaO}fS<$|aS_Af${509>7n_1`S+4;z>%CDrl~TT1 z;2=l4p076x{FvJ$ZD4)8=ft(?q0?XzJ{0S_)ENcHaBf~wS-Qv82Fq5rcg0Fp zs7MH$xQKS#ufIV~9=#jf-kHAQJ>;>O#(=a`g`H_=?xTSchB+V^meq4_m<7PJm{I{w58ITXLQm z2zqr8{~;w$ddnZnP*Odh9(`|3*B)f$!chTqcq4&usu$k!D>kJi)fRDw#2te^t{>v| zqbs#uuxC5*Kr(+ld(_LTm}|tlAqLG8>&;CrVW9j1Vf{J*bluKe&6hpdgM31VR`L*( zlo9;+~$_c`Ld7&B(c0Sjs`A z-a`AJFYTs7a&`B9OUYvtRT7$5ao+gIL{8wqw1~>6PF~G_@|vAF4eg zj2yW?e5U|CAy5vy`ImCwjY66DW`UmXhJYLC9P3WEq9|v#@)HGXw7wH+=h5V`U79Qa zgzu|TZ{n;=0?-maz#@5DjcpaUIC**wnZ(?Rhm@`$$|vCQjk-NJ!%7Xj)T#a+EAqc5 zjDIE4QNzcNj}DM&q^`_jcG^{CXVCa&pnhN0Hg~UTuk)?bP9xuJ@K6=&w{ z^&50IvT-M}f-!(b`5?)W`FtY$s{@LU1ZVGqiBY$It$LB9#WW}qT>FFjQ*F5Mlj`|IW# z)u0GZ;KyhB-~77BU6x2lNrD!^<_%b+ci?DxA!swOPQHzizFaFhsObR+>`$PItS+eaX3e_!P+YA<3Mr;?byzug?fsc?X#yZZL)*exhQsem~|b zNdDn1jo1BuCXxSUm;Q;Jf?2v>h@bzeNkW_JMddCZ(O>X8K!ELS&iya@hfptYYpcLd z0s_tHH(shs4-9iv%;J8S+KLxVvY{qJEv zc&O1g{G$ehGaes;S1d>{W_q~&U zh>P?sZdGNt<;uj8wQPjQ|-_*?5M@8OANfN~GI zp;wt7B@`Ks?xaP^DB8RuKF&>~*~r*ipxo@NnDOh~K!$0fdkgfl& zix+IZ%;vQdHMBSY#L*uR-wbkySor2-S?(7&CmI6tHI7&BhDeVJ83oCm^%IEp$5Vgt z={Xvn`^g@cL2}`HgX|x_5DszdFcgmzxs+x5yg(Flh0b0R3I07`q55Qus%-2YHed5~&1QO%?c~Gh^QS4jn3;>7Oe>Z?Y6(Ix^FTA5&;3C7la$q)V~e&1EF^DmE8Ho}@pn_y4}hE9p2F0f}ota^M0ZAMx-V$f*b zRFVAFD}~xj&V2+|Xa_%ftK2afbF7C(?x#odHHVQ3r$NFuoU!+&(4(cBW`LvyNTAx-iZpwP_A8e|A`wYocHX>IYR3Mi9%L|Obc&g8vAz;EC^L^7Dtah$ z(=ke#HMJVtg}`}fBieuCiCtVvJqTU_j>RgE?&VG>tx#NMvKIo}-2yNjJBXEeY9f2l za7l1R+ryQGTjU#~5$}6CWBI!J-z%MIQNu}$c{fY2PsCI80aFgw({Wbao1S)EuAZH# z=yJVd3pB4^+Jr}!UC}OS9^-%eQxbi-3)f&@)uumlPSKZQ|Ix5Ro;#q?3u`x5Ae{&V zq@d=_VEuU~J?KNx5*;_`4ykTMiS)Gh<x0Cz6QwnTwN5w;%fd3SRdL<+N&u zrvm6+O^fW)+~u@m?~)nb_X{J;H3O(n-J$y zjZa_W;O=yXYA6Z*ZTD`tvkL1zGKAFV&j-7y>zQtkoFD!NEAHUY}ewKB;;l?pP(>vyXg* zv!Lo7OM$CJB@9=exgguN);Q6u%%b%OQZU!1OiE0h9qrjbM0e^9EV&yD*PaGs!MjyC z>%Z+la5RW%;{!M?@H8SWHAOX1wU|_T5+9#$J=AtPjUpXYv;*3HpQnQSv6&? zZIP}#I__ItlDU^%%Om}gOzU55w|9q_w`C&>m6vTKG6SnjQ{yUAhl&7nO5jKL9B?_~ zWul;NY9=B|a0hWaG$}jdOy^wWnVR}_++t8^Fl{}sF_-6?0($O9Yw_sW-~v=_g^2w6 zsGYWOA{g zgP+6U=S0@m1U3_Rj;Mq_jm}xJ3fqqy?5tESPe%d1%`If=!$|}*=m^R?#c-;IoRL3!}?kk%Z%SdZ}wSvC|uph zP<_qY^QpMXSx9z(0p^;+L{AE@c=;vKmK-x&i37&C?eBZ`gK4Y3vML$hh&ccYRs zOvB?XD{p#@V}3AGs&0*{*BJeg??xV)%CHD&Il;Ah6;-e$c6HmS|$z zaO5m@9DQ!cDcnfzkg8Y(hQ}Y{2~NVrBS%D>;Zpj=nj#-mm2<$#r6 zPCZ|I^z(sm7|782_1xy)A2Z453AJAc1-K0Un;*`>FUV;}>hGMoFLz8&S!@#~sdLH~ zLTJp9{uOWW(Hn*T(p5iR5V~-o7jVRjYv;pXSAv{`WUmPi_YUjh={K5jh2BSt92xY= z-2h4!284Yz-6ll9^`BjMlB?JoAf1qr_zDVV6x-UyBixU4g-H`qZlo;7^IpEb?}THI zjBydujY1!bcL>=z!7_2*cw_+D>Lwz>ni|l${1F8)+Tgs3T?8tGvDY3|F$|SV>PKz_ zeajd<5!XR4u<#H7dG%bZ)jH6}5dF1>rq4uo3zgzy1IjL30ELWkc}T*#>uiL$L;jIV zR$c@1?73o_dO{0%D3;0`+OX=@ff}%u#6qq+S&YyfcgoNeFgS7r5_0JDQQ~_u ztu)=Ci;v(n5_=J0kUQ3gQi9Iu1Y^qY;X>00k-_Ak5pGFnKU#0QEX4vnx{-Wcha1GJ zi=%=wsXTZARomm0eUP5f1;CXhezT=HRm)sqe=pTj{T&GQk&9ojjai{hg`GaQKnmV; z+UD#=M9iN)k{Ac!9nikd`NV*1SU9J*{t_rdEN*WtU|o9!A>pv@SUTZ@*H4YT zBU8cAjt!)-N{WY#Y>+WIIww*XXmjDdx#4RqN@DPy26WQ$X!?S*Vm>i8IHtxbu9A5E z`zHoo!^U|!BkIcxPkIOKkT3L)C(fi0AB%ke1e`N<0sPxNfM1U8qk}qhf6CoRv`~%q zA0c`ZfP1Q8UIbZm2(FHL3ZQaG0>|8Vw7=JAB4iW+t4sD_gaH~?W}i@= z87?{)Mm>R$dK9?$A~wwx*k%!dISP3NW1CGG;d9{9AhUwAmz{00(a>BQ-^OAfXtTS5 z|6n<$8uA`Ab$=wU5Q96j-~*-PJLsy}%gHQ_j{d4s3ha*JcQ5qh7P)}qaY!DXl}2oyR^;Tzq;Hl_&U&XKKpZhX>?+g>$b4XaYxl{nP-U} zuim;$nxH_;+AUGoeHl}7$o)SzOSu-H>PlX}smFgLMKJhqBJLzVH}|ZA!go`%Dt)mX z7$kk|w;f2va{A>VNM&Px>1&%J$}FloU_)WJqRDM*Qs639!EJGM1G95zeU8xk|K$<@ z{r?9cuv1N?j$Fvay_f6puE>(n>eTmDY82+wct3#{&9aWDaz;X67<;}{=vr8CwGtxs zu|ZhU``K=&_#+yB+a{W+o9ctPFU{RCUEs^ zmqZ;@_*%u!j;QHH1vD?{euR%+%QhOJz)P{ ziFuL#FNcLY4VFVgCpuQ0`}ZBZg*KYSdF_|(Xg!N&`>#oo3%A7{fq4jo>AXgtvULA_ zQUXmw%uxqtMV1$9DEX}y3xfyuBN z5S?HmgUo9a#6dLoA9~I8GC{73mVYmm0RgalLXd9*m>Yhurz+b(Wy{9qQxf_Xxx{=) zaEDxC^)DRVLkJ5fXg6lv18#kQrE2<`^f(>WlnxrtCY`W9lK0NJV}`0D=LY*FT^5ML z{It8fIVK9#P&mi5)%LZS84Bm}vCo<_gV$-i_ptksD*$3RJL4gl@BG37>_SAZ(^qsW zI*;R`{()Ksz0;NrWoah11MKZc-CNN}C3$$ckO4^~i@+tD^dmP=YCJN4`= zdG<)`P4U`$u73X*sX+C^3tZ8Ak3H$>gmMGW>c}O&AbdNVV-k|K`f^`W|2~mhv%o~n z0bfoY*=ScbxU2dexHHJT9B}DGeJzAOO>tfTmQ#qT2RZhBf&(WURMZ}NdL;wJr8gtO z;1*_mq*C|Rj7s@uT3eGoX2d<*82+HteUCgL1ev9Xaa-lX36XfF!@#MR#RegQT07p<9_xvU!!AOPI>(4Wat+maQ{#Cc)s&^wKFFiT);=2 zuOW1Dm#e`A+!d#wr`9i{$5H^3N^7Sn<|r6FlQW}Il=0MAsN2}(rTD;ipq-FAW%_nx zgxsFnJ0{*z)p2FKq2YK1oI0VlImMy1d3$~L%b1dZ;7CEvy)j{HqMLd#LRLh9TEj)< z&L`9L90Lba57zy!+69?ubJ!MGS1XSYeg&5Smn-sAurufhauiHI8}+DN=x7SXlpC<+KvFp z-oaFR`EcxnTN6-&yHjY~0T+)ujx(g1zpU9>tiPk{(N@m1O95_qVGBJ zTQ!K8%yK1iR@Ix(1V%CW?eW`7EPfs@O(K-Enyzu}Td4@^aer53O_V(17FH#%=i;sL zhHrx39_bv4^DcvPskRuZOylG1p(bQpMijz)dyATrv8*d&DJc)UtG!bZyupCAOBGc^_!p z=P*PIBE{e;4eP6Xd&?Epx2DD5rL!cn8auNZ1T3oHj3MqICKt(^(sLMw^#CZKTYTj( zB~R|?x}_~qveU@a!G`VYHy^^NC&>awlRb{gMG8V~#P2+{l<~3o(P7S1Fs#gIoq4ub zP%57;VSqe^*kUh(60Z6f7QiIHV9DxjWlNj9Rrc7msK1PRtP7c=(x7^J1PCHHxmgpD zEc%c3NXvKLdT>WiEvcysFG9r~(cqqva?riC)&@v+pF;5Brt>UajoOZvb}$n^eLtOn z>@G{Qlay&mF;^LT^w(}Jw>qK#QAfi&oSma`UK?WYRQ{(aLqxdwgCb=a7wn=wOck7q zS0{gSAE)>rs<1(@t-QFry>7)`9sJ7p?9=E&=vR1@$WPF`2ESs>*=ZECIAdohq*(&X zgn7tv+vO(;X1X4Oo%+%e6#m~>A5EY1tpICc^YY<1>(xT3^7qr2Z8h8)?s)+RvfQ@V zTTjokpx0|P1HE2}Gjubf*Wl}45f*95(`vF?Ku=NEb54dKC&~MGZy|pC(A25_7Q4mh zBRp(;X~wtGnn$(LhYz!c_Xrg_mfU(K>xK?(S*OogY z=Gc!!)Q>>Zy-M_OwJ8_e3Xvl^^VTQ_zz-Sh^ZkS9a2ZMcr5C(1&y=WKu(2+mG{W<3 z1|RVfo20R>V$TA33Y**L)nKao?$wp(>gdX^s{*Y z2V91~=}ZspQ~@tnv*IAG)q{R=NXVA#i1kKCA zfr}&OOb){c7z@NsjdlDe3)QlMD=EBq^^SOy>ck%=FdIHz{q8tNKr|)Hquo* z_6+9R>UxXg3NGp4imQ$&?^3ferkEOA|GAQQ|ix(X+%7z!Z9m zuBPyhS^8thX66Vtwi0MmT2Al7G8XAjPmh*=21_qUeg!i;thG0pN#{E#WQ342YK(hhb=KsPI6m~r=favic7d}e z|5&R#qcf%>X0us*WYN|F<_g^HgOh!rMT@erHkuA+z{e#AwQiiL)tsC%@WFV4WxxaL z)DP4){qvKW%)^_X1uKfz+emP6zzUtfej+?kQzh~t;QkKV^WRHqbTAMW3^ojw?;ZTI z`6wG}rOyp^_8Il(?=pfL=l{zX{`tu}X(s37^mc4s&3?M+{>TFPWa?@7Pi)?u_Qy*FCkU+3{w+x|aCOXYT{`qSbgeQ& zB`c(mRgeXf2FfuyF<4DDgxcgCuAT6e#sRADJ{P)AbOptq@X&HHy!Ow}Y$+PYOAfUP zY8>zSN;6_NJ26TV-_)ZL!rLucs5kz-M?HU=!EHicLC=y<8;-pl?rvZMgj4=iJVoX+ zH@*T#l30!FPD$!CSD*4fJgI6~miI1jv0i2U!k)PrSH6DOg%|u6!Gnl@co4F@H=od> zf^QoL!x8|E@pxXXTzu%!M9bSDwFI~E>>S7N8b@do;l60gBmHN~1M6~UJj8-3l)y@( zK;?DnDkEfnn!>~zKkf!BE8%X~##*^rAu>`r+@pC z@ZScY$kdymR#D8&hN^Fg1*`8{3obUL?9%%LMJaqS4|;GQPqe9G=XQ4sz{08zeDTC5 z`uqDwmW+~#Cc>$J*<<5(UVIELO44u{b&4TWU!u>ap-9uf&FZ_R7r3awhd-H(3!Rz7 zofZVQ1Ij$sl9GL#!@$>`Z~4>LYU#X8&uq=H6a{@r`$SvkGv7)f&wYm4ggyIifa+B~ z1$i8VNJ05P2KjGy*3A4MJ6t=6jdHwxuh@~V6<=4QAe7?W+*S1K@`vC&%OpNY@sjj8 zzWHnwIH8n(+Y@Q9&wEKzj%Y29wE=fvv|}+<&v79q2*3X6IsG%y(=~_B6%54M%AIx0 z|GcEp8qD+A#W_LA#E`@G8y!xChJx$fmM2dmmM6SU{rTrm=D&yPy@|7V@8Etp^nTpU z<&ifi=w3i)L(mI#>D9qhA7-*gq}a#{aIh_3{$7=R1)n6#hMYljZQw4qGxLw|%c0oC ztJUPD0$qCnLthVjO5&srY>(x*k@-)%@k75NtAv2Y{eity`M^cTQmYS1(1W%gE{WYr z6m@(Sd;J=DZ?`=NQQmwzE}O&z50uzSo}G8Nig&lW!r#a9%6}_)Vv|lP7l7XV?;cW+ ziaT9OQShUdm4+q+@!-*Kf2W1ZwZ*Gc+&mGSJa$%EZ>PSQjx`JN8N@f}H%SK{_D(a% zuA^7&M)2=%dqh@LMt(~z^#1)rM_|^YOiN?L@1cjro?UxI?R51HexrgsW+>@D9Hb<9 zN+zOkVPfJ@c~Q{=sorH~Sv{Awng$k&_~fqz4e8d#@^sdNzL)yRFyGhz`}Sd=`ZdKb`@UCC&AZYRJ1C>=8A| z+!}MC4Y+B({>!+MMh5ED><0!^!VY%4bOwmpPwgzI54m;r6|1{IAcYmqh4?lW!_+ zF=;|HkG3qbi$8Q z5TM3k7nn8)P_MC;fN%H(+*MxN3D2(_(@6x}f{w9<^>)r&pd}ho=e<2-rb!MbU{5IO z+yUv3W<#a>&hkRdVnOaUa+r$y_yLwMc#&rWTJv=uUv7TG7SPeqYjz5sbvMhlfDSq{ zUlK>gg{!@dB$tri9KjTlkhXEI|YT)oI39g*#frMHhbGA#dRQ$wCJq{lCB)*fgN%CC5;Mj$wLC7 zu=&yz?P^HXXe+w1_Wdy!Yh2=Dji;-_1>6@34-As$U%h;FMUWL)N4Vs^Ik)t*Fj=e08rN`1%gpA0 zT4AMK$K}F88%dB;)&Mp7}`jt=1kvHkHPaXqWsQiRZ^C5tg-9@>NwO3y84txHA6kluJr4ez5 zOD0P~M4ky);WPX1s%R^GobY)dllU_kpR_6FO|w^p?du*kz0kQJq!~NM^=2B$%FqY0Sni3cD{ z1_z`-KB5L0=Bq0g4Pv+y=j-&ZJ>=Q|$={69J!v1bXJDLuCzDPr7Zd*d9L6(Ha6FAw zJ_{eHUld;y>!q=mP_N zep1X1?Q%1?5H+FG8oPy6GIL1rH&gR5D1lN!Y1ZgaEJuMVMenCDi6FdbP6 zvGR-hvtYb(bd^A{UWhBVk;4EXe51{obL{_V@6E%h?B2g&q>u^`DYDHE~wI$u(`~E)9?~mtrpZ7hE`~K%X zs(oG8TI*cv96#r0rCw`We3NjhkcEbnvWd4|JND!Kw+sP1U)fvE<}jPxP~iXX3fgs9 zNei(8Hr|&1`DAdeKQ_4lC!D^7-BGhkqGnm@)5?8hxYS z?h?nGoGxZE+MSHPP5B;Yf96zt0l>B0ff$+1U2cLLTl%&m&EDQdDniMj$a?Ju)}9o$ z8Mgm2_v!YVS$!NYeJWJ^Ai5JHOL2EiFR~ZoP`n$awy8wCUj-=Wz)Dl!qom=7g|5Cw zT=r(YZEpoU^xn`CN~?|D`_|_ExcbCqWXr3Tfcn=*ges41=SSxP zzpQitm;f@R0haWJhUoE=Z?B*JT6A7Y)(6E!6eroXMXyGjnCLJP$75AYV{=riMv_;F z9DVC0J@Wd-@CvGL=(<{#_X`LgMuOs}J#?B~^Y+t9<+poQHHqw*E?N`-Mbo}*7~5a^ ziE5FIg6Q1KXWaZ>*jDNjLD$(K6yf4BdD8(g0lS0YOaSm=8BbM*+(rKO#08PZr{BD{ zx0Y)-X@;DcTl!2Bw@Ao`*9KEJ9M8#f80y;cKf4XyA_Yg zIlrvYjzo$34^TYBeC!S_yzLsKj>J=zb_9mivy=G7(8qO5(_2$xhi+HeiY}evmR8boFmJnuu53BfR12(Qg^8 zcErj8a1qM6R0A9G%a$BR8^_5SNuf!{p`=V5Fx;c5Gs$q{l{GNEnvKPJPB({^I2Kd! z27YxesFNAXo6m30b=D=Eb3TU$sH5dL#fBo^NX20z`qo%!x-Dn~S5NwcehBgvHSD0o z;1+Z~LM$#Mi+4KcU{ak*i7q<{H6&?+0)iQb>j7#y!bBwRXjIpHplI#R?2mhl8S|G_ zcIOgGrU@&X@3Ry4;uc>LNwY9*W~|(eJF(I#BR5}t5p>L(CD7YHy#koq#*xepqmkyc zSMn}U32Fq&Z(VU+-?8le80)3^si_X<(KbD5{Y(c>=-Hu5K#yfzd`RhgSpWuEAH=;a$38Ybcjm*>q} z(|L7q(R|Kbv%#u@Z**Un@5uX}yf=_nH>ni27k5v3@U_TzdmiaqfNekO%G&$kqG$gu ztnEd?j5}OT$#+JQ)dZUkgB2MFCRxI%w)EaBt=U=PIG5IBvI%WX(TFaSBau9~SDpmd zFV1n|U2c(l&P8jk1&z~*`0e-52G`{FB_6abf7e^Qz3nLcfcd`3sAab!>kYFw$qt&FA71aPe$sc~(3t_r3~@q5NuLkX0gV zYv6okL8`TQL43gs9n^W{s7r7X<>^egQ#Bg7!nc4CWsaM%JBIcj&e>Lj0Hq^9fU@ML^y2R<} zg-8(>W`Cp-HH0LvHWBJRQ6g1Y7~Da7?s?w~I8hOMw4_tYfRb<2;iFI%LKx zej#WXNGZ2GAVDHzuU+UlXrqxBI(#AYRLt-qT=AJA{r!1JaCtRJJETLMtK0{kS-A&? zX|881#7SKhzZVxDCcHmj^n`rYL&=ay+R^rQl3dEm<~y&$lCtaMW(=p`CeOV20-EysGggaDE_M=#_qn{ks9R~7T_=re*u*UM;Gc73HOxI524Zh5xb z(W0E?%1KA)JL1IM{qpE7=G10VTa8bBpe}yptgov1coD?0WkbxQ1y|bBu2~$10IqZt zKAb$%aoB5lu3zP8%f^usyexTDJ`@7tRfY1?m;0e!A~U@VnAflK9iy3k?QEI0tvW0H zDhl%-MfM;p?4Y-I4<{S*l<98%N?Pnv;eroHl{Gw6N1mLzG-2kAv>4xBtLtnS~&*mei+hBA%`v0j<|R3bt+uBm`s(sh6PwCG;a4=7{NzeA*0WSoFyqDCAXF=113LtDLZP*=uYR!PT)}g z5#jBe_SBXBNYF|`;e0~Nz1;7ei&;_Z4k6E(@8!Bqq}=laaXF_c7o4g0ux-!5FTWc0 zzaKt1h1i6q3Xy>C&1D10=+F$J$Pb*G3n-ionD20)e?8ZdYOcCecP`iI?%V_3CsnF3 z%=LjQa&Srb(lTPF7g6wD?)NrYSpceoJpq$-%foep-YX*=%Oer73QM0Ak~)B+WMx4_ zVa#hLcgVZLp-RAPtV-i)#So%HDO+5uh+RCsRPfliMrvjD-b$9&ifHUybwsQ)5OGcw zA{KY-e)YL#G1rl=`R>*CWVO#3O-x>@317SrmACvocG+rpNn!E5LgLC&9f;1%s}{od z`K3Cq=`^#k%Pr||yu2YIHS>adInJ&akmK{XG7(Y#&a^w@_aaQ?j>^u0JBc)04^L4| zg!vA*hc@P+=gz{rSz*)-V;=o7_)`l#yb5{&+PsF%j9+gzD{ey$D0%`^=@Cp^BgqjH zET2lrl#hS(e(jMv;#Rx{dghIqI%LWhsu+6^0NkTrTJMGZ7E($vsvla0eH+kj!jdH_ z9pG%Ct+)1(kf+X6He@nVr0)dPs^`R!+PhHeK0W*f)h#)2YFeQfOuaW*%hyKl?H4HF zyWg0|2Lh^ZNRVeSrv<`gpEcygPST{doG}-9X>5Wi#K*6}03m*Gm3tGgbLR%AT={U5 z{Zv+M#Dt;3(`tKMsjFQg}1z4=DyR?VDK^j5p}({VkHt zxhT1;PZ`br%=T{<)dzC?h91(}@fF~o>e)y#*!57YS{LF^ea}$Y+uq9(bR3NgGC&E^ zlf0_-5My1Yv@g$>e8EKrW#;Xq^QK()H(=l6<+|K3n)$6_D5}M^4lr+pU~V6&+ox0f z8eeIBiuS|c`;G!nP9QV|J`!r$M`gJ?<%{~k{T662*C^{lAgB|DDIX#GS-OWY^kEKH zkuxs$c{?G6SOL{l@7W09FGmrpv%wT*7kpX)KE1q)_R#NGRsSRS2EmNyk$GI7t0<+t zs0H)R67h?wQlv?iUr<4mf@nh5euLpA#f{Jr_VyD@JW>9t-Q-ZP6pUmq>1dX-f7CmW zG#O<*6E$D(6WZ(y6~o<;K}%H1XhG(W+&T%nsET~xcv!-bORzTEVDu~vRjeUVB7Q>- z7n3_b;E|A|v=2iB>89ip)9}nRcrz-clX!}3KKgh|I7vtL9=nlla~xdJn(OkQlL`i3 zbcw7Dd(jC^WGAnp@r9#`7(a-hDcL9pPD_RvV(BZ@=YlgI>Z(77!57SX@k|L_7}PXi0TA9&NUzM3T1? zHGZqTy*}owzD)1i2vpsJ;9FyJarrx#DGgOUll$3*8+);$o3PRLZd(cX3_6>UTdKj; z;57mE3AsN{5$nv;DwQAbLo!%9 z@>AG@ToCTEYs+ZkkU&*;@Oq&b;kQtIrHDs{6Rr(w*pu)B0M4r4>cCva9mpeLf zFg?KRZ1$cO)^LV7YftNuoQSzVQuvWiObHA6l(4!_!G}Q0Bbagx{avxo{A{{6T8kEH zXY8G5oNs7(v;7?<3`r3~>UIW-nYTgwDn12Gxxv$d?A=!wu(o-MA2s||-~5#K?h!N& zP0Ak_#+Mscb<0m>iyMw)WmDu`EiS%K>&E{2)8CWD?DJ)TJo6A$34WYRS&pdFZqYX`=y zMz~aFC@0Y%6W5Y2AGl0Ece`OO_CIxxn>j=EDTSs>tyXMG@|`#62Uo%XtkT-V_|^2K>1KEe zBjMYyq~Me{iy#m8BSBe+cY4j$VMWW(VmY6~&@}^@JQUaxGVgCC$DG3W;ugGp{U}ii zZ71n`SJ7r8lbo`CzAkA;-!|t2^VUrFk+y8nfUMu^W|g-m53%iV=(Em zr;X$H7vV?cWbj+?PN%QGXGRkHeXeMu6@#Kg&_0H-M0U+1@3mHLrfm=c_yLdJdAO-M zso=*=AuWIbs{Eu^tvY4HB&SH+E9=5JP1Tc?Q72+SZRt1Eu+a?##fLomqn&jw#(FwU z#mwZrnqTZ!Fg^#ad1G(5vC&HH6nw`>p=}u5sWQZSr`$_F>kpcW7Q+sf4+(PDhs9w+p&w^efNAa3MJVDnQu;`u&Z)%=oU z&|Ec(a+X0z;7HOr|DEH=W|{>1gvRv5)UZn$m|xVK6ra<6+BYdvG79wUd)niooji^; za^v8J;+Hva&+d?M?hnswmW<0CqeG@w+tT|ZvJ_CO-c-$SMfl>1@UEe^d#9{J6=;#Rw z$vd!E%w`@z9Jsqoe6tUaWwW+zd?`1830U=(j{6zBE9kM z6UoS89Cw|l;1!}@+?*aAfif?6+5)({SC?UBlvlX_&ce$qyHSkI9w7F491msw7xKT@j%6Xb!2B?xXe7=OHivb2pTPHV|r z*mdT!kyp)OB}+}E%9PYetF?3v+YCP0GpPk`T42qTIlA0h`qiT&$*^j3R*%aUy^GpR zhW78yZsB++Y1^U&WgyQf-PdjLsf&fXRf4cI6gyUknH#xBu}vEEgc`Gw6&Q^~hC@EK zyKGS4va4$JtKseU=g$^?zdx65I$KP2wULRsTxph>YA1oXFE&T!r0y^jJafjDLdB3G z^fn|OeMxC)AM9IMsOea&iO)VP@Fw8(jwd_@_m$6%w%`+_N76qJhFZ~G8+B#jur`08 zGWT_ob`t% zme^83;8yEHdMT3NE~GbwI_Y)ZW&m zr{!?zvB8Sri#AzHJL>SHaW$-90c#ZL$@6D!Aj=j)JhJ%R$n@lC^b2NO=fve#z4ryz zq=-^X_qO>)t&&Idm(r9nJ?ffgWC$VM;y05GJZ+cvKlcdF%_bA*u2d~~8&F5J&}W^> z|BR)TVX$V*QiHyV<7u>10r2__hF;RcI|*gFjocXTiN`mImrk8lVHM{oh%(57tL0>P zg4%b6xYo?qPC?NJYtFyi)x}}(p2BHQh#)e&nA<^>A{GHTkRo7utt?%W4bKQpJ%rcv&)@a_&QTC$U5dyevD)uDuk6&&yPLSZl~9fO)=US%W^p^%gNwH zRN*D|E@Pc2D5#E-8mqaa6>LbNBfuTtOVwlQl9_grZ2Gsd)TJG<@~6lS>Tpo_=P+6I z*PjNPczQpwy77x$IMP=WYNKcC zl<>Bz&Ne@6C8mvW^hW-r0H@Yh?M}9HQ6AGL?X1FQdK=;IGhRaNEf#>CQ(>167R(h0 z=Kur9AVpY(cdSF@-e(j!_+~~yk&_Fx_}!`nRW%v*oV+~eFL2i@8&^kSuB&k0@3sj1 zbr!$yDu%bdqa!3$y(fhzf}QN#&y@-a3t*|mPF>Gyn~CYoEh?Z9i{inx&!n42WnOyW z1k${$X_z}EuOa{Vq)uvbR+qniQ;qVMc!!vl!o;YbCuJ{L9l`syWy@E=$jG5QB9eUgRE!>$pllnOZc)ja#83Y#@boYjGs2f8# zVeG&{*g@LevK9FyNqts-JWk^K6t-z{6b;{`+EbdYNNt;rL8$s-Orm`}l#dnc<5F08 z?b!=T(lD1Dw$L$|%mfzn@xcjT0{m^cNJvA-_jvqxHz=O$s^-{q{@QV;rZ2EG3J;}YJlkQnjR0u zHRp5HABY5?Y;rf=sh~k~Vdm~oJr>#2&54&KZ`;6!a_&T){?lSl$70Mkc0&n>TMhF~fMHfpP+Znr-w#1n8xf zA(y0Rq3;dLp52F`xnM(oE%j|1-s~@e`X*8+zbCteimr>KNas03O&Li?+Ui^8 zg4IVlBn6>?LfU>5gL_7bDmM3T`i#>I>_54a0emb8@Uh+w6`q-H$$o;Ll;HXJ66fEA=#=)6854-h!X$4E9PJ{J`$LHgJfBCwTA)5 zKvM6)ZN3!{a!@Skbz{ri%aDH@W;a{CUW70o=+#TGH_sEiUku}~9I@$FmHx+lFnKVfX2!BZ}Bf)yr9w1#?ubt6e&JOet=$5B66iM+WD(qJJdcJ znJ+$mQd!NK2_B4jIbyVJ{KKonSH^xBsN_#hR6p4JP`dAIGQ}R3IA|o)oT}6A3Yu0hS$S;AcaZJhAz-* zlq;oN;#L?hp$BkEuG2_-DbCNxRn3l?>7DyWWv092NtEqyk6~6$=dIoGP!Rf3o}`!d za*x3!D9@Z*Z~=#%KQpHQ{@@1g1A*g*@(t9_$!UCGTC5N{&=Sg}AO;&u8a_}KUhwn9 zXf(ll+>J>joK?%u!<2yd8sLRbD-7-82OvWLV&Fa$Zb zY}*#n@W$^bdSpzo+wG!hST#5Aes!UGO3onz}MzX$xWXTejqVe#>b7mJ_MDKZY;EuHe+KwxUjcK~U$;Iis{iiSkEnZnYUdiZlb?!x>H^ zZ(6p@5F_6Njx>j&aW#2?&w2b)9h?3rhgEsYmEzs`A{Or8`XuaTFsT*VBd#6UV4M4# zalKDWYsRjQ0a1VYErT+k%fSYgcSZe?H{#~19Vej$o4j{sc zFD)%i>Bx?mJ~!OwQe)e40OvOXz_kXEYB&8XS(2J&G4EIIVI6v7X#%o8es$U)s&4 zWvQRcipya9xWM>bLB`K9?@Mj?)zy7PNASJUfAc*)#L$LGK$r#P|IYf7$ldvll3*r} zVeHJlS=%BvT%vw;hg>ag-UQ9^SDslomPF1Dt18BXAuIZ<0xfZvVV0lYet-n!{l#kx@HwY zC&sbIQGZt z>y=r6wId;8qyoICsrIFk=R_TrxO$-PW^H>c<2PhUf`!oI0=voL25D;gO_18WrRGy0 zH9VjEFyG0}a>V2KE8=e6g=Lj;rX_qN>4NOwhr>m)6jvE}wm`~fOB9JGwrL8&M?&nY zo1c}g@zN=j?g*l#0gJu~S#*+UcF+c&!REfK3K5q|viQ_8$3vWCqG6f?y!CAMsspe- zLE)2%{MO)Zy?OcfZ?CVzEh?ha;LhXd+vjxt^E>}Ke)2$X#f#^Q!RIM@3-P9{a)7W!2e9IS#VDfGL_T-%`)Kos3o(*3>dbR`2>}YaZ~C4xpV>S}D#CJN0(x zFBz;Ko%fI|M|#rw??YYJaV8O~+D23D?_Syco8VrgnOp?%7YUQjKke+guuYA)qTg3_ z)BjGI#(N>{_CNP0?`3VnDQKYMq`?uxxaVKt|113eizom8w))ecrcv>OQXOUkillsM z??WVI1vcSxZ^f?1I-*u19w9^*T?eO^4LUgSSKtL^>X&ZY$rDG^)LN_F=3g}Rf7cRR zdL%w;SOCx~e<-)6<%o?k*CE4y3v}C7Cf+NSt3ep=|0qscIniu`yn{c@>mM)wPtECF z;%L9*sxPI+<+6P|{fGSxRKGnyYqDUrXX4RrXrVk9B;UJWwua;?vgUe_?-bpcQ^C%|>_ zI^jlcR#R|^ij2MoF+3H%i^4G`wEn-tG31f`Ib~jGVAoRN-+=5z7_t|c)tjy$^V$iP zt#ix5;2{~wbf<#He^}S^UAs=RZdE{|(;$QJQ!cFwLJAVHWq4wFc;4$d(ZISQ=ZL9` zsFD{;rV1CU3boi)X3G;$j=WK(W3JX3;Jr>i0ko_OwUgH?3);zU+EX@#(>A|)hd;^x zcvR={GFagLPqul1SQ(GyPZVAsDZWAuQKxXmy|BDrD7LUl-rKw1+3S_QzJ6o^+nIol zhUI>qtW;8kQuE)ANs0{I7m)zi$27O*DkGg}AXR8YI1A|yz;&vHLa-HgggjJcI#;q_ zZz6ARR8KLm;V0=liKmaeBAakM#q?N5G9%+II-HZl`PYrC1gZlXTuBLo=L@|NX)Z(F8HRJfNH0k6cYi9Kp_SDJ7 zzz1M*bwh< znFV#=`TGypg_Qu!Ag(0Q0}1{uA>g}2IL_2aujil&uH=92PT$hseDHxM#GtyV@iizP zrFepD((O!T%J^0oZ4n0;)zWxc&5*Ui0Y@zlc#+YvKZb|X>I6BQuR;2(60(^=?%C;n zERc91gTxDMyrEN&zTAVos>p>jk7OFT)d=|}{BBlaNqg=1E5_NZmHQygG&s*PzDonV z_x>H^6v&rdcYvblK45KQVWAXJ{;J_=*xX6vlFl7Ce*qlbW8@BPShnrP4&Vb-aw;0{ zPqsM7S-bi`;6FbwaQsNTL^ddjU7)VEa$jO0mT2ovqv7trPFq8=%l}v;24v6$b#i|p zb}A6u15hfQ8%obzB|~*PRP)vNz_1MsWUpxnFRD)+NA)SqjY!I2@M8hp+f6rouyVer z;=)nOf!uGpDh%_9pwH?z9Eg2` z!VqJgKqT8cC=+|6OBDygbA=Pv+qnN?$!byT+CM)4uK%${9$iXB#UnliubL9Gec&vr?f-yx1mzk( zXF>ZlZZ{;V?4(5f6-a+gZCNz=JttZ#)?2lw{tzvg42nPMU9@F)&mL$vm`GKF$*|nn# z!DZhHoBY;xi6CN4WmUBPQtoK5%3Nw-)D*`7KT;ZgABp$_Ebs&0ECwaZOvDfISsY) zOW(1;6g9`KFX2w^`-fF(RK?39CQYpuS+VfL&m~h(=haO5Rpgucl39Rv1H7vWKS9^X z)f^A}Dmj97FWf)fmNB{{nDy=2d=pBKP47*PmT~@)K=?dtkrb2}!N(toPK;^kO*ZsF zemJe=(f;VuzpB*Jrd6xQu?J8*o5l79vblWowMGgSnyKQ6c-^(l&=a6&>Z3qS|i zI4mUq9c*C#8HG!_Is5`T3^8ns%oxmr7QBxq@QH#|g~AofHKo$NaDoIbn)tr zfK?6Yatj-9?9$)k@x`Npk;s2@X9#XxyVv{}u=i8(Q&8Cvaf^Gj=pNP%{eky~4bg_@ zre-Kdlh}o{*(+k&V?Tsk`nYW=RK!CBZ?@INy^^EL`+h_RcM<-dEg(w>AqMB^+y0ca zVv)q!k#h7WQ}Z8EVe?G?IxW!g!05XSK|^8bsx7Z+Zni+)T=WnmUGc$5-82Aq9gt~N zcabc-B4<^eVc%MFXW&m~64d`>5bAg9fXk z4%KA*Li?b6tN}WY@@X8BV8OPLx&=q;(^5gs@j8j;$D^!%rV?vsSNSpVm%rZ*DujvV zE;{B$u=LY8dHKg`5u62#EFG^eQg(jNsUXVrDcV97nY^jux?tv|<}(#H6J>oIT2#$A zX;RxD8SV&#M0X9d`fXVNg8D4>s%&?l=+j2kvPA;igw~QdruzQ%-ODrI>cRcE(tI9j z-Ol2VyszBWoAg0llwM~oC)wj_q&?u$fZa=Ow`GNTA8M+!oIHt(Sf-j!y3J}8CWp&ke!af0?g!a=(bl)KP-8}(F_@$r97HEl6G=af)6I%e0KGnYU&k+^N< zO5nusw#>*JXfm;$?5n|Fo}s4uT!N<$2cBU^$GP5cg2LE<*QPUz6;*S2&~cft`*L22 z*BHR9hX*`oKHsF})sjo6zPuvqwSMeA~bQtYM)lo0%bWi;9exU4aX4JVSH+?q0stE81 z{`eBSU3-o-(BMzi(CCeOEwpyXPagenzgECOAY5^{;H)4O2LW(6;E$Z#8gN9y&qj6Q zr$nc8zR?d2ONNB>5j**1o_pv-m---fNMP{ME*I@L#}QnZLV!+O;TBn_L)0?iU`mEc)?gz*d@A`h(GK@nXOQ4hJz=t2Q^9=O~vcp zRZ1~b3g`$B%z4e|*QKg72`$AoqypGVZ^_d5MEyc&A;ewYCG~M1_5)Te*CJ4Ti;Tnp z-0TCX=q#f`uce3q#*gj*BdM#_^T>)K3uzsCRobbPUh>v^Wx2B5#a?oEn<4gad-ENW zu-&vl4-!IKchocVI|SzSCEcit3SVR;J4jVB9B^>bWY`Xj@^2(d%Om!L-I;9;RRfv$ zX9scdClFFdRKf!}a}mlI3k`>BIwh8qN8eC>vFf<9T*51Vy5a=RFk%=Q)t1NlRCSWQ zhcdlvxE?DvWbbHuNeg$HJe!vx)HI&W?AiyMk_?t!D!I&=2KcaUCPv11Xf7=@iUvjN zz?jl*Xl_@=myoCaI(H^2uqPif?amvDleS4_`^`EQ>#SlJBuep#MUthN9*h#DOX;CQ z6#^Zf3$Dni8CGQ(&wmOZ+`T;yb84S&glCG@rV`sIqRShkhsjo)Lzt{&lC0Qok!^#7 zyl3r;t$DT%cKlK9XDjy?+J)+?2lR>f*|grh20GJsl&U1JyC68rDIu}u_Brv5QBdv) z4&jff5$LFC9N~Fm)mnU!>TITTo1t1PH?Dm{QQJj-kC+czTkd%;cJuoW9j6mWkxFS} zh}Or-)x=gMXSe6h)dMJPrhhx<^lioJf+n_o7fkOco*W57Y&F$n6{U@E|E8>)--#;* z%|~eD#9DX;Mt|f6+^UfIUSsQ^_CSzcQBd7tE;?iBRL}!zi4w#`>m5P`RnK*t`*+og+8bFs?_IkzL~&mK6ru zwT{O5`nQ)+cKR6tZApgI8!|m}n4eu5v$J~?o;1of_dz9I!)qesnQdoUP}Fom&#;r} z@j$x(kI7p_J&f~uun3<0k+z+WThKuI=s#dZd0sk2#h$mJMsrd#$hP#dm-Nmsn=n;8 zA?eEABY5-z-t0xvrP?usYI~$GaxKfw)4?7kQ&FoPAQ|L@Pc9pmyz!XPT~HKdx;iPU zY**kf1>DA3 z#i`R19CQoz#_{UD24D<8SDeS$4LaNCb$FN5%bFHrc6aG(9zqRI>~yH;mBEn0)~214 z72{DK)m%)s6HsOY0h^D>iPPO>r>T&I8?G9e`-q1bs&r|JYFL4^)VXMZnW!hD?#?v= zJ)^#2AsvUV(8SWwwWr7S>K5Go;$g2ox!~?+;}}~+3!xvSZ^V)}=EE^?g9i>mO|Onx zmNOqw{JPcH7-_OPHJxt+N_OADPpU$;+^M&xDDDsAXveKNHv??GP%dn?QgQ+i zqz=B79q?ia8~vdgHTF8y!pNRJ1O;yx$$4 z?9t0V=o20m){tSl6`%7gspHr*3O)R_`qS-@+ivx&R0eHVV}#>mokp))_3_kmn#A}C z$XLCgt9g?=qq#uyJP_I0qIst)S;+B-dd<8MmRK49`}G$|=D_BLfcV}&rbm#C^{mx@ zt!e#y{-lm%0;I`jU;nW z;+2Y}WBk48#w41p5styO%&rC1ZvGF|{E%<_YilYVQFLcb#(xgHlQsR~;doX9J;uyB zdTSEEM2GgV=^{7-PjC2Gn4?G~yA^e`%KLP6_4%9{~T zJ{9}VNyApd)ikNKqHL!0Rk+sRpYT5ao4O?po$%j=wKi>7fqL3{qjH-OF*EhFKY%!S z_E}EBHX~0r-U95-AM1pP@R^o2vgzM_>hDD)sCWI}O9^Wl{#zXbv-odm^xx9xzjg6{ z>*D`{BK`$M{ELYB|0g2mIUND97ffZ>dE(p%xnFk($Rhw2ZNyQ4M~Nw;7Pxv8@b!NP zU_M2x4&V6$Ow|RPY>fmXciSoGkWVDSg`K@;oIiHGC$fK7fsghf5BYzq{hATVtC%Pv zLYNv$1O;GA95uDjy~B+_@REQy;Xj%ZpU$Ba#FCI~mpZO=NNc^?L3?!d6(9cq0Tn~0 zu`yL&fWOgi(6YB^m2u;jBl&duDx}-~4@kEHc4@Zz9sx3R-n%935{Y*;g$@FKTAKFY z$DZEhk*7oRo|4PwZ?o#${sEjM_pr4~%Mf@~c~n)q{ODo~b7@Go=N%PO?6~aG&(F_X9P)(5^Wf6@J*AV-V0pKz zV!WW_3Zkg!Lj7VY<7Zur?T+RWRE;KrPe0E78eWH;fiA%*zL>T#RaV6Ja#|L0piO+W zEMuy&P%ik%7lRlDb`w9-5A0#grIX!kD=rKglSIM|x0Qts;}tbCg{r!|8SWU=8^%y~ z&+F&2)3OJ@hPyx}BMaUrKR>`1gWg#9Q?*dczaI$nVBkYU4vQ*WTDf54wk1ydtlEgT zzPi9y14F!ZBZaPjfPm-Q`1qTQ6w_r5F24TX63zLXynm{AYb~`FE*VTkk9oY>?)yz} zy60LYRfNP?fJXM)%k$Xc>dFQ6tjdiZqP2!&GVg?#7HeD_^2h9sec0$N8e=$?8=@{a z8#UhJVk|h^t|~ZtP8ODd+I=RN+MP)QH`81EHNU6$Yw0sj|zu$GO1I-jz=)4$+%pIrUd#F)N+P@zV z0q=+_&o&Fda|Qo?b0PO;zS_P8(|*&&rn(8yF;C`x;PLp%7elWub)Mng%^5g;C8uSP zNM!s)2@4#T+J|yGmPYwv1UoKoUUVfhcSx~`@r)|8aa7qIOJ_@L^GNyf-O!5J|J-os z&{e%oXgnQ|A+;SFl%YUmX_#*)Vx;~;^{WjyRlaa&HhoK!Q_YxRdD9*vaz0eqKS}rP zP1eiGL&8w9A%#-;24&2R9aNT%Dm;NGu~8`|)Uq|fT&iZf88z#hq|@z1cDieYR2&a{nY|M&o8 zjPA#)0XV?t7K!KSBUHOph^6Ay4tHWB(i-C6@AWk-Q}i0}V}Sm^%_FFU_q(AM9~HIV3$Outvs>iLBLq$m z6JU(^|0py8%3$ICY%sJ}o!SE?$5p(F8N1pxZ}QI%C~E9FgRj_u@(OW6)_mu?|0r3! z_Dj=UAL!rk;(Vh|>4oK0h^NW(@JsvGkbF_4;<5tPxeurw6+c0>Rpr20Vh1j28FY?E$<8A9@zdTx+9+D#)k3URiQaSA zDf}E(NQbT^nth6Vh;83%N942i`p*075g|gIxR0)5yBb=0t8O4f7(0SicpmdW+nMhk ziDyb)WN)BUIo>l!#6b9;ABf}K`lh7^3JjK@EyN$b#S$yVtD9P@q&Z=Ip#Hpy8v6=v zaKW6E0J|8tg~9pbs(IK;n`}>}s;YV=x(IQ7{+w&_m|FUNJ?%peO(v>E$2WDzCEFOB=>zR$`q*6{#}pSs(YZxGGPIiLwe5Ehe- zh-}3Tte=9irYir!tasVW*RureK84Y~MMO3yK0Mlqj35B?DwEln;pJFZw(g0N)^CVM z@Lj0vp<*O+bnz7${(erNCgNG=ZXpL!BMk03Fx9Fl@<-yGO#V87OY}g$lsb>W*=jT& zc={PpG%@SZbN@NVTdF=V^eOv`-o@2KuHf^pvk*0lFd{+X`Ncp5EHO&E$qZXLajn%% zmqLm6D*RVgCGqno5dRYIW25(uNr-Q#Gnfmow{fZV)!3_tO$$olnR)i1}5lap&Ql*I7vvg47c4O>2f>Ps2-Z2BW5#lru2^SU(@H? z5H(S^UsjMP{?>>xT8Q^Aj}uE%YtnqHfu@OH($hD&fo_1&#gH9_X>R5MW+1YFqu^vI zo&hw@a~Jpi$4Hc8JouY8kSJ>ptCzsS|AbbfH!I>iz@QVy3Zs`XI+EE3w5PvFmSH1? za~*q(z=_>9DXdFxAyFQ`3)dCBVjy3xE0ytEV0Z@2%Aeu*{k z7q^(4_NP9MCQwR>`3pL3OCVw!-NAyDdwT_QJcr0y1ebaJxu;2dEs6X~Dp4n;+Nc`OlBdnf1cXj`n7p7A7NJFTl=m2C6Yzw#V@@@88T0IzKx@B;DS~Jc31LK?!&?0={nwfm6_DA+OWOR z;1C^f*O2&bA{E>mL8N3`MU4ad6mUwlTNIf5BD*Ah#`hhqq9M)82Cm3kz?r4~en;|e z?G7X13n1ZtVBQ#DSwp927{z~FgY4k&U zcG2$oQ@dbjqkvLO;`AcQwEXcxpQ3NDNEEsb+mWvMLobu~Ho^Q;?sSbYk-O+iiT-sQ zJ84M~eO|j&JTRGRwrxQMbN$6V+^`5$g@w;JaSH|p2T*{x{^l@{nCRY5wBM{ct+Kk% z8C?Ho;p1?zL+XC=zhc|r&D`)%xR!wFU$rW{H3SC9Q}yY39FQqp=LjYOWq%JPj$4=q zho?AC;hRmalcbLaC~~?Kfp)|1AFPf_4)fN!F`foDcxcaalY2#Hw6&`R+#T6D{_-;n z9Vz)Kj<*|}b5CjS;3sT|C4UYC?Y}1t&eZHme(>fjxBa&*NZ`NY%IZqE!zS1MA2E|) A7XSbN literal 64996 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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png b/docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png index c81e221dc88cc4e32926524183ea2d4f72e84ed4..36d7dd49387984f4ec74eada9c0d26228118b701 100644 GIT binary patch literal 47689 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 aTZ)?5U3qKylr)hJehl<}(Isl*&;B>kDWJOm literal 47574 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 Date: Fri, 7 Apr 2023 20:43:22 +0800 Subject: [PATCH 174/252] Update DG and PPP to reflect new changes Fixed minor inconsistencies in DG --- docs/DeveloperGuide.md | 11 +++++++++-- docs/team/jaredoong.md | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index d6840905f9..b8eb3888d2 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -17,6 +17,12 @@ * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) * [List Recipes Feature](#list-recipes-feature) * [Delete Recipes Feature](#delete-recipes-feature) + * [Add Ingredients Feature](#add-ingredients-feature) + * [Delete Ingredients Feature](#delete-ingredients-feature) + * [List Ingredients Feature](#list-ingredients-feature) + * [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) + * [List Weekly Plan Feature](#list-weekly-plan-feature) + * [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) * [Appendix: Requirements](#appendix-requirements) * [Product scope](#product-scope) @@ -25,6 +31,7 @@ * [User Stories](#user-stories) * [Non-Functional Requirements](#non-functional-requirements) * [Glossary](#glossary) + * [Instructions for manual testing](#instructions-for-manual-testing) --- @@ -213,7 +220,7 @@ The activity diagram below shows how the `Database` component works at start up: * [Delete Ingredients Feature](#delete-ingredients-feature) * [List Ingredients Feature](#list-ingredients-feature) * [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) -* [List Weekly Meal Plan Feature](#list-weekly-meal-plan-feature) +* [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) ### Categorise/Tag Recipes Feature @@ -431,7 +438,7 @@ The sequence diagram below shows how this feature works: ![](../docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.png) -### Edit weekly meal plan Feature +### Edit Weekly Meal Plan Feature The current implementation: diff --git a/docs/team/jaredoong.md b/docs/team/jaredoong.md index 4bdb518753..fa7c6c386c 100644 --- a/docs/team/jaredoong.md +++ b/docs/team/jaredoong.md @@ -50,6 +50,13 @@ apps. * Added documentation for the following classes: * `Database` * `WeeklyPlan` + * Added documentation for the following implementations: + * Add Ingredient Feature + * Delete Ingredient Feature + * List Ingredient Feature + * Edit Weekly Meal Plan Feature + * List Weekly Plan Feature + * Mark Recipe as Done Feature * __Contributions to the team-based tasks__: * Setting up of GitHub team org/repo * Maintaining issue tracker From 97b62cd4e143a90f238f9a3db385756c53551d47 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Fri, 7 Apr 2023 21:54:17 +0800 Subject: [PATCH 175/252] Update Architecture diagram Simplified diagram to be neater --- docs/UML/Architecture/ArchitectureUML.drawio | 2 +- docs/UML/Architecture/ArchitectureUML.png | Bin 50056 -> 29336 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/UML/Architecture/ArchitectureUML.drawio b/docs/UML/Architecture/ArchitectureUML.drawio index 0e82a7039a..2c128a3c22 100644 --- a/docs/UML/Architecture/ArchitectureUML.drawio +++ b/docs/UML/Architecture/ArchitectureUML.drawio @@ -1 +1 @@ -5Vvfc5s4EP5r/NgOkkDAY2KnvebSmcxlem0eBcg2LUYeWU5M//oTQRgw2OGXC/Y5D0GLhKXd71vtLvIETVe7z5ysl1+ZR4MJ1LzdBM0mEAKgGfJfLIkSCcYwESy47yUiLRM8+b+pGplKt75HN0qWiARjgfDXRaHLwpC6oiAjnLPXYrc5C7yCYE0WtCR4cklQln73PbFM14Xt7MZf1F8s1Vdb0ExurEjaWa1ksyQee82J0N0ETTljIrla7aY0iJVX1MunI3f3E+M0FHUGOE50/3h3/zta8r///TS9d3+uVx909ZgXEmzVitVsRZSqYClWgbwCE3S7EZz9olMWMC4lIQtll1v1BMoF3R2dG9ivWEKFshUVPJJd1AALJyMUSICOkvZrpnLTVE9d5rSNdEuZWpl5sX90pgl5oZTRRDGN9NKDCgA2izrAuKQDjI2yDqCtnUsHWmnNnG1Dj8aDNLlsxsWSLVhIggfG1koXP6kQkSIy2QomRTlNSW3w6Ica/9Z4jhsfjbQ52+VvziLVSmZCvRJbD/Qr3QPhCypOLMuotgOnARH+S/H5VTpVQx+ZL785sx+yCvZDEBcfsWFb7lI16sAy+2m0N1aZyN82lJcMKL3QOr7croIbV8Q0vo1h60uP90AcGjyyjS98FsouDhOCrXIdbgJ/Ed8Qsa3zRmVbEfih9AupD9Z64oRW9AvQLnMCaWVK4HMxwi7pM0bkk2pmdLjLpLfdKbPzxY+MJLL1nLuT8SVupHTJaJYx67lArGqazf0gSN37BKK55VLXLTl+ecexDN1oRsyEAO8RswaBrY4E7gQBAIbEAMghIMPDexho5movAgNAGxQEaDyOQGvlCMA1gAAPiQHYxhG4W/7yBgHQLyDMNogougV4HX4BDokJhMeKidrhArw+NwHsPiL+G85JlOuwjiP5zfGEAOrFhA7Zdh5fpf7Ygqf6y4tkBr1mDahNRHsewBZDG7NubKN6Xhdgu25s7QB7UIHQlTc7ClhgnOp/HsCqr8yluV8pCRAulypyEGtr9G7Jq3VQENDUI/JFLUW/fPJqnCt5hW2C1nFxvUsu6xFqzSutjl2LOvN+qY4vIl6B+kgh8X9GxLBZjTFSRMDTkLgM03YNRDuZFpe2zhkRxCEb2mDvrK3YXvdOYOrD7p1WSXff/AZawxqxgVmlNTgzsfYGYBaKfIzy9jlTJGIZA0ci5WhtuDS5e+WkYeHEM6jl6VVgsKCDMO7XN6Uv0sceiYypctL9PUvDNHSskBikcIIwKLgrXYd5eJX6mxo81f88eWh6zGMUeG1X6btGwA5SOEGWVtxfbXQSsIaNT/U/D2BTHeZCmEfCq44InAj+6lq9U7iCYJH/gxdO0Hhyol643vQQwHwOq8tlHnaw0TfXYV2um0PGK2i0/r/2+2B4jaAYNMNOp5nzsf9Q11/TB38jGvjZ2srt5Gd1o7htycDr48CJIRpPPTJXcWrkac1OrDLiv8rqytunZ1bVrlsN6mpBuXD1ndJfQbQOSNiEVe8r96AIk3z6YZthHJxlHAHbxlOGaVTr7evlLwUyoK2sytnYRKRvtpmXsYeZR/awBkyrrdhu+5dVfP+MgD0wn+Bo+NQuJgR5MjU/EeYAz5trVWYHmols2jOfrMvgU/nVwZdwwann07BJTFhbuZ04ZcKD0gQc+MULGs8pyz9yaKFPgth1CTLsgXr7BEHeS5x6gPz+F4l/IjCTzewXf0lpL/vdJLr7Dw== \ No newline at end of file +5Vpdb5swFP01edwENhh4bNOuW9dJ1ap99NGASdw5GBmnDfv1M8UUqFlaErJQLZUqfP0R+9xzrq9NZnC+2lwInC2/8JiwGbDizQyezQDw7UD9Lw1FZXB8UBkWgsaVyWoMN/Q3qYx2bV3TmOTaVpkk50zSrGuMeJqSSHZsWAj+0G2WcBZ3DBleEMNwE2FmWn/QWC611UZBU/GR0MVSf7UPvKpihevGeiX5Esf8oWWC5zM4F5zL6mm1mRNWYtfF5cNfap8mJkgqX9MhDIvL6/PL38VSfP7+YX4Z3WWrd44e5h6ztV6xnq0sagiWcsXUkz2Dp7kU/BeZc8aFsqQ8VU1OzYnUgxIhyaZl0hO7IHxFpChUk5omqOqhSWI7sCo/NJB7nh512UIbOr52tXbz4mnoBgn1oMEYAswgXEaAwEZeFwOEDAwQck0MQGAdCgPLWLPg6zQmZSdLLZsLueQLnmJ2xXmmsbgjUhZayHgtuTK1kFIAieKn7v9YuC0L7926eLZpV54VuvRXhCUWCyK3rEJDRuKO0E0/CMKwpPdd3fdhqrtec6qm0vgP+h3/QYC6Q+R8LSKiez3zzNM0dneWKeRvORGGA1UUysrH9YqdRLKU8WnJUaoi3hUOCbvmOZWUp6pJyKXkq1aDE0YXZYUsfd12Kl9LRlMVF+oYvNVjAzRhdeMCCExNQMuUBDqUIgIDz5JWN7rYyOG8sZ7uL5kNlT8bkajSbaum0UtZqOXSyKxR1m1HWP0ySyhjdXifAZj4EYkiI/CrmtB3HXermyu+vyzMFwXsjy3gvShg28fkgN1iQMOHlzgwLNROkQN1OjgVEsDpBAJrp0Bgv0ESoElxwDU23C8EM4jMpKnlwhFhHbCN+s9SE8s20+vA3EbdQ22jYBf5RGtx/6ge+3AB1XttRN1rV40x8ZNer6PIJ2Gyl5jQayMqmJSagDNRSvxHjJhWfAXuRBkBtlNikq4NJuVaZGydZ1jiEOdkwN65D7C775225xx37/QN7L7RAagRO3aJ14dagDyI0YEyDt89csZhZmXHCia7Ze97HeGUy/3Y6XO6D0KItjr9xRhUH83eXMaBJkqJ3W52Bh7oJkKJ0felx64nQuCi1SArL13z1sjP7m6fDm11uPJAm15Ge88C29qrh2oGo17w1i+WJsDXMTLkt8nX0VPknfjqBt178fpdw0H5V4PUyjyuseh7x7AlZ9vDi6/PPmDdZSr3HfXO14LuK4loRq5oLgfAlyQJ6L8uilGI3JHgc9xuNFTh8f2R0zfbPDH8IOQXKzKG0yEAuuVf75nh8VP24Kls2avPOMC6LpocsIEB7Kd0IUhM1TIHsjO04zix+sC1LQ8GZBwQEQL/DkRVbH6gUQXS5lcu8PwP \ No newline at end of file diff --git a/docs/UML/Architecture/ArchitectureUML.png b/docs/UML/Architecture/ArchitectureUML.png index 27210addbca410bac87faf301530030a6747b45b..bfae3c75c6269a3cb42fd2dfc7d746552712c4be 100644 GIT binary patch literal 29336 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 L)KJKmGeQ0vnoVdW literal 50056 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 Date: Fri, 7 Apr 2023 23:12:12 +0800 Subject: [PATCH 176/252] Update README.md --- README.md | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f82e2494b7..a9fc66b426 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Duke project template +# Meal360 -This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. +Given below are instructions on how to use Meal360, a simple CLI meal planner application. ## Setting up in Intellij @@ -8,23 +8,30 @@ Prerequisites: JDK 11 (use the exact version), update Intellij to the most recen 1. **Ensure Intellij JDK 11 is defined as an SDK**, as described [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk) -- this step is not needed if you have used JDK 11 in a previous Intellij project. 1. **Import the project _as a Gradle project_**, as described [here](https://se-education.org/guides/tutorials/intellijImportGradleProject.html). -1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/duke/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below: +1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/meal360/Meal360.java` file, right-click it, and choose `Run Meal360.main()`. If the setup is correct, you should see something like the below: ``` - > Task :compileJava - > Task :processResources NO-SOURCE - > Task :classes + > Task :compileJava UP-TO-DATE + > Task :processResources UP-TO-DATE + > Task :classes UP-TO-DATE + + > Task :Meal360.main() + ---------------------------------------------------------------------------------------------------- + Welcome to Meal360, your ultimate Recipe Manager! + __ __ _ ____ __ __ + | \/ |___ __ _| |__ / / / / \ + | |\/| / -_) _` | ||_ \/ _ \ () | + |_| |_\___\__,_|_|___/\___/\__/ - > Task :Duke.main() - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - - What is your name? + ---------------------------------------------------------------------------------------------------- + | Loading recipes... | + | Recipes loaded successfully. | + | Loading weekly plan... | + | Weekly plan loaded successfully. | + | Loading ingredients... | + | Ingredients loaded successfully. | + ---------------------------------------------------------------------------------------------------- ``` - Type some word and press enter to let the execution proceed to the end. + Type `bye` and press enter to end the program. ## Build automation using Gradle @@ -39,7 +46,7 @@ Prerequisites: JDK 11 (use the exact version), update Intellij to the most recen ### JUnit tests -* A skeleton JUnit test (`src/test/java/seedu/duke/DukeTest.java`) is provided with this project template. +* A JUnit test (`src/test/java/seedu/meal360/Meal360Test.java`) is included in this project. * If you are new to JUnit, refer to the [JUnit Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/junit.html). ## Checkstyle @@ -53,7 +60,11 @@ The project uses [GitHub actions](https://github.com/features/actions) for CI. W ## Documentation -`/docs` folder contains a skeleton version of the project documentation. +`/docs` folder contains the project documentation. + +![Developer Guide](https://github.com/AY2223S2-CS2113-F10-3/tp/blob/master/docs/DeveloperGuide.md) + +![User Guide](https://github.com/AY2223S2-CS2113-F10-3/tp/blob/master/docs/UserGuide.md) Steps for publishing documentation to the public: 1. If you are using this project template for an individual project, go your fork on GitHub.
From 3c08c6258e13560f23d9388e47441395a121b7eb Mon Sep 17 00:00:00 2001 From: JuneNita <88151966+JuneNita@users.noreply.github.com> Date: Fri, 7 Apr 2023 23:35:47 +0800 Subject: [PATCH 177/252] update file path --- .../RandomFunction.drawio} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/UML/Implementation/{randomFunction/randomFunction.drawio => RandomFunction/RandomFunction.drawio} (100%) diff --git a/docs/UML/Implementation/randomFunction/randomFunction.drawio b/docs/UML/Implementation/RandomFunction/RandomFunction.drawio similarity index 100% rename from docs/UML/Implementation/randomFunction/randomFunction.drawio rename to docs/UML/Implementation/RandomFunction/RandomFunction.drawio From 40ec18cf21c470a001579f0763c8745f5d0ed732 Mon Sep 17 00:00:00 2001 From: JuneNita <88151966+JuneNita@users.noreply.github.com> Date: Fri, 7 Apr 2023 23:42:10 +0800 Subject: [PATCH 178/252] update file path --- .../RandomFunction/RandomFunction.png | Bin 0 -> 17610 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/UML/Implementation/RandomFunction/RandomFunction.png diff --git a/docs/UML/Implementation/RandomFunction/RandomFunction.png b/docs/UML/Implementation/RandomFunction/RandomFunction.png new file mode 100644 index 0000000000000000000000000000000000000000..8ebd0d09dba04ac3b166c3d05d2df6488a299bb2 GIT binary patch literal 17610 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 U4tDULlhB Date: Fri, 7 Apr 2023 23:42:43 +0800 Subject: [PATCH 179/252] Delete docs/UML/Implementation/randomFunction directory --- .../randomFunction/randomFunction.png | Bin 17610 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/UML/Implementation/randomFunction/randomFunction.png diff --git a/docs/UML/Implementation/randomFunction/randomFunction.png b/docs/UML/Implementation/randomFunction/randomFunction.png deleted file mode 100644 index 8ebd0d09dba04ac3b166c3d05d2df6488a299bb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17610 zcmeHv2{@E(+dtE!kua#F#Zs0c>xe;?5XzQpQOGjJWSL>cl5I>SNm1Fdhe8w&(n1Us zLbhz#RbZj@GAV}~`hB1KOX{$6c_=g^UT2qxSyKe6=9o^oWgyUxj&R+HyCls9kLT&9y zKuW>^izf&m)CHuZtZ_IoJB&5j&Dt3+=7J)CB2e#)wZqtBPq(V z#RygK1S({t*B-rOqz{3TV>p}>$`oazjREV>ID(KBL&$*QgW6g~x;g?+TPj?^V1NtJ$azq@EEMi`j#ZcK=ZZ5qX^dM zwNh_q7Y|b>oU4nW6VgH3UCLSq3x=k3CS1g!*4o&iJTSJarHJDK630Lt?Jq)YU5MZX zvo1C-Ydd{WITNQNr_Hch1TEyLGsl5gXrsAUgC(zu{}hm%s3fiQ=g~ICboSD8v&K2- zV(m~)pqri7S|>?~BkN1IySP?zL>93>Lop_SHe9BxnVO81MDzB-i_)-7$73{Q79? zJH%q02pHUN3vID3E-2gelU*Ot+Rcr2oU6-UFS5rvt?zlg00*}9n-;VJLtAU7KbD$e z>qP5mSVbBg6GfPUWFWlLBqw#tH-oYB6Ypwrk(I4fwAx$?d7L51Pp{-T? z{7X|2HIx%g*c)uh9<_L6WGT|ama zYbW=0;R5A6jk3kyP&yc(<*R_h6E1Fu9tdm|%I?liIv9JD6UGH}Q^ld&FwQ6f$_+@; zX}$Q=uVt#94j2N;5N8dLk5Kmnpagv!2+mI6O%gl;oDi(RNVM*>cRM#M&dAyg4fq71 zPE&VVEZ_tj9%Hk*3|fgB%GMnyqzCFW3crR=S}E3@KwFX858TlTaacD3D8Uolz#Oy@ zQPy~ZCyGX4sxBzc<8}aB8yl1b%p&9JPCIE;)Q^fEML;$`)jQc>f9m~fBO25E7=+g7 z*Vo?+04Rlk0jU0|`sc1-gC2lGe+&isg5&>bY&WdCi`^eu$f|?2uge5M+yB}b(k4S~ zFu+<7&iYqitzzx3(Y>JvfL2g|Gzo4O0nXP)JR-Y}%ymYQS%3BXRXu+wp~KIrDSc#Z zE!OLlfc`Nwjp_a#wE=C`weGK%|0l}%ry3!>F0Y?7;`d7M6LfJ{fT`8BA5j%JLKFSZ zx&V;pfJI|ntet+=hCf9qVHNL&H1(nl_dEUi{}94|7i|CZ1XnrjufgzFSeE`RlsAz5 z6O?JaY4H3R$w1Xs%l>tMyslZlrS?UjPFPzg6KTHwFal*S*&@|9!(#U3*(w5^X>*K6v?)IA^_R z%_&-I^{1Fv)#`s76QUAg>offX1LV3TcSAW@6F`LVn??Q^4*s6`e|0!c(L6?QBpbf? z1`yXNR&pcA-k1rGb$7Ext@omx<-hF|uTAzhr$lUo!+&eaHL?GvOu4ZOti3&cBR%x@ zZU6yd9pKylh&KLO&g-pL*;(TqR?}{@DEjYJ zv%ePBuPFL)4pI{TG;Ki~`K?1DDJv(2`1z0Q+O9WX_n)sklE2qiS-Ia%`4214KO62+ zf6N8_4EKZolTFD#fbn&HrkMzkz+OA!e;)2PP_{wYh;?rIuLHWwh9UY}Q~tw1|CLfU zY~jW({wG=qsXxZqKda3eaQ>zIumAN{LPl!cN#202jKqJll|abKiv7+~ZKOmuu>K!b zAK;-|(^9Y-1LD?Fk*ogxKhMQlwPJtcu4Kc){dz0)GcT{!Zrp>dRjhZQT|ll~pA;YT z{YXd0OLs#3n30#|SORg>#CTt2j%uU&aAkjV@QZ6-_BupJQ3m2~N%9G&i(QH_dg8CM z3(B!G&?RE`E)w2EhikJWA|Ecu&ToI*<|@Jwe_*K$9PxF zqcgcFVwLUrXra#)H?`Ar<67Cj+HW1CEdtShh(naN!J=O-Sa=EQC&s^vK?rdv`}-ET zh`7@xI)sycilR+qZqq;1m|AsKDw@Il zdY)jyFW*VZ4XFME3)%MZD|T+4ZU z?q(wyX)d>-n&n;n%U+W-uP1vn>#`U~FDuOvTzeT)*bZnsM>$ZYtZVfB=S=WRePx%c z-UM@W=S5e4cqyCvkup+?JwVELXx#7lIM?HQ8;2CKWmo4Dc8H=`c*!Gl(3>-ktaTj) zj*i)$Uu~ZIE=+NgY;82h8aJQN^q2^>;IAF0oa(;lE8-Zb-y@q~(y6xK#n`XdIxwb$^g}SIZaADu0=Z| zk+-`a-=rL}QFb3i*^O{ABD{xX-t6VjtBYV(>oZ<<3i z2lBLyN=kFdC+;5HWLSemKs2?xN|4jhC2*wV4d2CvBhaamw*`nnzr4R;)BDA-qTJ1#rDJ<^$FPL`w7(1;p+ zWAteD?Doi#4?_(LRKweO3vEoj*vG~Gi|Hosqa}0ARi2*j&#FPy=t8uvs7y)R>dhq1hx$ji)9YP~R4oaF|arjc9qflE*4V`vmoe{;lU%bV1Y%T~BH z&<2jYxn&z9UGl(5b)9=7oG(78svWfnakxmKF@)1^8RGv(Vr;no=^!UPx#+_ zn8Z9A(s)<;6E=u5$MeaGJ>lgcoX`A}gjDGuE&Qcjntew2{`VJX_MK*qJNB2d8=w7v zWLz`bbR;PbU_s>MpD;so*?D!l`43({#w!JR=NFY>zWaT+kiMRbb4P?cdaR?M>ItUF ze9AEETOO(={$kI|i+)oD&Ye%~UR`0#nQpAJ_0SCC*1fuo>&{*|H-4_8UbwSkv5Gz( zQur_L>}G}vS)vtsOP;fppiRk|~qc6a0AoE=0Z;nkk`&cC=_r~%lO7v9z} z<`b2Ar6c8dNXJg^$9YV~i6Q3>-uX^aDF7l85yQ>YF4AaiZmiS79yR>_fg%@Nxl_uq z^^slq^&R7J-|G?-!XrgY1*=~U-Bt1{q_kBJtq7y%9_d^4Wjqr1CLj`&iTmZP)?Bxp6c^)AxTQH@tSV6|gz$Z`F6Z<+pSpC9NbT|Ob!3b;mvwXu@x6O~`m50% z_cILWnkZ3svn-3*rN@@V9l?;u#$>mVuuw_ciswWj-Pq>v1j)vs&gHp~2R7)*$$V`p zQ{lTF9fnFQ+1JXW9hKcHf0%mVb+$#(V!XA;BKwKhLWfVyTS#v3^W&PlI6~?)w!&k2 zuRI~6D0k6pXZL;M9!_pSZk>#wmz$Y(&UE42r{knh*E#6hx7GC&`*iDexTF;_F4~m6 zxz!y}@P?0gK;wp%(sWGy^SF$b94QY(i|#@xX_H<=`o2WIBdA>`O8XnGM%h8or|6nshZvbaH4#5Z7-N)RMJp z!C8t8{fK|)D)XM!e0Afna2}!Za+?oYeLC^T#`066OS${gsCjqEcE+JKoR3%CQj!PE z$R^x%&VH-g2X64I$Xya}1jA8b3ec#RY)`SkFIjL5-Jh!b3)$LYU z-s5Vb6|?J1o?UQF-_Vx{CN2(hL7aEz<E*bV%7ydBc?% z%Z;;4Z2tvu-d7)>PZ&%L+0$HRXz* zj%7oZocWqnI*DNQpA!_3&f9j_uqCrp^5Z88N0J7x8Wn>ju)Q3&{S|hjaK0aHRW)B7 zj4QicFT8c{`{sedU*7MAZ9fjkAc=s2hKkC?ls4$<)d*7ELPQ_iA&^w&8Y%X{B%=R? z_7gU?z{?PGyt9LwI(0iq_m`FVsIn?CgQ|If=yRW>n2SXXj)a$0DY^E~A5*=syg2I; zlf{jwv2<9`@d&QAs+MdmSUPdWK03pfkAJSBav~=wFe`FwDw>ivh#A&jT6!+cjxG6g8qv?6jEumKX){kY+x+Y9T0i3${xL>nfX=Ja3L-% zAENo)>BLD{|Ff^&%N4eFyw`fXEtGh`L{1^SRnYeAok=VetPZtVPo^lM+sH9Y87(W* zR_)(zZ?iJ_y=Q45?uH*J+#)T{DU?USwQ5|X+U3Jsz6w<;lFUDZU5e6QcAoxHt2j9s zy~8=Cy2Er|@$X(JoRA(yh251|tZ8Ri1!`MtotG?P^F!y=AF(kAXzLiGjZ|jEC55 zwKzYKbk6HzU{&Zog-dwH!7XN&Wg$Tztb;>f@poYHyp3-dq5Jt7bQsVL_l_Oop&zi> zRn?cg2mW1|J}Lu_)M0={gsLEXaH>pq8mK3?L^9CgKu{^eh1ky9zz3PzZcO%H9&r(4 z5!F(qe1*$r27(~3;T9bvop1kE6<%e?&7R8~=C`iQMe}eSRilH{!p{d^7s#})U_|kr zl7}R3KH)%ouu0=GZvzT?w+R+6wr7eUyAzTuZkfDX{wl^_m_4`o%|O$RvR%1-{|<$|X45A`ueFS<#g>*DQ}zEAp%WG*>%JUKLA zyJ5`cvUuKDl=xoEbNyTqRo}wsGe53t^4L6bXr7Ks&6%(NJ`4POxa*dCh62!70r;Xl zdxus2@=%%^-{w&9h){0D*lk=={BmynT2fx$`c!Xc>I;VQd&ppW;@`!|<}}Eh;)0qB z1e9VTcMb5J;w3d);(tPh81$P&x_nqGx$O?v)L~f8dr8~LD{D1Cyi5|qU#gw-rbcPUpf2C#l1br zT(#=i!)}kd`zOM^q1PDs7Nm-j%Bot&m;{$=S@OSjSrmCZfZpuL^`0Gh6=>pe`QEEg zvy@DpqfouTEi$@cNh%Jk@h@P2nYY-LnZ~y{paV$ zyY=3D_Xv)du2ZN-oqLy~Ue^53u$w*n(|O2=Pg*HjTz6>k(iWDzLu_XL43#;C&f%;a zeC$?RSh)%N)u|w;8XU=8VcjG12pwFV)0v}>O4o_`^d>S`$+77}uC1ZAi@dmFi1lHk zT-J9OsNRlBQRk~F-U)m_gEcsA-_-0?gU;D9Up*b?)dZURQf(ir^!dBT6LqW;rivpoJ7IeZ!i z(IX>4zN4M>%@Y>w0J)o`j0!2=7)Y03S4zAB=S<;O&t+9@-Fw#L4xNEuWj-@v1^VxHpapth;yY@}>EslyKJgKia+IA0pj|9$dvPF4Y+>#9Ib%e$i= za$hUbbB@6LL>XJMk1q4#rtXJeVKcW?hC)s|5dB8E)79>YFiOXj9qXHM2I-c?im-gX zTOw<+IHwSXhpC^u7o&(w9=zZ{G=?!l(zhC<+_cc-5pjt_FpM|s2bs5 z+s3{&yyGUdO1@hNQUm_T6LNeJ&l^RE5KJRpg_j2i|77y=K$GK35K^pd;~MaI2Wy-Gr5%>b|o<@dD)mx6&5e79xUS_N^0PI&_FGe zks$1a$Z^0FP1PthFDS>l4&W}G2gYcM55AbPy~9eWxIzTV3t!tbjPJjB)2#<^AbPQT zdyB7XJ-PCXxq8WNAE4*e6jhDC&`%ksnn5>J=M5?C`Ms2Mg5P3db#3!ms!u?qe~sOF)O=0o?#}1UhrSoOf4!5S;3-JUHMM42#GM1dfEbf) zkW*8duC{%B;+T$bx-H0)DRQxu>sG#hpdAiUMe}yJDABWDl)g$RXHKjKKH<7?GB5Ci zj4ogz;sYKEMC8dV#3=cB>lXue3BNM`^@)r*0~&Bg)uqi$ceKS`@Ea%9bryMIrR?AB z8hqW+2&u>x*}ZlS0ldFIhbIlL99xC-;&JFhhBn%A{;hAIb=P-@uqV(`Q9>I02U+$a zZ{4*>QHzQ0F7g!O5Y*A?Z+jCQbvMy>>V%Mv(U)%@U+WoZU5oeZxu|#M;f*U=9uI4B z3~kg^%k$(ebVeL9?7BFWF0cE`&W0ph7>5h==(g?5G!SK} z^8Se&pQCX6r$)ccm!6SP+i%nL+*NPe_g9s@y`Ru#G#k&Tg{&ET?<`x`MS)XyHLd(6G9c4ceQkr{sXKIS% zn&MR`4*4=d^#*NKn0QY`uc_^oY)R6iGv5$L7FSCAC|##d6>keAs|y^vk9w$~ZB%Oy zh`+*L@#&Hs@!5m4>3U@{u&ebfwRa_7D;`H_pNV3u7Bgs1+(*u?fEMMeuW5hErQd6R zlWJu?q*DF*xuL7rOQ@L$5cdJnx zpZ4fQsr3==D7mZMqo=Wl2GxI|#!4`RQ(Q06>l5R=#@VrfJ`g%y7iw_Ge%g`JKsA3% z<``f@Cfw6YfIHlwNmP-@F4OzHLiUdG%0hh=llaR%bI;ipQz6e@KhJQ{2fF~(+)**W zE8E4@d|@IPKE2k!4fCQU2c6sV%27_f*0wDNaJ#O&$`?~@~w!=vxkaSI3Oh}XR*aCkt-vn*!CY@}L3=Frp)H08+SDZ&uB26u0@_KzHitGH#cbMKEo$vNc$|ru}NYZL2PKH<^ zi+Tv76!Hp{l3<~KX2C;|S&%XiZIzg({H=6Tos#RPHxbKaTX+Z_%WncFG|e>IXSc^< z+YB${S$PjXI7CrnRqP*K#I>YoHzA`o(i>r zl%xif7^Jd=v0oGyQP%jr*-&4xC0`oV-NHOssZ7oFiGK!cf8A2GNY2dB9udl(-tQV{ z;=(|*;hb#oux=goy|(y+QFdKUJ^iodp>*@y1a#@V73ci@6JOz%m<@$OrN}oH?1s{C+?{!uk>~H zPAASk4=eH*JK5e#>6tIAFFZjRaOY@Cjw{5r=~@M;2VkSM8u%LfIt7FYT6Vzchwoz- zD6vR69;AK)8~wJCukmxIz;%Ka|AI&G!F}w;ph`PP{VwR$#MhYix*}LTfhG88uNYf~ zT1vw+ZRwF)*Jj4pW90ee{fg8dvIHA}s?M7rgS;nIFG)m=7fZ6`C6G+gz6_@)=_L}W z7ttnyDrWR7FqL~Rp%KOf?@nDj+a43ehm(JuV9wXDosQ{mD}!^ogF)Xp;s(c8wxf}J4G%3j>57F0dlfQ6cAsLP7%^GQycY5suNujMe0FP;zgbl9^xf;tT=?sZQlDFe)R6+>!5IuyhP^SpFgK{=Ha`B zWVP;<>2I!GxsJj&%M_;{8>~tinISsWb0STW77tQDte6nc#N0N5V6#tosFr-l zxL_^rzjWM|w;^yfzJJf`Q`7h1?3or7BI^wlf`9*v)Zt)ytMA__XO|9#^jyz;t$ryO zUi^!Wa(u>Oo*9=e+^Wycx_vd!Lq#y|R`Pvb!-5JtA#>UG)!RiS{1+Xe8%viD>&5yH zg_wdAL);l@7{o$@7U~`9zEuxmyH5r?fnCS&5V2>a)~%y|NbYoMs;3@5AGR;E0dXkiyRx-Gr5ZviGX@ZPJD zxb(eY7?^4w2=@pF@0*cq_aCoqWbTF5+!4^eAZG9|{>mkpZS}E7YMfPNJ{mZ_&atve z6%e-SJEI6P3p!)-w=HHn*yF6yot^5&%W^#y2SM6wAl!*X+h||x9U~@sn7RhImN!$W z`LK`p*_Er)^ovYj-SaDRruH7-HlSN2Kp=DLVT0vC<&_iuQ{hSc=B<6#LO@8k>~(cD zztW4SyFv$5g`d}pKGU~X!Q=2koo7jSm+y3K70m+mV~LcrQ=y(O52$xd(vzw|7()yE zrUHiPpu&0qau%wj=?UUWXEEPA%?v6JrEjZyn4UP|U;h13eqHAGTd50hm>Ta)xyTc; zMDZIYkV+B*a6QS7<99l2Yx}AqHmDTic@1y*2)de)vKi1L^U{$0WtYM4o+&ec@R`OUj|h15szs z#eB^nE1}v#hKwx5lc$%p?1t|uc)C6l1F7-7JwIP!H zCD!q@hho|NDR0Sp6IK)Xjmfew%3RSzNoOQ^aU{!d&S(5ZWqZ!csp^Pjv@#_op9oGu zr=3WhPEw!%b2S;UOr=bCdMFwUv}L7}?Z``0HHLGwak2^&O<>O>{J@n%9rbpYFF&fS z3H=-UdJ#tMp&5=k>PJ>0617r`_5VD|v(&f6aBiQ12aL@cWQ<4DAyWravMaCle!D9BTuPk0lt*df7T}gRA3#~6+12VKx9UT6*(h=H zODT2vW`^lxV(-!yuo>WXL<_I9J}YVQ^Pg)+8xH6zFB8yhpIb|a6wyP=+b>O6VHaB_ z>xoo^F?9?}ETSyUlUEdtd!mNsCVG>EiJ((aef`mCoy?cqA6t``wf%iGZtfmXQeK{E zdN>8lWoW*(PDk=wA`tj^Y80cNa;j#SN75_;?tig(MWd2K|LASuoVe$ql|00w#?(tp zVz?w8pV3^Si^0%+8aOfW!s546Kbw*l zjWb^^OJC)#nWu=bJ@^cKAe~6s_av01(oL-QtF`YBeufa0OH;S z9MeN9rsrG(DZUfM^K%j8kxX!pe`S$1>{HPGU>+EO#zwQYr=FMQroH_3imB@Hv!2+4 z(r!XG)+*-Q19>Tt|? zG5QAh9$XSj&o8MgL7%@Z=dtyMk<6iYDFQo@t5-=o~;i~zSH>v$gHe>U&Lz<^2~QrwR;P%(qTrj8ISA> zRJl%vPZAJLgF;gTOEq3+yw)BBQ4bxShxB?TK&2Th;P^gE`7IzjzQ-1@k<2~UtMbAnv}WONqv_&qOb>*3!XhGR^BT71o+#plU!miCv6{cA1|RtxzzNGb zU?iaCd@8YpJIo^jRgMCIz~a3$5Q?Pr&E4YzX>eI}^^I?spqYSM4GXR{TEd!nRbpeU z=}F_@G8P@2si3J;JiZ&^Bt05?s>uL$fA#)WhY_Z(3$ApVKR&?2GqeL9%oM#16 zqa!sjNb8YQ+F{^Y)rl=x5q|J09iFU&hU!V$-ZJOCB|8VH|5RZt!Bun U4tDULlhB Date: Sat, 8 Apr 2023 00:56:01 +0800 Subject: [PATCH 180/252] Update Ui class diagram --- docs/UML/Untitled Diagram.drawio | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/UML/Untitled Diagram.drawio diff --git a/docs/UML/Untitled Diagram.drawio b/docs/UML/Untitled Diagram.drawio new file mode 100644 index 0000000000..bcd64be978 --- /dev/null +++ b/docs/UML/Untitled Diagram.drawio @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 23a95bac6acb214b1d1edd1615118a21edd8c606 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 00:58:22 +0800 Subject: [PATCH 181/252] Rename Untitled Diagram.drawio to Ui class diagram --- docs/UML/{Untitled Diagram.drawio => Ui class diagram} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/UML/{Untitled Diagram.drawio => Ui class diagram} (100%) diff --git a/docs/UML/Untitled Diagram.drawio b/docs/UML/Ui class diagram similarity index 100% rename from docs/UML/Untitled Diagram.drawio rename to docs/UML/Ui class diagram From 51079bd19308856de4333b75fcce82b9a66d0186 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sat, 8 Apr 2023 01:07:15 +0800 Subject: [PATCH 182/252] update Ui component in developer's guide --- docs/DeveloperGuide.md | 530 +++++++++++++++-------------- docs/UML/{ => Ui}/Ui class diagram | 0 2 files changed, 273 insertions(+), 257 deletions(-) rename docs/UML/{ => Ui}/Ui class diagram (100%) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b8eb3888d2..56db61121e 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,43 +1,44 @@ # Developer Guide -* [Acknowledgements](#acknowledgements) -* [Setting up, getting started](#setting-up-getting-started) -* [Design](#design) - * [Architecture](#architecture) - * [UI Component](#ui-component) - * [Parser Component](#parser-component) - * [Recipe Component](#recipe-component) - * [RecipeList Component](#recipelist-component) - * [WeeklyPlan Component](#weeklyplan-component) - * [Database Component](#database-component) - * [Ingredient Component](#ingredient-component) -* [Implementation](#implementation) - * [Add Recipes Feature](#add-recipes-feature) - * [Edit Recipes Feature](#edit-recipes-feature) - * [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) - * [List Recipes Feature](#list-recipes-feature) - * [Delete Recipes Feature](#delete-recipes-feature) - * [Add Ingredients Feature](#add-ingredients-feature) - * [Delete Ingredients Feature](#delete-ingredients-feature) - * [List Ingredients Feature](#list-ingredients-feature) - * [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) - * [List Weekly Plan Feature](#list-weekly-plan-feature) - * [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) - -* [Appendix: Requirements](#appendix-requirements) - * [Product scope](#product-scope) - * [Target user profile](#target-user-profile) - * [Value proposition](#value-proposition) - * [User Stories](#user-stories) - * [Non-Functional Requirements](#non-functional-requirements) - * [Glossary](#glossary) - * [Instructions for manual testing](#instructions-for-manual-testing) +- [Acknowledgements](#acknowledgements) +- [Setting up, getting started](#setting-up-getting-started) +- [Design](#design) + - [Architecture](#architecture) + - [UI Component](#ui-component) + - [Parser Component](#parser-component) + - [Recipe Component](#recipe-component) + - [RecipeList Component](#recipelist-component) + - [WeeklyPlan Component](#weeklyplan-component) + - [Database Component](#database-component) + - [Ingredient Component](#ingredient-component) +- [Implementation](#implementation) + + - [Add Recipes Feature](#add-recipes-feature) + - [Edit Recipes Feature](#edit-recipes-feature) + - [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) + - [List Recipes Feature](#list-recipes-feature) + - [Delete Recipes Feature](#delete-recipes-feature) + - [Add Ingredients Feature](#add-ingredients-feature) + - [Delete Ingredients Feature](#delete-ingredients-feature) + - [List Ingredients Feature](#list-ingredients-feature) + - [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) + - [List Weekly Plan Feature](#list-weekly-plan-feature) + - [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) + +- [Appendix: Requirements](#appendix-requirements) + - [Product scope](#product-scope) + - [Target user profile](#target-user-profile) + - [Value proposition](#value-proposition) + - [User Stories](#user-stories) + - [Non-Functional Requirements](#non-functional-requirements) + - [Glossary](#glossary) + - [Instructions for manual testing](#instructions-for-manual-testing) --- ## Acknowledgements -* [GSON](https://github.com/google/gson) library used for saving and loading databases easily in +- [GSON](https://github.com/google/gson) library used for saving and loading databases easily in JSON format. --- @@ -48,13 +49,13 @@ ## Design -* [Architecture](#architecture) -* [UI Component](#ui-component) -* [Parser Component](#parser-component) -* [Recipe Component](#recipe-component) -* [RecipeList Component](#recipelist-component) -* [WeeklyPlan Component](#weeklyplan-component) -* [Database Component](#database-component) +- [Architecture](#architecture) +- [UI Component](#ui-component) +- [Parser Component](#parser-component) +- [Recipe Component](#recipe-component) +- [RecipeList Component](#recipelist-component) +- [WeeklyPlan Component](#weeklyplan-component) +- [Database Component](#database-component) ### Architecture @@ -91,15 +92,15 @@ API: `Meal360.java` The `Meal360` component: -* initializes the databases for the recipes, ingredients, and weekly plan upon program startup. -* receives the user input once initialization is complete. -* passes the user input to the `Parser` component. -* receives the output from the `Parser` component and passes it to the `Ui` component to be +- initializes the databases for the recipes, ingredients, and weekly plan upon program startup. +- receives the user input once initialization is complete. +- passes the user input to the `Parser` component. +- receives the output from the `Parser` component and passes it to the `Ui` component to be displayed to the user. -* saves the databases for the recipes, ingredients, and weekly plan upon receiving the `bye` +- saves the databases for the recipes, ingredients, and weekly plan upon receiving the `bye` command. -* terminates the program once the databases have been saved. +- terminates the program once the databases have been saved. ### UI Component @@ -107,11 +108,13 @@ API: `Ui.java` The `Ui` component: -* displays the welcome message upon startup of the program. -* formats all the output to be displayed to the user. -* provides the user with information on whether command was executed successfully or not. -* displays the error message if the command was not executed successfully. -* displays the goodbye message upon receiving the `bye` command. +![](../docs/UML/Ui/Ui%20class%20diagram) + +- displays the welcome message upon startup of the program. +- formats all the output to be displayed to the user. +- provides the user with information on whether command was executed successfully or not. +- displays the error message if the command was not executed successfully. +- displays the goodbye message upon receiving the `bye` command. ### Parser Component @@ -119,8 +122,8 @@ API: `Parser.java` The `Parser` component: -* receives the user input from the `Meal360` component -* interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the +- receives the user input from the `Meal360` component +- interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the commands. ### Recipe Component @@ -129,8 +132,8 @@ API: `Recipe.java` The `Recipe` component: -* contains `name` and `ingredients` attribute -* store the ingredients details the user has added in `ingredients` +- contains `name` and `ingredients` attribute +- store the ingredients details the user has added in `ingredients` ### RecipeList Component @@ -138,15 +141,15 @@ API: `RecipeList.java` The `RecipeList` component: -* extends from `ArrayList` -* stores the recipes the user has added as `Recipe` objects -* allows users to add their own recipes -* allows users to delete the existing recipes -* allows users to edit the existing recipes -* allows users to view the entire list of recipes -* allows users to view the ingredients required for a recipe -* allows users to add and remove recipes from a tag -* allows users to random a recipe from all the recipes that users have +- extends from `ArrayList` +- stores the recipes the user has added as `Recipe` objects +- allows users to add their own recipes +- allows users to delete the existing recipes +- allows users to edit the existing recipes +- allows users to view the entire list of recipes +- allows users to view the ingredients required for a recipe +- allows users to add and remove recipes from a tag +- allows users to random a recipe from all the recipes that users have ### WeeklyPlan Component @@ -154,11 +157,11 @@ API: `WeeklyPlan.java` The `WeeklyPlan` component: -* extends from `HashMap` -* stores the names of recipes that the user plans to prepare for the week as `String` -* stores the number of times the user plans to prepare each recipe as `Integer` -* allows users to add single or multiple recipes from the weekly plan -* allows users to delete single, multiple, or all recipes from the weekly plan +- extends from `HashMap` +- stores the names of recipes that the user plans to prepare for the week as `String` +- stores the number of times the user plans to prepare each recipe as `Integer` +- allows users to add single or multiple recipes from the weekly plan +- allows users to delete single, multiple, or all recipes from the weekly plan How the `WeeklyPlan` component works: @@ -181,10 +184,10 @@ API: `Database.java` The `Database` component: -* stores the recipes, ingredients, and weeklyplan in a local database in json format -* loads up automatically upon startup of program -* saves automatically upon exit of program -* comes with a default database of 10 recipes for new users +- stores the recipes, ingredients, and weeklyplan in a local database in json format +- loads up automatically upon startup of program +- saves automatically upon exit of program +- comes with a default database of 10 recipes for new users How the `Database` component works at start up for the recipes: @@ -198,7 +201,7 @@ How the `Database` component works at start up for the recipes: create a new `RecipeList` with 10 default recipes and return this `RecipeList`. -* The loading of the ingredients and weekly plan works in a similar manner, except that the default +- The loading of the ingredients and weekly plan works in a similar manner, except that the default ingredient list and weekly plan are empty. The activity diagram below shows how the `Database` component works at start up: @@ -210,24 +213,24 @@ The activity diagram below shows how the `Database` component works at start up: ## Implementation -* [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) -* [List Recipes Feature](#list-recipes-feature) -* [Delete Recipes Feature](#delete-recipes-feature) -* [Add Recipes Feature](#add-recipes-feature) -* [Edit Recipes Feature](#edit-recipes-feature) -* [Random a Recipe Feature](#random-a-recipe-feature) -* [Add Ingredients Feature](#add-ingredients-feature) -* [Delete Ingredients Feature](#delete-ingredients-feature) -* [List Ingredients Feature](#list-ingredients-feature) -* [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) -* [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) +- [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) +- [List Recipes Feature](#list-recipes-feature) +- [Delete Recipes Feature](#delete-recipes-feature) +- [Add Recipes Feature](#add-recipes-feature) +- [Edit Recipes Feature](#edit-recipes-feature) +- [Random a Recipe Feature](#random-a-recipe-feature) +- [Add Ingredients Feature](#add-ingredients-feature) +- [Delete Ingredients Feature](#delete-ingredients-feature) +- [List Ingredients Feature](#list-ingredients-feature) +- [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) +- [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) ### Categorise/Tag Recipes Feature The current implementation: -* add single or multiples recipes into a tag -* remove single or multiples recipes from a tag +- add single or multiples recipes into a tag +- remove single or multiples recipes from a tag It is implemented through the following step: @@ -235,22 +238,22 @@ It is implemented through the following step: the `Parser` component. 2. In `Parser`, `parseTagRecipe()` is executed to identify whether user want to add recipes to a tag (`<<`), or remove recipes from a tag(`>>`). Then, - * If `isAddTag`, user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to - extract - the all the recipes to be added, separated by `&&`, and pass those recipes and tag label - to `RecipeList` - component. - * If `isRemoveTag`, user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be - executed to - extract the all the recipes to be removed, separated by `&&`, and pass those recipes and tag - label to - `RecipeList` component. - * If user enter invalid command, an error message will be thrown. + - If `isAddTag`, user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to + extract + the all the recipes to be added, separated by `&&`, and pass those recipes and tag label + to `RecipeList` + component. + - If `isRemoveTag`, user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be + executed to + extract the all the recipes to be removed, separated by `&&`, and pass those recipes and tag + label to + `RecipeList` component. + - If user enter invalid command, an error message will be thrown. 3. In `RecipeList`, - * If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in - to the tag. - * If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to remove recipes - from the tag. + - If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in + to the tag. + - If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to remove recipes + from the tag. The sequence diagram below shows how this feature works: @@ -260,8 +263,8 @@ The sequence diagram below shows how this feature works: The current implementation: -* list all recipes -* list recipe with filters (name, ingredients, tags) +- list all recipes +- list recipe with filters (name, ingredients, tags) It is implemented through the following step: @@ -269,20 +272,22 @@ It is implemented through the following step: the `Parser` component. 2. In `Parser`, `parseListRecipe()` is executed to first identify whether user want to filter by tag (`/t`). - * If user filters the recipes by tag (`/t`), `isTag` is set to `true`. - * Otherwise, `isTag` is set to `false`. + + - If user filters the recipes by tag (`/t`), `isTag` is set to `true`. + - Otherwise, `isTag` is set to `false`. Then, it will extract all the filters separated by `&&`, if any. All the filters are extracted out and passed to `RecipeList`component. + 3. In `RecipeList`, `listRecipes()` is executed to first identify whether user want to filter by tag. - * If `isTag` is true, `listTagRecipes()` is called to filter all recipes that meet - all the filters by tag, and return the `recipeList` containing all relevant recipes - to `listRecipes()` - and `ParserRecipe()`, respectively. - * If user `isTag` is false, it filters all recipes that meet all the filters by name - and ingredients, and return `recipeList` containing all relevant recipes to - `ParselistRecipe()`. + - If `isTag` is true, `listTagRecipes()` is called to filter all recipes that meet + all the filters by tag, and return the `recipeList` containing all relevant recipes + to `listRecipes()` + and `ParserRecipe()`, respectively. + - If user `isTag` is false, it filters all recipes that meet all the filters by name + and ingredients, and return `recipeList` containing all relevant recipes to + `ParselistRecipe()`. The sequence diagram below shows how this feature works: @@ -292,9 +297,9 @@ The sequence diagram below shows how this feature works: The current implementation: -* deletes a single recipe by name or recipe's index in recipe list -* deletes a range of recipes -* deletes all recipes +- deletes a single recipe by name or recipe's index in recipe list +- deletes a range of recipes +- deletes all recipes It is implemented through the following step: @@ -313,7 +318,7 @@ It is implemented through the following step: The current implementation: -* Add a single recipe in 1 line and followed by all the ingredients in next another line after being +- Add a single recipe in 1 line and followed by all the ingredients in next another line after being prompted. It is implemented through the following steps: @@ -334,10 +339,10 @@ It is implemented through the following steps: The current implementation: -* There are 3 ways to edit: - * Edit all ingredients. - * Edit 1 particular ingredient. - * Add new ingredient. +- There are 3 ways to edit: + - Edit all ingredients. + - Edit 1 particular ingredient. + - Add new ingredient. It is implemented through the following steps: @@ -355,7 +360,7 @@ It is implemented through the following steps: The current implementation: -* randomly pick a recipe and display to the user +- randomly pick a recipe and display to the user It is implemented through the following step: @@ -374,22 +379,22 @@ The sequence diagram below shows how this feature works: The current implementation: -* allows for adding only 1 ingredient at a time. -* ingredient needs to have its name, quantity and expiry date specified. +- allows for adding only 1 ingredient at a time. +- ingredient needs to have its name, quantity and expiry date specified. It is implemented through the following steps: -* When the user enters an input with the first word being `add_i`, the input is passed to +- When the user enters an input with the first word being `add_i`, the input is passed to the `Parser` component. -* In `Parser`, the `parseAddUserIngredient` is executed to identify whether all the required +- In `Parser`, the `parseAddUserIngredient` is executed to identify whether all the required parameters are provided. -* If any of the parameters are missing/invalid, the user will be alerted with a relevant error +- If any of the parameters are missing/invalid, the user will be alerted with a relevant error message. -* If all the parameters are valid, the input is sent to `IngredientList` component. -* In `IngredientList`, `addIngredient()` is executed to first check if the ingredient already +- If all the parameters are valid, the input is sent to `IngredientList` component. +- In `IngredientList`, `addIngredient()` is executed to first check if the ingredient already exists in the list. -* If the ingredient already exists, the quantity of the ingredient will be updated. -* If the ingredient does not exist, the ingredient will be added to the list. +- If the ingredient already exists, the quantity of the ingredient will be updated. +- If the ingredient does not exist, the ingredient will be added to the list. The simplified sequence diagram below shows how this feature works assuming all inputs are correct: @@ -399,22 +404,22 @@ The simplified sequence diagram below shows how this feature works assuming all The current implementation: -* allows for deleting only 1 ingredient at a time. -* ingredient needs to have its name and quantity specified. +- allows for deleting only 1 ingredient at a time. +- ingredient needs to have its name and quantity specified. It is implemented through the following steps: -* When the user enters an input with the first word being `del_i`, the input is passed to +- When the user enters an input with the first word being `del_i`, the input is passed to the `Parser` component. -* In `Parser`, the `parseDeleteUserIngredient` is executed to identify whether all the required +- In `Parser`, the `parseDeleteUserIngredient` is executed to identify whether all the required parameters are provided. -* If any of the parameters are missing/invalid, the user will be alerted with a relevant error +- If any of the parameters are missing/invalid, the user will be alerted with a relevant error message. -* If all the parameters are valid, the input is sent to `IngredientList` component. -* In `IngredientList`, `deleteIngredient()` is executed to first check if the ingredient exists in +- If all the parameters are valid, the input is sent to `IngredientList` component. +- In `IngredientList`, `deleteIngredient()` is executed to first check if the ingredient exists in the list. -* If the ingredient does not exist, the user will be alerted with a relevant error message. -* If the ingredient exists and the new quantity is more than 0, the quantity of the ingredient will +- If the ingredient does not exist, the user will be alerted with a relevant error message. +- If the ingredient exists and the new quantity is more than 0, the quantity of the ingredient will be updated. Otherwise, the ingredient would be deleted entirely from the list. The sequence diagram of deleting an ingredient is similar to adding an ingredient. @@ -423,15 +428,15 @@ The sequence diagram of deleting an ingredient is similar to adding an ingredien The current implementation: -* allows for listing all ingredients in the list. +- allows for listing all ingredients in the list. It is implemented through the following steps: -* When the user enters an input with the first word being `view_ingredients`, the list of user +- When the user enters an input with the first word being `view_ingredients`, the list of user ingredients that is represented by `userIngredients` is passed to the `Ui` component. -* In `Ui`, `printUserIngredients()` first checks if the list is empty. -* If the list is empty, the user will be alerted with a relevant message and the function exits. -* If the list is not empty, the list of ingredients will be printed out, with information regarding +- In `Ui`, `printUserIngredients()` first checks if the list is empty. +- If the list is empty, the user will be alerted with a relevant message and the function exits. +- If the list is not empty, the list of ingredients will be printed out, with information regarding the names, quanntity, and expiry date of each ingredient displayed. The sequence diagram below shows how this feature works: @@ -442,28 +447,28 @@ The sequence diagram below shows how this feature works: The current implementation: -* allows for adding single recipe to the weekly meal plan. -* allows for deleting single recipe from the weekly meal plan. -* allow for adding multiple recipes to the weekly meal plan. -* allow for deleting multiple recipes from the weekly meal plan. +- allows for adding single recipe to the weekly meal plan. +- allows for deleting single recipe from the weekly meal plan. +- allow for adding multiple recipes to the weekly meal plan. +- allow for deleting multiple recipes from the weekly meal plan. It is implemented through the following steps: -* When the user enters an input with the first word being `weekly`, the input is passed to +- When the user enters an input with the first word being `weekly`, the input is passed to the `Parser` component. -* In `Parser`, the `parseWeeklyMealPlan` is executed to identify whether the user wants to +- In `Parser`, the `parseWeeklyMealPlan` is executed to identify whether the user wants to add/delete only one or multiple recipes. -* If the user wants to add/delete only one recipe, parseEditSingleWeeklyPlan() is executed. -* If the user wants to add/delete multiple recipes, parseEditMultiWeeklyPlan() is executed. -* `parseEditSingleWeeklyPlan()` and `parseEditMultiWeeklyPlan()` checks if the command parameters +- If the user wants to add/delete only one recipe, parseEditSingleWeeklyPlan() is executed. +- If the user wants to add/delete multiple recipes, parseEditMultiWeeklyPlan() is executed. +- `parseEditSingleWeeklyPlan()` and `parseEditMultiWeeklyPlan()` checks if the command parameters are valid first, then it returns the name and quantity of the recipes specified by the user. If the command parameters are invalid or the recipe is not a valid recipe, a relevant error message will be displayed. -* In `Meal360`, the second argument of the user input is then use to determine whether the user +- In `Meal360`, the second argument of the user input is then use to determine whether the user wants to add or delete the recipes. -* If the user wants to add the recipes, the list of recipe(s) would be passed to the `WeeklyPlan` +- If the user wants to add the recipes, the list of recipe(s) would be passed to the `WeeklyPlan` component to execute `addPlans()`. -* If the user wants to delete the recipes, the list of recipe(s) would be passed to the `WeeklyPlan` +- If the user wants to delete the recipes, the list of recipe(s) would be passed to the `WeeklyPlan` component to execute `deletePlans()`. The sequence diagram below shows how this feature works: @@ -474,15 +479,15 @@ The sequence diagram below shows how this feature works: The current implementation: -* allows for listing all recipes that are in the weekly plan. +- allows for listing all recipes that are in the weekly plan. It is implemented through the following steps: -* When the user enters an input with the first word being `weeklyplan`, the list of user +- When the user enters an input with the first word being `weeklyplan`, the list of user ingredients that is represented by `userIngredients` is passed to the `Ui` component. -* In `Ui`, `printUserIngredients()` first checks if the list is empty. -* If the list is empty, the user will be alerted with a relevant message and the function exits. -* If the list is not empty, the list of ingredients will be printed out, with information regarding +- In `Ui`, `printUserIngredients()` first checks if the list is empty. +- If the list is empty, the user will be alerted with a relevant message and the function exits. +- If the list is not empty, the list of ingredients will be printed out, with information regarding the names, quanntity, and expiry date of each ingredient displayed. The sequence diagram below shows how this feature works: @@ -493,23 +498,23 @@ The sequence diagram below shows how this feature works: The current implementation: -* allows for marking a recipe in the weekly plan as done. -* marking a recipe as done automatically removes the recipe and one set of its ingredients from the +- allows for marking a recipe in the weekly plan as done. +- marking a recipe as done automatically removes the recipe and one set of its ingredients from the weekly plan. It is implemented through the following steps: -* When the user enters an input with the first two word being `weekly` and `/done` respectively, the +- When the user enters an input with the first two word being `weekly` and `/done` respectively, the input is passed to the `Parser` component. -* In `Parser`, the `parseMarkDone` is executed, which then send the input to `Recipe` component to +- In `Parser`, the `parseMarkDone` is executed, which then send the input to `Recipe` component to obtain the list of ingredients of the recipe using `getIngredients()`. -* The list of ingredients is then passed to `IngredientList` component to check if the user has all +- The list of ingredients is then passed to `IngredientList` component to check if the user has all the necessary ingredients using `findIngredientCount()`. -* If the user does not have all the necessary ingredients, the user will be alerted with a relevant +- If the user does not have all the necessary ingredients, the user will be alerted with a relevant error message. -* If the user has all the necessary ingredients, the `IngredientList` component will then remove the +- If the user has all the necessary ingredients, the `IngredientList` component will then remove the ingredients from the list using `deleteIngredient()`. -* The `WeeklyPlan` component will then remove the recipe from the weekly plan using `remove()` if no +- The `WeeklyPlan` component will then remove the recipe from the weekly plan using `remove()` if no counts of the recipe is left, otherwise it will reduce the count of the recipe by 1 using `put()`. The simplified sequence diagram below shows how this feature works assuming no counts of the recipe @@ -525,12 +530,12 @@ is left after the deletion: ### Target user profile -* has a need to manage a significant number of recipes -* has a need to manage a significant number of ingredients -* has a need to manage their meal plan on a weekly basis -* can type fast -* prefers typing to mouse input -* is reasonably comfortable using CLI apps +- has a need to manage a significant number of recipes +- has a need to manage a significant number of ingredients +- has a need to manage their meal plan on a weekly basis +- can type fast +- prefers typing to mouse input +- is reasonably comfortable using CLI apps ### Value proposition @@ -539,29 +544,29 @@ driven app. ### User Stories -| Version | As a ... | I want to ... | So that I can ... | -|----------|----------|---------------------------------------------------|-------------------------------------------------------------------| -| v1.0 | user | add my own recipes to the list | refer to them when next time | -| v1.0 | user | edit the existing recipe | | -| v1.0 | user | delete a recipe from the list | clear the unused recipes | -| v1.0 | user | view ingredients of the recipe | know what is needed to be prepared | -| v1.0 | user | list all recipes I have | know what I have some idea of what to cook | -| v1.0 | user | find the recipe that contain specific ingredients | find specific recipe without having to go through the entire list | -| v1.0 | user | exit from the program | | -| v2.0 | new user | list all the command that can be used | know what command I can use | -| v2.0 | user | add meals I plan to make for the week | refer to the weekly meals plan next time | -| v2.0 | user | delete meals I plan to make for the week | remove some meals from the weekly plan if I change my mind | -| v2.0 | user | categorise recipes using tags | group recipes with similar theme together | -| v2.0 | user | list the recipes by tag | list recipes that are under the specific category | -| v2.0 | user | random a recipe | have a suggestion when do not know what to cook | -| v2.0 | user | know what ingredients I have | know what ingredients I need to buy | -| v2.0 | user | add the ingredients I have | easily track the ingredients I have | -| v2.0 | user | delete the ingredients I have | easily track the ingredients I have | -| v2.0 | user | be able to cross recipes off my weekly plan | have a neater weekly plan | +| Version | As a ... | I want to ... | So that I can ... | +| ------- | -------- | ------------------------------------------------- | ----------------------------------------------------------------- | +| v1.0 | user | add my own recipes to the list | refer to them when next time | +| v1.0 | user | edit the existing recipe | | +| v1.0 | user | delete a recipe from the list | clear the unused recipes | +| v1.0 | user | view ingredients of the recipe | know what is needed to be prepared | +| v1.0 | user | list all recipes I have | know what I have some idea of what to cook | +| v1.0 | user | find the recipe that contain specific ingredients | find specific recipe without having to go through the entire list | +| v1.0 | user | exit from the program | | +| v2.0 | new user | list all the command that can be used | know what command I can use | +| v2.0 | user | add meals I plan to make for the week | refer to the weekly meals plan next time | +| v2.0 | user | delete meals I plan to make for the week | remove some meals from the weekly plan if I change my mind | +| v2.0 | user | categorise recipes using tags | group recipes with similar theme together | +| v2.0 | user | list the recipes by tag | list recipes that are under the specific category | +| v2.0 | user | random a recipe | have a suggestion when do not know what to cook | +| v2.0 | user | know what ingredients I have | know what ingredients I need to buy | +| v2.0 | user | add the ingredients I have | easily track the ingredients I have | +| v2.0 | user | delete the ingredients I have | easily track the ingredients I have | +| v2.0 | user | be able to cross recipes off my weekly plan | have a neater weekly plan | ### Non-Functional Requirements -1. Should work on any *mainstream OS* as long as it has Java 11 or above installed. +1. Should work on any _mainstream OS_ as long as it has Java 11 or above installed. 2. The number of recipes and user ingredients is limited to only 1000 items each. 3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than @@ -570,7 +575,7 @@ driven app. ### Glossary -* **Mainstream OS**: Windows, Linux, Unix, OS-X +- **Mainstream OS**: Windows, Linux, Unix, OS-X ### Instructions for manual testing @@ -580,12 +585,13 @@ Given below are instructions to test the app manually. 1. Initial launch - 1. Download the jar file and copy into an empty folder - 2. Run the jar file using the command `java -jar meal360.jar`. The GUI similar to the below - should appear in a few seconds. The app comes with a smaall sample data of 10 recipes to - allow for easy testing. + 1. Download the jar file and copy into an empty folder + 2. Run the jar file using the command `java -jar meal360.jar`. The GUI similar to the below + should appear in a few seconds. The app comes with a smaall sample data of 10 recipes to + allow for easy testing. Expected output: + ``` ---------------------------------------------------------------------------------------------------- Welcome to Meal360, your ultimate Recipe Manager! @@ -593,7 +599,7 @@ Given below are instructions to test the app manually. | \/ |___ __ _| |__ / / / / \ | |\/| / -_) _` | ||_ \/ _ \ () | |_| |_\___\__,_|_|___/\___/\__/ - + ---------------------------------------------------------------------------------------------------- | Loading recipes... | | Recipes loaded successfully. | @@ -605,20 +611,22 @@ Given below are instructions to test the app manually. ``` 2. Shutdown - 1. A user input of `bye` allows the user to exit the app. The app will then save the data for - recipes, ingredients and weekly meal plan automatically before exiting. + + 1. A user input of `bye` allows the user to exit the app. The app will then save the data for + recipes, ingredients and weekly meal plan automatically before exiting. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | Saving recipes... | - | Recipes saved successfully. | - | Saving weekly plan... | - | Weekly plan saved successfully. | - | Saving ingredients... | - | Ingredients saved successfully. | - | Bye. Hope to see you again soon! | - ---------------------------------------------------------------------------------------------------- + + ``` + ---------------------------------------------------------------------------------------------------- + | Saving recipes... | + | Recipes saved successfully. | + | Saving weekly plan... | + | Weekly plan saved successfully. | + | Saving ingredients... | + | Ingredients saved successfully. | + | Bye. Hope to see you again soon! | + ---------------------------------------------------------------------------------------------------- ``` #### Ingredients @@ -628,6 +636,7 @@ Given below are instructions to test the app manually. into the user ingredients list. A success message should be displayed. Expected output: + ``` ---------------------------------------------------------------------------------------------------- | Ingredient successfully added! | @@ -638,22 +647,24 @@ Given below are instructions to test the app manually. Expected: The ingredient `fish` with quantity `5` should be deleted from the user ingredients. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | Ingredient successfully deleted! | - ---------------------------------------------------------------------------------------------------- - ``` + + ``` + ---------------------------------------------------------------------------------------------------- + | Ingredient successfully deleted! | + ---------------------------------------------------------------------------------------------------- + ``` 3. Test case: `view_ingredients` Expected: The list of ingredients should be displayed. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | Here is your ingredient list: | - | fish (5) [by:10/10/2024] | - ---------------------------------------------------------------------------------------------------- - ``` + + ``` + ---------------------------------------------------------------------------------------------------- + | Here is your ingredient list: | + | fish (5) [by:10/10/2024] | + ---------------------------------------------------------------------------------------------------- + ``` #### Weekly Plan @@ -662,58 +673,63 @@ Given below are instructions to test the app manually. A success message should be displayed. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | I've added the recipes to your weekly plan! | - ---------------------------------------------------------------------------------------------------- - ``` + + ``` + ---------------------------------------------------------------------------------------------------- + | I've added the recipes to your weekly plan! | + ---------------------------------------------------------------------------------------------------- + ``` 2. Test case: `weekly /delete avocado toast 1` Expected: The recipe `avocado toast` should be deleted from the weekly plan with count `1`. A success message should be displayed. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | I've deleted the recipes from your weekly plan! | - ---------------------------------------------------------------------------------------------------- - ``` + + ``` + ---------------------------------------------------------------------------------------------------- + | I've deleted the recipes from your weekly plan! | + ---------------------------------------------------------------------------------------------------- + ``` 3. Test case: `weeklyplan` Expected: The list of recipes in the weekly plan should be displayed. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | Here is your weekly plan: | - | avocado toast x1 | - ---------------------------------------------------------------------------------------------------- - ``` + + ``` + ---------------------------------------------------------------------------------------------------- + | Here is your weekly plan: | + | avocado toast x1 | + ---------------------------------------------------------------------------------------------------- + ``` 4. Test case: `weekly /multiadd /r chicken rice /q 3 /r seafood paella /q 1` Expected: The recipes `chicken rice` and `seafood paella` should be added into the weekly plan with count `3` and `1` respectively. A success message should be displayed. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | I've added the recipes to your weekly plan! | - ---------------------------------------------------------------------------------------------------- - ``` + + ``` + ---------------------------------------------------------------------------------------------------- + | I've added the recipes to your weekly plan! | + ---------------------------------------------------------------------------------------------------- + ``` 5. Test case: `weekly /multidelete /r chicken rice /q 2 /r seafood paella /q 1` Expected: The recipes `chicken rice` and `seafood paella` should be deleted from the weekly plan with count `2` and `1` respectively. A success message should be displayed. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | I've deleted the recipes from your weekly plan! | - ---------------------------------------------------------------------------------------------------- - >>> weeklyplan - ---------------------------------------------------------------------------------------------------- - | Here is your weekly plan: | - | chicken rice x1 | - | avocado toast x1 | - ---------------------------------------------------------------------------------------------------- - ``` \ No newline at end of file + + ``` + ---------------------------------------------------------------------------------------------------- + | I've deleted the recipes from your weekly plan! | + ---------------------------------------------------------------------------------------------------- + >>> weeklyplan + ---------------------------------------------------------------------------------------------------- + | Here is your weekly plan: | + | chicken rice x1 | + | avocado toast x1 | + ---------------------------------------------------------------------------------------------------- + ``` diff --git a/docs/UML/Ui class diagram b/docs/UML/Ui/Ui class diagram similarity index 100% rename from docs/UML/Ui class diagram rename to docs/UML/Ui/Ui class diagram From fa2e0370e90253c4dcc74d100312fdbb9fd9bcb0 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 01:11:43 +0800 Subject: [PATCH 183/252] Added UiClassDiagram.drawio.png --- docs/UML/Ui/UiClassDiagram.drawio.png | Bin 0 -> 32968 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/UML/Ui/UiClassDiagram.drawio.png diff --git a/docs/UML/Ui/UiClassDiagram.drawio.png b/docs/UML/Ui/UiClassDiagram.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..c6fdd4adb654d74830273be0648f4de29d7c1d34 GIT binary patch literal 32968 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 literal 0 HcmV?d00001 From e6df5329fbd36b3d375d38a0e664cbb2a8afe157 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sat, 8 Apr 2023 01:13:38 +0800 Subject: [PATCH 184/252] Ui component DG update --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 56db61121e..5c02c7e57d 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -108,7 +108,7 @@ API: `Ui.java` The `Ui` component: -![](../docs/UML/Ui/Ui%20class%20diagram) +![](../docs/UML/Ui/UiClassDiagram.drawio.png) - displays the welcome message upon startup of the program. - formats all the output to be displayed to the user. From f75de59b79541c00032c506d6101f90429a47d88 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 01:15:39 +0800 Subject: [PATCH 185/252] Added Ui_sequencediagram.drawio --- docs/UML/Ui/Untitled Diagram.drawio | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/UML/Ui/Untitled Diagram.drawio diff --git a/docs/UML/Ui/Untitled Diagram.drawio b/docs/UML/Ui/Untitled Diagram.drawio new file mode 100644 index 0000000000..0b0d588231 --- /dev/null +++ b/docs/UML/Ui/Untitled Diagram.drawio @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 575eedce84c0b822e64870f3d97b518da59aba3c Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 01:50:51 +0800 Subject: [PATCH 186/252] Added commandList.drawio.png --- docs/UML/Ui/commandList.drawio.png | Bin 0 -> 37027 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/UML/Ui/commandList.drawio.png diff --git a/docs/UML/Ui/commandList.drawio.png b/docs/UML/Ui/commandList.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..d9051723bbbe7ca0a230b36f85dc29fe9782433e GIT binary patch literal 37027 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 Wwdq?n<-r*SAn Date: Sat, 8 Apr 2023 01:53:36 +0800 Subject: [PATCH 187/252] Updated Ui component DG with UML --- docs/DeveloperGuide.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 5c02c7e57d..d310f6994a 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -116,6 +116,11 @@ The `Ui` component: - displays the error message if the command was not executed successfully. - displays the goodbye message upon receiving the `bye` command. +The sequence diagram below shows how the `Ui` component works together with `Parser` +when the user inputs `list`. + +![](../docs/UML/Ui/commandListUML.drawio.png) + ### Parser Component API: `Parser.java` From ce6baa02bfdc7dafb33bfb65a02fbfe8308555c3 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sat, 8 Apr 2023 02:27:12 +0800 Subject: [PATCH 188/252] updated UI component in DG --- docs/DeveloperGuide.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index d310f6994a..f9fc392aa7 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -119,7 +119,7 @@ The `Ui` component: The sequence diagram below shows how the `Ui` component works together with `Parser` when the user inputs `list`. -![](../docs/UML/Ui/commandListUML.drawio.png) +![](../docs/UML/Ui/commandList.drawio.png) ### Parser Component @@ -128,8 +128,11 @@ API: `Parser.java` The `Parser` component: - receives the user input from the `Meal360` component -- interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the - commands. +- checks and filters input string +- catches `exceptions` and throws error messages via `UI` to + 1. prompts user to enter valid input + 2. prevent `Meal360` from crashing upon invalid input +- interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the commands. ### Recipe Component From 29fab49fd0e9d12b61ecdd32b8d1d95b1fe4c091 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 02:31:29 +0800 Subject: [PATCH 189/252] Added parseDate.drawio --- docs/UML/parseDate.drawio | 62 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/UML/parseDate.drawio diff --git a/docs/UML/parseDate.drawio b/docs/UML/parseDate.drawio new file mode 100644 index 0000000000..e70ab47ca9 --- /dev/null +++ b/docs/UML/parseDate.drawio @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bcd406bc930a9680d7af21c763b3648199d7f893 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 03:01:51 +0800 Subject: [PATCH 190/252] Update parseDate.drawio --- docs/UML/parseDate.drawio | 121 ++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 30 deletions(-) diff --git a/docs/UML/parseDate.drawio b/docs/UML/parseDate.drawio index e70ab47ca9..b59bd0d0c7 100644 --- a/docs/UML/parseDate.drawio +++ b/docs/UML/parseDate.drawio @@ -1,61 +1,122 @@ - + - + - - + + - - + + - + + + + + + + + + + - + - - + + + + + - - + + - - + + + + + - + - + + + + + + + + + + - + + - - - + + + + + + + + + + + + + + + + + + + + + - + + + + - - - + + + + + + + + + + + + - + + + - + + + + - - - - + + + + + From ac26d0239224b3b4c9b9d75452af40ffb4262277 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 03:02:06 +0800 Subject: [PATCH 191/252] Added parseDate.drawio.png --- docs/UML/parseDate.drawio.png | Bin 0 -> 41462 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/UML/parseDate.drawio.png diff --git a/docs/UML/parseDate.drawio.png b/docs/UML/parseDate.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..7111bd7df909d70cd92a54096fcb646b9cd933a7 GIT binary patch literal 41462 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 Qe+T^NX&Y&koU*<4f9Q&@`2YX_ literal 0 HcmV?d00001 From 4a97bf1671200b7dfb73f93e3ddd8013da34c932 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sat, 8 Apr 2023 03:06:15 +0800 Subject: [PATCH 192/252] updated Parser component for DG --- docs/DeveloperGuide.md | 5 +++++ docs/UML/{ => Parser}/parseDate.drawio | 0 docs/UML/{ => Parser}/parseDate.drawio.png | Bin 3 files changed, 5 insertions(+) rename docs/UML/{ => Parser}/parseDate.drawio (100%) rename docs/UML/{ => Parser}/parseDate.drawio.png (100%) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f9fc392aa7..01da28b442 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -134,6 +134,11 @@ The `Parser` component: 2. prevent `Meal360` from crashing upon invalid input - interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the commands. +The sequence diagram below shows how `Parser` filters user input dates and parses them +as valid `LocalDate` objects. + +![](../docs/UML/Parser/parseDate.drawio.png) + ### Recipe Component API: `Recipe.java` diff --git a/docs/UML/parseDate.drawio b/docs/UML/Parser/parseDate.drawio similarity index 100% rename from docs/UML/parseDate.drawio rename to docs/UML/Parser/parseDate.drawio diff --git a/docs/UML/parseDate.drawio.png b/docs/UML/Parser/parseDate.drawio.png similarity index 100% rename from docs/UML/parseDate.drawio.png rename to docs/UML/Parser/parseDate.drawio.png From 243342f916ab2c02b25f0bde08549bd73ca52fe1 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 03:17:29 +0800 Subject: [PATCH 193/252] Update parseDate.drawio --- docs/UML/parseDate.drawio | 150 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 docs/UML/parseDate.drawio diff --git a/docs/UML/parseDate.drawio b/docs/UML/parseDate.drawio new file mode 100644 index 0000000000..cde32f7942 --- /dev/null +++ b/docs/UML/parseDate.drawio @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4a77a5612ecaf0d71e82ec0c0e01a855bfe4ec50 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sat, 8 Apr 2023 03:19:03 +0800 Subject: [PATCH 194/252] Update parseDate.drawio --- docs/UML/parseDate.drawio | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/UML/parseDate.drawio b/docs/UML/parseDate.drawio index cde32f7942..c62f023d5f 100644 --- a/docs/UML/parseDate.drawio +++ b/docs/UML/parseDate.drawio @@ -1,4 +1,4 @@ - + @@ -123,14 +123,22 @@ - - + + - + + + + + + + + + From 84df99ebfd4b87b65aed1ca0eb6fd51a7b44ac91 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sat, 8 Apr 2023 04:59:16 +0800 Subject: [PATCH 195/252] fixed issue where it is possible to have empty string as ingredient name --- src/main/java/seedu/meal360/Parser.java | 280 ++++++++++++------------ 1 file changed, 146 insertions(+), 134 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index e6451168ae..8531465b61 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -28,47 +28,58 @@ public String combineWords(String[] input, int startIndex, int length) { return word.toString(); } - //@@author jaredoong + // @@author jaredoong public String[] cleanUserInput(String input) { input = input.replaceAll("\\s+", " "); input = input.toLowerCase(); return input.trim().split(" "); } - //@@author - public HashMap parseIngredientName(String[] command) { + // @@author + /** + * Parses an array of strings representing ingredients and their quantities. + * + * @param commands an array of strings in the format "name=quantity" + * @return a map of ingredient names to their quantities + * @throws IllegalArgumentException if an ingredient quantity is negative or an + * ingredient name is empty + */ + public HashMap parseIngredientName(String[] commands) { HashMap ingredients = new HashMap<>(); int flag = 0; - StringBuilder add = null; - String ingredientName; - int ingredientQuantity; - int indexOfEqual; - - for (String s : command) { - indexOfEqual = s.indexOf("="); - if(s.charAt(indexOfEqual+1) == '-'){ - throw new IllegalArgumentException(); - } + String currentIngredient = null; + + for (String command : commands) { + int indexOfEqual = command.indexOf("="); if (indexOfEqual == -1) { - if (add != null) { - add.append(" ").append(s); + if (command.isEmpty()) { + continue; + } + if (currentIngredient != null) { + currentIngredient += " " + command; } else { - add = new StringBuilder(s); + currentIngredient = command; } flag++; } else { if (flag > 0) { - indexOfEqual = s.indexOf("="); - ingredientName = (s.substring(0, indexOfEqual)); - ingredientName = add + " " + ingredientName; - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + currentIngredient += " " + command.substring(0, indexOfEqual); flag = 0; - add = null; } else { - ingredientName = s.substring(0, indexOfEqual); - ingredientQuantity = Integer.parseInt(s.substring(indexOfEqual + 1)); + currentIngredient = command.substring(0, indexOfEqual); + } + String quantityString = command.substring(indexOfEqual + 1); + if (quantityString.isEmpty()) { + throw new IllegalArgumentException("Ingredient quantity cannot be empty"); + } + int quantity = Integer.parseInt(quantityString); + if (quantity < 0) { + throw new IllegalArgumentException("Ingredient quantity cannot be negative"); } - ingredients.put(ingredientName, ingredientQuantity); + if (currentIngredient.isEmpty()) { + throw new IllegalArgumentException("Ingredient name cannot be empty"); + } + ingredients.put(currentIngredient, quantity); } } return ingredients; @@ -79,18 +90,18 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { String recipeName = combineWords(input, 2, input.length); if (recipeList.findByName(recipeName) != null) { return null; - } else if(!Objects.equals(input[1], "/r")){ + } else if (!Objects.equals(input[1], "/r")) { throw new ArrayIndexOutOfBoundsException(); } HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); - System.out.println("Please Enter The Ingredients & Quantity: "); + System.out.println("Please Enter The Ingredients & Quantity (enter \"done\" when complete): "); while (true) { - try{ + try { String line = userInput.nextLine(); if (line.equals("done")) { ui.printSeparator(); - if(addedIngredient==0 || ingredients.size()==0) { + if (addedIngredient == 0 || ingredients.size() == 0) { ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { @@ -100,15 +111,15 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { addedIngredient = 1; String[] command = line.trim().split(" "); ingredients = parseIngredientName(command); - if(ingredients.size()==0){ + if (ingredients.size() == 0) { ui.printSeparator(); ui.printMessage(recipeErrorMessage); ui.printSeparator(); } } - } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + } catch (IllegalArgumentException e) { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(e.getMessage()); ui.printSeparator(); } } @@ -131,17 +142,17 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); int index; Scanner getNum = new Scanner(System.in); - while(true){ - try{ + while (true) { + try { index = Integer.parseInt(getNum.nextLine()); - if(index <1 || index>3){ + if (index < 1 || index > 3) { ui.printSeparator(); ui.printMessage("Index cannot be negative or out of bounds!"); ui.printSeparator(); - } else{ + } else { break; } - } catch(NumberFormatException e){ + } catch (NumberFormatException e) { ui.printSeparator(); ui.printMessage("Enter valid index for respective editing options!"); ui.printSeparator(); @@ -150,11 +161,11 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { if (index == 1) { System.out.println("Please Enter New Ingredients & Quantity: "); while (true) { - try{ + try { String line = userInput.nextLine(); if (line.equals("done")) { ui.printSeparator(); - if(addedIngredient==0 || ingredients.size()==0) { + if (addedIngredient == 0 || ingredients.size() == 0) { ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { @@ -164,15 +175,15 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { addedIngredient = 1; String[] command = line.trim().split(" "); ingredients = parseIngredientName(command); - if(ingredients.size()!=0){ + if (ingredients.size() != 0) { recipeList.editRecipe(recipeToEdit, ingredients); - } else{ + } else { ui.printSeparator(); ui.printMessage(recipeErrorMessage); ui.printSeparator(); } } - } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { ui.printSeparator(); ui.printMessage(recipeErrorMessage); ui.printSeparator(); @@ -187,17 +198,17 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { System.out.println("Which ingredient do you want to change?"); int ingredientIndex = 0; Scanner getIndex = new Scanner(System.in); - while(true){ - try{ + while (true) { + try { ingredientIndex = Integer.parseInt(getIndex.nextLine()); - if(ingredientIndex <=0 || ingredientIndex > recipe.getNumOfIngredients()){ + if (ingredientIndex <= 0 || ingredientIndex > recipe.getNumOfIngredients()) { ui.printSeparator(); ui.printMessage("Index cannot be negative or out of bounds!"); ui.printSeparator(); - } else{ + } else { break; } - } catch(NumberFormatException e){ + } catch (NumberFormatException e) { ui.printSeparator(); ui.printMessage("Enter valid ingredient index!"); ui.printSeparator(); @@ -221,16 +232,16 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } System.out.println("Please enter the new ingredient:"); - while(true){ - try{ + while (true) { + try { String line = userInput.nextLine(); String command = line.replaceAll("\\s+", " "); int indexOfEqual = command.indexOf("="); - if(command.charAt(indexOfEqual + 1) == '-'){ + if (command.charAt(indexOfEqual + 1) == '-') { ui.printSeparator(); ui.printMessage("Invalid ingredient quantity!"); ui.printSeparator(); - } else{ + } else { String newIngredientName = command.substring(0, indexOfEqual); int newIngredientQuantity = Integer.parseInt(command.substring(indexOfEqual + 1)); recipeToEdit.getIngredients().remove(ingredientToRemove); @@ -238,7 +249,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { recipeList.editRecipe(recipeToEdit, recipeToEdit.getIngredients()); break; } - } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { ui.printSeparator(); ui.printMessage(recipeErrorMessage); ui.printSeparator(); @@ -253,11 +264,11 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { ui.printSeparator(); System.out.println("Please Enter Additional Ingredients & Quantity: "); while (true) { - try{ + try { String line = userInput.nextLine(); if (line.equals("done")) { ui.printSeparator(); - if(addedIngredient==0 || ingredients.size()==0) { + if (addedIngredient == 0 || ingredients.size() == 0) { ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { @@ -268,15 +279,15 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" "); ingredients = parseIngredientName(command); newIngredientList.putAll(ingredients); - if(ingredients.size()!=0){ + if (ingredients.size() != 0) { recipeList.editRecipe(recipeToEdit, newIngredientList); - } else{ + } else { ui.printSeparator(); ui.printMessage(recipeErrorMessage); ui.printSeparator(); } } - } catch(IllegalArgumentException | StringIndexOutOfBoundsException e){ + } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { ui.printSeparator(); ui.printMessage(recipeErrorMessage); ui.printSeparator(); @@ -292,7 +303,7 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { if (!input[1].equals("/r") && !input[1].contains("-")) { Integer.parseInt(input[1]); } - } catch (NumberFormatException e){ + } catch (NumberFormatException e) { throw new IndexOutOfBoundsException(); } if (input[1].contains("/r")) { @@ -342,7 +353,8 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2))); return rangeRecipes; } else { - int recipeIndex = Integer.parseInt(input[1]);; + int recipeIndex = Integer.parseInt(input[1]); + ; recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based return recipeList.deleteRecipe(recipeIndex - 1).getName(); @@ -489,7 +501,7 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { return recipeListToPrint; } - //@@author jaredoong + // @@author jaredoong public Recipe parseViewRecipe(String[] command, RecipeList recipes) { assert command[0].equals("view"); Recipe requestedRecipe; @@ -514,7 +526,7 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { return requestedRecipe; } - //@@author + // @@author public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { int recipeIndex = 1; for (Recipe recipe : recipes) { @@ -533,27 +545,27 @@ public Recipe parseRandomRecipe(RecipeList recipes) throws NullPointerException return recipes.randomRecipe(); } - //@@author jaredoong + // @@author jaredoong public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) throws ArrayIndexOutOfBoundsException, NumberFormatException, InvalidRecipeNameException, InvalidValueException { WeeklyPlan updatedWeeklyPlan; switch (command[1]) { - case "/add": - case "/delete": - updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); - break; - case "/multiadd": - case "/multidelete": - updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); - break; - case "/clear": - updatedWeeklyPlan = new WeeklyPlan(); - break; - default: - throw new IllegalArgumentException( - "Please indicate if you would want to add to, delete from, or clear the weekly " - + "plan."); + case "/add": + case "/delete": + updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + case "/multidelete": + updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); + break; + case "/clear": + updatedWeeklyPlan = new WeeklyPlan(); + break; + default: + throw new IllegalArgumentException( + "Please indicate if you would want to add to, delete from, or clear the weekly " + + "plan."); } return updatedWeeklyPlan; @@ -665,18 +677,20 @@ private StringBuilder getRecipeNames(String[] command, ArrayList recipeN return recipeName; } - //@@author + // @@author // parser to read dd/mm/yyyy format as local date catching invalid date format public LocalDate parseDate(String input) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + LocalDate date = null; try { - return LocalDate.parse(input, formatter); + date = LocalDate.parse(input, formatter); + return date; } catch (DateTimeParseException e) { throw new IllegalArgumentException("Please enter a valid date in the format dd/mm/yyyy."); } } - //@@author jaredoong + // @@author jaredoong public void parseAddUserIngredients(String[] command, IngredientList ingredientList) throws InvalidValueException { String ingredientName = null; @@ -685,36 +699,36 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL for (int i = 1; i < command.length; i++) { switch (command[i]) { - case "/n": - StringBuilder nameBuilder = new StringBuilder(); - while (++i < command.length && !command[i].startsWith("/")) { - if (nameBuilder.length() > 0) { - nameBuilder.append(" "); + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); + } + nameBuilder.append(command[i]); + } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); } - nameBuilder.append(command[i]); - } - ingredientName = nameBuilder.toString(); - i--; // Move back to the previous flag - break; - case "/c": - try { - ingredientCount = Integer.parseInt(command[++i]); - } catch (NumberFormatException e) { - throw new NumberFormatException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } - if (ingredientCount < 1 || ingredientCount > 1000) { - throw new InvalidValueException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } - break; - case "/d": - expiryDate = command[++i]; - break; - default: - throw new IllegalArgumentException("Missing required information. Please provide " - + "ingredient name, count, and expiry date."); + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + break; + case "/d": + expiryDate = command[++i]; + break; + default: + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name, count, and expiry date."); } } @@ -725,7 +739,6 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL ingredientList.addIngredient(new Ingredient(ingredientName, ingredientCount, expiryDate)); } - public void parseDeleteUserIngredients(String[] command, IngredientList userIngredients) throws IngredientNotFoundException, InvalidValueException { String ingredientName = null; @@ -733,33 +746,33 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr for (int i = 1; i < command.length; i++) { switch (command[i]) { - case "/n": - StringBuilder nameBuilder = new StringBuilder(); - while (++i < command.length && !command[i].startsWith("/")) { - if (nameBuilder.length() > 0) { - nameBuilder.append(" "); + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); + } + nameBuilder.append(command[i]); + } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); } - nameBuilder.append(command[i]); - } - ingredientName = nameBuilder.toString(); - i--; // Move back to the previous flag - break; - case "/c": - try { - ingredientCount = Integer.parseInt(command[++i]); - } catch (NumberFormatException e) { - throw new NumberFormatException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } - if (ingredientCount < 1 || ingredientCount > 1000) { - throw new InvalidValueException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } - break; - default: - throw new IllegalArgumentException( - "Missing required information. Please provide " + "ingredient name and count."); + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + break; + default: + throw new IllegalArgumentException( + "Missing required information. Please provide " + "ingredient name and count."); } } @@ -770,7 +783,6 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr userIngredients.deleteIngredient(ingredientName, ingredientCount); } - public void parseMarkDone(String[] command, IngredientList userIngredients, WeeklyPlan weeklyPlan, RecipeList recipes) throws IngredientNotFoundException, InvalidRecipeNameException { if (command.length == 2) { From 3bdf0000ceeb8252a47dc42a1f302c87448c40b9 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sat, 8 Apr 2023 05:02:08 +0800 Subject: [PATCH 196/252] checkstyle update --- src/main/java/seedu/meal360/Parser.java | 142 ++++++++++++------------ 1 file changed, 72 insertions(+), 70 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 8531465b61..49239a141a 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Objects; import java.util.Scanner; + import seedu.meal360.exceptions.IngredientNotFoundException; import seedu.meal360.exceptions.InvalidValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; @@ -36,6 +37,7 @@ public String[] cleanUserInput(String input) { } // @@author + /** * Parses an array of strings representing ingredients and their quantities. * @@ -551,21 +553,21 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) InvalidValueException { WeeklyPlan updatedWeeklyPlan; switch (command[1]) { - case "/add": - case "/delete": - updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); - break; - case "/multiadd": - case "/multidelete": - updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); - break; - case "/clear": - updatedWeeklyPlan = new WeeklyPlan(); - break; - default: - throw new IllegalArgumentException( - "Please indicate if you would want to add to, delete from, or clear the weekly " - + "plan."); + case "/add": + case "/delete": + updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + case "/multidelete": + updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); + break; + case "/clear": + updatedWeeklyPlan = new WeeklyPlan(); + break; + default: + throw new IllegalArgumentException( + "Please indicate if you would want to add to, delete from, or clear the weekly " + + "plan."); } return updatedWeeklyPlan; @@ -667,7 +669,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, - StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { + StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { recipeName.append(command[nameStartIndex].toLowerCase().trim()); for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { recipeName.append(" ").append(command[j].toLowerCase().trim()); @@ -699,36 +701,36 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL for (int i = 1; i < command.length; i++) { switch (command[i]) { - case "/n": - StringBuilder nameBuilder = new StringBuilder(); - while (++i < command.length && !command[i].startsWith("/")) { - if (nameBuilder.length() > 0) { - nameBuilder.append(" "); - } - nameBuilder.append(command[i]); - } - ingredientName = nameBuilder.toString(); - i--; // Move back to the previous flag - break; - case "/c": - try { - ingredientCount = Integer.parseInt(command[++i]); - } catch (NumberFormatException e) { - throw new NumberFormatException( - "Please enter a positive number between 1 to 1000 for the quantity."); + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); } + nameBuilder.append(command[i]); + } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } - if (ingredientCount < 1 || ingredientCount > 1000) { - throw new InvalidValueException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } - break; - case "/d": - expiryDate = command[++i]; - break; - default: - throw new IllegalArgumentException("Missing required information. Please provide " - + "ingredient name, count, and expiry date."); + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + break; + case "/d": + expiryDate = command[++i]; + break; + default: + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name, count, and expiry date."); } } @@ -746,33 +748,33 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr for (int i = 1; i < command.length; i++) { switch (command[i]) { - case "/n": - StringBuilder nameBuilder = new StringBuilder(); - while (++i < command.length && !command[i].startsWith("/")) { - if (nameBuilder.length() > 0) { - nameBuilder.append(" "); - } - nameBuilder.append(command[i]); - } - ingredientName = nameBuilder.toString(); - i--; // Move back to the previous flag - break; - case "/c": - try { - ingredientCount = Integer.parseInt(command[++i]); - } catch (NumberFormatException e) { - throw new NumberFormatException( - "Please enter a positive number between 1 to 1000 for the quantity."); + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); } + nameBuilder.append(command[i]); + } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } - if (ingredientCount < 1 || ingredientCount > 1000) { - throw new InvalidValueException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } - break; - default: - throw new IllegalArgumentException( - "Missing required information. Please provide " + "ingredient name and count."); + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + break; + default: + throw new IllegalArgumentException( + "Missing required information. Please provide " + "ingredient name and count."); } } @@ -784,7 +786,7 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr } public void parseMarkDone(String[] command, IngredientList userIngredients, WeeklyPlan weeklyPlan, - RecipeList recipes) throws IngredientNotFoundException, InvalidRecipeNameException { + RecipeList recipes) throws IngredientNotFoundException, InvalidRecipeNameException { if (command.length == 2) { throw new IllegalArgumentException("Please enter a recipe name."); } From 7a5f7650caa0571809f9a717518302a9ceced515 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Sat, 8 Apr 2023 09:30:54 +0800 Subject: [PATCH 197/252] update exception --- src/main/java/seedu/meal360/Meal360.java | 16 +- src/main/java/seedu/meal360/Parser.java | 38 +-- src/main/java/seedu/meal360/RecipeList.java | 33 ++- src/main/java/seedu/meal360/Ui.java | 7 +- .../meal360/exceptions/NoRecipeException.java | 7 + .../RecipeNotFoundInTagException.java | 7 + .../exceptions/TagNotFoundException.java | 7 + src/test/java/seedu/meal360/Meal360Test.java | 230 ++++++++++-------- 8 files changed, 205 insertions(+), 140 deletions(-) create mode 100644 src/main/java/seedu/meal360/exceptions/NoRecipeException.java create mode 100644 src/main/java/seedu/meal360/exceptions/RecipeNotFoundInTagException.java create mode 100644 src/main/java/seedu/meal360/exceptions/TagNotFoundException.java diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 32e8b63ae1..24b6df7588 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -2,9 +2,13 @@ import java.io.IOException; import java.util.Scanner; + import seedu.meal360.exceptions.IngredientNotFoundException; -import seedu.meal360.exceptions.InvalidValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; +import seedu.meal360.exceptions.InvalidValueException; +import seedu.meal360.exceptions.NoRecipeException; +import seedu.meal360.exceptions.RecipeNotFoundInTagException; +import seedu.meal360.exceptions.TagNotFoundException; import seedu.meal360.storage.Database; public class Meal360 { @@ -100,7 +104,8 @@ public static void receiveInput(String input) { ui.printSeparator(); RecipeList recipeListToPrint = parser.parseListRecipe(command, recipeList); ui.listRecipe(recipeListToPrint); - } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { + } catch (TagNotFoundException | NoRecipeException | IllegalArgumentException | IndexOutOfBoundsException + | NullPointerException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -147,8 +152,8 @@ public static void receiveInput(String input) { ui.printSeparator(); String returnMessage = parser.parseTagRecipe(command, recipeList); ui.printTagMessage(returnMessage); - //ui.printMessage("You have modified the recipe(s) in this \"" + tag + "\" tag."); - } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException | + RecipeNotFoundInTagException | TagNotFoundException | NoRecipeException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -156,8 +161,9 @@ public static void receiveInput(String input) { ui.printSeparator(); try { Recipe randomRecipe = parser.parseRandomRecipe(recipeList); + ui.printRandomMessage(); ui.printRecipe(randomRecipe); - } catch (NumberFormatException | IndexOutOfBoundsException | NullPointerException e) { + } catch (NoRecipeException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index e6451168ae..5ed8a86472 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -4,9 +4,13 @@ import java.util.HashMap; import java.util.Objects; import java.util.Scanner; + import seedu.meal360.exceptions.IngredientNotFoundException; -import seedu.meal360.exceptions.InvalidValueException; import seedu.meal360.exceptions.InvalidRecipeNameException; +import seedu.meal360.exceptions.InvalidValueException; +import seedu.meal360.exceptions.NoRecipeException; +import seedu.meal360.exceptions.RecipeNotFoundInTagException; +import seedu.meal360.exceptions.TagNotFoundException; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; @@ -350,7 +354,8 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } } - public String parseTagRecipe(String[] inputs, RecipeList recipeList) { + public String parseTagRecipe(String[] inputs, RecipeList recipeList) throws RecipeNotFoundInTagException, + TagNotFoundException, NoRecipeException { String returnMessage; String tag; boolean isOnlyTagWordInCommand = inputs.length == 1; @@ -368,7 +373,6 @@ public String parseTagRecipe(String[] inputs, RecipeList recipeList) { isAddTag = commandString.indexOf(">>") == -1 && commandString.indexOf("<<") != -1; isRemoveTag = commandString.indexOf("<<") == -1 && commandString.indexOf(">>") != -1; - if (!(isAddTag || isRemoveTag)) { throw new IllegalArgumentException("Please enter the command in the correct format."); } else if (isAddTag) { @@ -383,7 +387,7 @@ public String parseTagRecipe(String[] inputs, RecipeList recipeList) { return returnMessage; } - public String parseAddRecipeTag(String command, RecipeList recipeList) throws IndexOutOfBoundsException { + public String parseAddRecipeTag(String command, RecipeList recipeList) throws NoRecipeException { String tag; Recipe recipe; String[] recipesToTag; @@ -405,15 +409,15 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) throws In String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + " tag."; String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + "successfully added from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + throw new NoRecipeException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } recipeList.addRecipeToTag(tag, recipe); } return tag; } - public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws IndexOutOfBoundsException { + public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws RecipeNotFoundInTagException, + TagNotFoundException, NoRecipeException { String tag; Recipe recipe; String[] recipesToRemove; @@ -429,8 +433,7 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws tag = args[0].trim(); isUnableToFindTag = !recipeList.tags.containsKey(tag); if (isUnableToFindTag) { - throw new IndexOutOfBoundsException( - "There is no \"" + tag + "\" tag found. Please make sure you have " + throw new TagNotFoundException("There is no \"" + tag + "\" tag found. Please make sure you have " + "entered the correct tag."); } @@ -443,24 +446,23 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + " tag."; String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + "successfully removed from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + throw new NoRecipeException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } try { recipeList.removeRecipeFromTag(tag, recipe); - } catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException | RecipeNotFoundInTagException e) { String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + " tag."; String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + "successfully removed from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + throw new RecipeNotFoundInTagException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } } return tag; } - public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { + public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) throws TagNotFoundException, + NoRecipeException { String[] filters; RecipeList recipeListToPrint; boolean hasTagArgs = inputs.length > 2; @@ -473,7 +475,7 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) { } else { isTag = inputs[1].equals("/t"); if (isTag && !hasTagArgs) { - throw new IllegalArgumentException("Please include at least a tag."); + throw new TagNotFoundException("Please include at least a tag."); } else if (isTag) { firstArgsIndex = 2; } @@ -526,9 +528,9 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { return recipes.get(recipeIndex - 1); } - public Recipe parseRandomRecipe(RecipeList recipes) throws NullPointerException { + public Recipe parseRandomRecipe(RecipeList recipes) throws NoRecipeException { if (recipes.size() == 0) { - throw new NullPointerException("There is no recipe in the list for random."); + throw new NoRecipeException("There is no recipe in the list for random."); } return recipes.randomRecipe(); } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index c05e6d7fed..a121118e12 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -1,5 +1,9 @@ package seedu.meal360; +import seedu.meal360.exceptions.NoRecipeException; +import seedu.meal360.exceptions.RecipeNotFoundInTagException; +import seedu.meal360.exceptions.TagNotFoundException; + import java.util.ArrayList; import java.util.HashMap; import java.util.Random; @@ -46,34 +50,28 @@ public void addRecipeToTag(String tag, Recipe recipe) { } } - public void removeRecipeFromTag(String tag, Recipe recipe) { + public void removeRecipeFromTag(String tag, Recipe recipe) throws RecipeNotFoundInTagException { HashMap tagRecipeList = tags.get(tag); boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); if (!isAbleToFindTheRecipe) { - String errorMessage1 = - "Unable to find the recipe: \"" + recipe.getName() + "\" in the" + - " tag."; - String errorMessage2 = - "All the recipe before \"" + recipe.getName() + "\" (if any) are " + - "successfully removed from the tag."; - throw new IndexOutOfBoundsException( - String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + String errorMessage1 = "Unable to find the recipe: \"" + recipe.getName() + "\" in the" + " tag."; + String errorMessage2 = "All the recipe before \"" + recipe.getName() + "\" (if any) are " + + "successfully removed from the tag."; + throw new RecipeNotFoundInTagException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } tagRecipeList.remove(recipe); } - public RecipeList listRecipes(String[] filters, boolean isTag) { + public RecipeList listRecipes(String[] filters, boolean isTag) throws TagNotFoundException, NoRecipeException { RecipeList filteredRecipeList = new RecipeList(); boolean isNoFilter = filters == null; boolean isNotPassTheFilter; if (isTag) { filteredRecipeList = this.listTagRecipes(filters); - } - if (!isTag && isNoFilter) { + } else if (!isTag && isNoFilter) { return this; - } - if (!isTag) { + } else if (!isTag) { for (Recipe recipe : this) { filteredRecipeList.add(recipe); for (String filter : filters) { @@ -89,7 +87,7 @@ public RecipeList listRecipes(String[] filters, boolean isTag) { return filteredRecipeList; } - public RecipeList listTagRecipes(String[] filters) { + public RecipeList listTagRecipes(String[] filters) throws TagNotFoundException, NoRecipeException { RecipeList filteredRecipeList = new RecipeList(); HashMap tagRecipes; boolean hasNoRecipeInTheTag; @@ -99,8 +97,7 @@ public RecipeList listTagRecipes(String[] filters) { // add all recipe from first tag to the list isNotFoundTag = !this.tags.containsKey(filters[0].trim()); if (isNotFoundTag) { - throw new NullPointerException( - "There is no \"" + filters[0] + "\" tag found. Please make sure you have " + + throw new TagNotFoundException("There is no \"" + filters[0] + "\" tag found. Please make sure you have " + "entered the correct tag."); } this.tags.get(filters[0].trim()).forEach((recipe, dummy) -> filteredRecipeList.add(recipe)); @@ -112,7 +109,7 @@ public RecipeList listTagRecipes(String[] filters) { hasNoRecipeToReturn = filteredRecipeList.size() == 0; if (hasNoRecipeInTheTag) { - throw new NullPointerException("There is nothing to list."); + throw new NoRecipeException("There is nothing to list."); } if (hasNoRecipeToReturn) { return filteredRecipeList; diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index a109732e5f..db26b87344 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -82,8 +82,7 @@ public void listAvailableRecipes(RecipeList recipeListToPrint) { "These are the recipes you can cook"); } - private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, - String listHeaderMsg) { + private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, String listHeaderMsg) { int numberOfRecipes = recipeListToPrint.size(); int order = 0; if (numberOfRecipes == 0) { @@ -160,4 +159,8 @@ public void printSuccessfullyAddTag(String tag) { public void printSuccessfullyRemoveTag(String tag) { printMessage("You have successfully removed the recipe(s) from \"" + tag + "\" tag."); } + + public void printRandomMessage() { + printMessage("Random Result....."); + } } diff --git a/src/main/java/seedu/meal360/exceptions/NoRecipeException.java b/src/main/java/seedu/meal360/exceptions/NoRecipeException.java new file mode 100644 index 0000000000..af2d783f06 --- /dev/null +++ b/src/main/java/seedu/meal360/exceptions/NoRecipeException.java @@ -0,0 +1,7 @@ +package seedu.meal360.exceptions; + +public class NoRecipeException extends Exception { + public NoRecipeException(String message) { + super(message); + } +} diff --git a/src/main/java/seedu/meal360/exceptions/RecipeNotFoundInTagException.java b/src/main/java/seedu/meal360/exceptions/RecipeNotFoundInTagException.java new file mode 100644 index 0000000000..21be98b159 --- /dev/null +++ b/src/main/java/seedu/meal360/exceptions/RecipeNotFoundInTagException.java @@ -0,0 +1,7 @@ +package seedu.meal360.exceptions; + +public class RecipeNotFoundInTagException extends Exception{ + public RecipeNotFoundInTagException(String message) { + super(message); + } +} diff --git a/src/main/java/seedu/meal360/exceptions/TagNotFoundException.java b/src/main/java/seedu/meal360/exceptions/TagNotFoundException.java new file mode 100644 index 0000000000..b76e2a9a18 --- /dev/null +++ b/src/main/java/seedu/meal360/exceptions/TagNotFoundException.java @@ -0,0 +1,7 @@ +package seedu.meal360.exceptions; + +public class TagNotFoundException extends Exception { + public TagNotFoundException(String message) { + super(message); + } +} diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index b9fe8534c9..28603e6997 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -16,6 +16,9 @@ import seedu.meal360.exceptions.IngredientNotFoundException; import seedu.meal360.exceptions.InvalidRecipeNameException; import seedu.meal360.exceptions.InvalidValueException; +import seedu.meal360.exceptions.NoRecipeException; +import seedu.meal360.exceptions.RecipeNotFoundInTagException; +import seedu.meal360.exceptions.TagNotFoundException; import seedu.meal360.storage.Database; class Meal360Test { @@ -838,8 +841,7 @@ public void testViewNonEmptyWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); weeklyPlan.put("salad", 1); ui.printWeeklyPlan(weeklyPlan); - assertEquals( - ui.formatMessage("Here is your weekly plan:") + System.lineSeparator() + ui.formatMessage( + assertEquals(ui.formatMessage("Here is your weekly plan:") + System.lineSeparator() + ui.formatMessage( "salad x1"), outContent.toString().trim()); } @@ -849,89 +851,106 @@ public void testListRecipe() { RecipeList recipeListToPrint; String[] inputs; - inputs = new String[]{"list"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(4, recipeListToPrint.size()); - assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); - assertEquals(4, recipeListToPrint.get(1).getNumOfIngredients()); - assertEquals(3, recipeListToPrint.get(2).getNumOfIngredients()); - - inputs = new String[]{"list", "tomato", "sauce"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(1, recipeListToPrint.size()); - assertEquals(4, recipeListToPrint.get(0).getNumOfIngredients()); - assertEquals("pizza", recipeListToPrint.get(0).getName()); - - inputs = new String[]{"list", "salad", "&&", "tomato"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(1, recipeListToPrint.size()); - assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); - assertEquals("salad", recipeListToPrint.get(0).getName()); - - inputs = new String[]{"list", "salad", "&&", "pizza"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(0, recipeListToPrint.size()); + try { + inputs = new String[]{"list"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(4, recipeListToPrint.size()); + assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); + assertEquals(4, recipeListToPrint.get(1).getNumOfIngredients()); + assertEquals(3, recipeListToPrint.get(2).getNumOfIngredients()); + + inputs = new String[]{"list", "tomato", "sauce"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(1, recipeListToPrint.size()); + assertEquals(4, recipeListToPrint.get(0).getNumOfIngredients()); + assertEquals("pizza", recipeListToPrint.get(0).getName()); + + inputs = new String[]{"list", "salad", "&&", "tomato"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(1, recipeListToPrint.size()); + assertEquals(3, recipeListToPrint.get(0).getNumOfIngredients()); + assertEquals("salad", recipeListToPrint.get(0).getName()); + + inputs = new String[]{"list", "salad", "&&", "pizza"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(0, recipeListToPrint.size()); + } catch (Exception e) { + assert false; + } } @Test public void testListTagAndAddTag() { - RecipeList recipeListToPrint; - String[] inputs; - // check add tag (1) - String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; - parser.parseTagRecipe(addTagInputs, recipes); - - // check list tag (1) - inputs = new String[]{"list", "/t", "breakfast"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(recipeListToPrint.size(), 1); - assertEquals(recipeListToPrint.get(0).getName(), "salad"); - - // add tag (2) - addTagInputs = new String[]{"tag", "breakfast", "<<", "pizza"}; - parser.parseTagRecipe(addTagInputs, recipes); - - addTagInputs = new String[]{"tag", "western", "<<", "burger"}; - parser.parseTagRecipe(addTagInputs, recipes); - - // list tag (2) - inputs = new String[]{"list", "/t", "breakfast"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(recipeListToPrint.size(), 2); - - inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(recipeListToPrint.size(), 0); - - // add tag (3) - addTagInputs = new String[]{"tag", "western", "<<", "pizza"}; - parser.parseTagRecipe(addTagInputs, recipes); - - // list tag (3) - inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; - recipeListToPrint = parser.parseListRecipe(inputs, recipes); - assertEquals(recipeListToPrint.size(), 1); - assertEquals(recipeListToPrint.get(0).getName(), "pizza"); + try { + RecipeList recipeListToPrint; + String[] inputs; + // check add tag (1) + String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; + parser.parseTagRecipe(addTagInputs, recipes); + + // check list tag (1) + inputs = new String[]{"list", "/t", "breakfast"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 1); + assertEquals(recipeListToPrint.get(0).getName(), "salad"); + + // add tag (2) + addTagInputs = new String[]{"tag", "breakfast", "<<", "pizza"}; + parser.parseTagRecipe(addTagInputs, recipes); + + addTagInputs = new String[]{"tag", "western", "<<", "burger"}; + parser.parseTagRecipe(addTagInputs, recipes); + + // list tag (2) + inputs = new String[]{"list", "/t", "breakfast"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 2); + + inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 0); + + // add tag (3) + addTagInputs = new String[]{"tag", "western", "<<", "pizza"}; + parser.parseTagRecipe(addTagInputs, recipes); + + // list tag (3) + inputs = new String[]{"list", "/t", "breakfast", "&&", "western"}; + recipeListToPrint = parser.parseListRecipe(inputs, recipes); + assertEquals(recipeListToPrint.size(), 1); + assertEquals(recipeListToPrint.get(0).getName(), "pizza"); + } catch (Exception e) { + assert false; + } } @Test public void testPrintAddTagMessage() { String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; - String addTagReturnMessage = parser.parseTagRecipe(addTagInputs, recipes); - ui.printTagMessage(addTagReturnMessage); - assertEquals(ui.formatMessage("You have successfully added the recipe(s) to \"breakfast\" tag."), + try { + String addTagReturnMessage = parser.parseTagRecipe(addTagInputs, recipes); + ui.printTagMessage(addTagReturnMessage); + assertEquals(ui.formatMessage("You have successfully added the recipe(s) to \"breakfast\" tag."), outContent.toString().trim()); + } catch (Exception e) { + assert false; + } } @Test public void testPrintRemoveTagMessage() { String[] addTagInputs = new String[]{"tag", "breakfast", "<<", "salad"}; - parser.parseTagRecipe(addTagInputs, recipes); - String[] removeTagInputs = new String[]{"tag", "breakfast", ">>", "salad"}; - String removeTagReturnMessage = parser.parseTagRecipe(removeTagInputs, recipes); - ui.printTagMessage(removeTagReturnMessage); - assertEquals(ui.formatMessage("You have successfully removed the recipe(s) from \"breakfast\" tag."), - outContent.toString().trim()); + try { + parser.parseTagRecipe(addTagInputs, recipes); + String[] removeTagInputs = new String[]{"tag", "breakfast", ">>", "salad"}; + String removeTagReturnMessage = parser.parseTagRecipe(removeTagInputs, recipes); + ui.printTagMessage(removeTagReturnMessage); + assertEquals(ui.formatMessage("You have successfully removed the recipe(s) from \"breakfast\" tag."), + outContent.toString().trim()); + } catch (Exception e) { + assert false; + } + } @Test @@ -940,26 +959,31 @@ public void testListTagException() { //check exception String[] noArgInputs = new String[]{"list", "/t"}; - assertThrows(IllegalArgumentException.class, () -> parser.parseListRecipe(noArgInputs, recipes)); + assertThrows(TagNotFoundException.class, () -> parser.parseListRecipe(noArgInputs, recipes)); String[] notFoundTagInputs1 = new String[]{"list", "/t", "/t"}; - assertThrows(NullPointerException.class, () -> parser.parseListRecipe(notFoundTagInputs1, recipes)); + assertThrows(TagNotFoundException.class, () -> parser.parseListRecipe(notFoundTagInputs1, recipes)); String[] notFoundTagInputs2 = new String[]{"list", "/t", "phone", "&&", "computer"}; - assertThrows(NullPointerException.class, () -> parser.parseListRecipe(notFoundTagInputs2, recipes)); + assertThrows(TagNotFoundException.class, () -> parser.parseListRecipe(notFoundTagInputs2, recipes)); String[] beforeAddTagInputs = new String[]{"list", "/t", "breakfast"}; - assertThrows(NullPointerException.class, () -> parser.parseListRecipe(beforeAddTagInputs, recipes)); + assertThrows(TagNotFoundException.class, () -> parser.parseListRecipe(beforeAddTagInputs, recipes)); // add tag for testing - inputs = new String[]{"tag", "breakfast", "<<", "salad"}; - parser.parseTagRecipe(inputs, recipes); - inputs = new String[]{"tag", "breakfast", ">>", "salad"}; - parser.parseTagRecipe(inputs, recipes); - - String[] nothingInTagInputs = new String[]{"list", "/t", "breakfast"}; - ui.listRecipe(parser.parseListRecipe(nothingInTagInputs, recipes)); - assertEquals(ui.formatMessage("There is nothing to list."), outContent.toString().trim()); + try { + inputs = new String[]{"tag", "breakfast", "<<", "salad"}; + parser.parseTagRecipe(inputs, recipes); + inputs = new String[]{"tag", "breakfast", ">>", "salad"}; + parser.parseTagRecipe(inputs, recipes); + + String[] nothingInTagInputs = new String[]{"list", "/t", "breakfast"}; + + ui.listRecipe(parser.parseListRecipe(nothingInTagInputs, recipes)); + assertEquals(ui.formatMessage("There is nothing to list."), outContent.toString().trim()); + } catch (Exception e) { + assert false; + } } @Test @@ -967,36 +991,48 @@ public void testRemoveTagAndAddTag() { String[] inputs; Recipe invalidRecipe = new Recipe("invalid Recipe", new HashMap<>(1, 1)); - inputs = new String[]{"tag", "western", "<<", "burger"}; - parser.parseTagRecipe(inputs, recipes); - inputs = new String[]{"tag", "western", "<<", "pizza"}; - parser.parseTagRecipe(inputs, recipes); + try { + inputs = new String[]{"tag", "western", "<<", "burger"}; + parser.parseTagRecipe(inputs, recipes); + inputs = new String[]{"tag", "western", "<<", "pizza"}; + parser.parseTagRecipe(inputs, recipes); + } catch (Exception e) { + assert false; + } //exception - assertThrows(IndexOutOfBoundsException.class, + assertThrows(RecipeNotFoundInTagException.class, () -> recipes.removeRecipeFromTag("western", invalidRecipe)); String[] invalidTagInputs = new String[]{"tag", "random", "tag", ">>", "burger"}; - assertThrows(IndexOutOfBoundsException.class, () -> parser.parseTagRecipe(invalidTagInputs, recipes)); + assertThrows(TagNotFoundException.class, () -> parser.parseTagRecipe(invalidTagInputs, recipes)); - String[] noRecipeInTagInputs = new String[]{"tag", "breakfast", ">>", "pizza"}; - assertThrows(IndexOutOfBoundsException.class, + String[] noRecipeInTagInputs = new String[]{"tag", "western", ">>", "random"}; + assertThrows(NoRecipeException.class, () -> parser.parseTagRecipe(noRecipeInTagInputs, recipes)); - inputs = new String[]{"tag", "western", ">>", "pizza"}; - parser.parseTagRecipe(inputs, recipes); - assertEquals(recipes.tags.get("western").size(), 1); + try { + inputs = new String[]{"tag", "western", ">>", "pizza"}; + parser.parseTagRecipe(inputs, recipes); + assertEquals(recipes.tags.get("western").size(), 1); + } catch (Exception e) { + assert false; + } } @Test public void testRandomRecipe() { // no recipe in the lists RecipeList blankRecipeList = new RecipeList(); - assertThrows(NullPointerException.class, () -> parser.parseRandomRecipe(blankRecipeList)); + assertThrows(NoRecipeException.class, () -> parser.parseRandomRecipe(blankRecipeList)); // general case - Recipe randomRecipe1 = parser.parseRandomRecipe(recipes); - assertNotNull(randomRecipe1); - assertNotNull(recipes.randomRecipe()); + try { + Recipe randomRecipe1 = parser.parseRandomRecipe(recipes); + assertNotNull(randomRecipe1); + assertNotNull(recipes.randomRecipe()); + } catch (Exception e) { + assert false; + } } //@@author jaredoong From 828ea8454a3bc8ea3983f3f8d2110c652014ec22 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Sat, 8 Apr 2023 11:47:37 +0800 Subject: [PATCH 198/252] edit UG, DG, portfolio --- docs/AboutUs.md | 14 +++--- docs/DeveloperGuide.md | 102 +++++++++++++++++++++++++++++++++++++---- docs/UserGuide.md | 48 ++++++++++++++++++- docs/team/junenita.md | 31 +++++++++---- 4 files changed, 170 insertions(+), 25 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 8aa80bfe1c..f6af41cc9d 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,8 +1,8 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:------------------:|:--------------------------------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) +| Display | Name | Github Profile | Portfolio | +|-----------------------------------------------------------|:------------------:|:--------------------------------------:|:---------:| +| ![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)| +| ![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)| +| ![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)| +| ![](https://avatars.githubusercontent.com/u/88151966?v=4) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md)| +| ![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md)| diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b8eb3888d2..39519854f3 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -24,7 +24,7 @@ * [List Weekly Plan Feature](#list-weekly-plan-feature) * [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) -* [Appendix: Requirements](#appendix-requirements) +* [Appendix: Requirements](#appendix--requirements) * [Product scope](#product-scope) * [Target user profile](#target-user-profile) * [Value proposition](#value-proposition) @@ -77,6 +77,7 @@ plan. For the class diagrams, `Meal360` and the `Ui` component are not shown for Additionally, methods irrelevant to the subsystem shown are also omitted for simplicity. 1. Recipe related + ![](../docs/UML/Architecture/RecipeRelated.png) 2. Ingredient related @@ -224,8 +225,6 @@ The activity diagram below shows how the `Database` component works at start up: ### Categorise/Tag Recipes Feature -The current implementation: - * add single or multiples recipes into a tag * remove single or multiples recipes from a tag @@ -258,8 +257,6 @@ The sequence diagram below shows how this feature works: ### List Recipes Feature -The current implementation: - * list all recipes * list recipe with filters (name, ingredients, tags) @@ -353,8 +350,6 @@ It is implemented through the following steps: ### Random a Recipe Feature -The current implementation: - * randomly pick a recipe and display to the user It is implemented through the following step: @@ -716,4 +711,95 @@ Given below are instructions to test the app manually. | chicken rice x1 | | avocado toast x1 | ---------------------------------------------------------------------------------------------------- - ``` \ No newline at end of file + ``` + +#### Tag/Categorize Recipes +1. Remove recipe from an unknown tag. + * Prerequisite: Make sure that `unknowntag` has never been created. + * Test case 1: `tag unknowntag >> recipe1` + * Expected: An error message is shown. + * Expected output 1: + ``` + ---------------------------------------------------------------------------------------------------- + | There is no "unknowntag" tag found. Please make sure you have entered the correct tag. | + ---------------------------------------------------------------------------------------------------- + ``` +2. Add tag command with an unknown recipe + * Prerequisite: Make sure that there is no recipe named `unknown` in the list, and + a recipe named `recipe1` using the `add` command. + * Test case 2: `tag testtag << recipe1 && unknown` + * Expected: An error message is showed. `recipe1` is added to `testtag` but `unknown` is not added. + * Expected output 2: + + ``` + ---------------------------------------------------------------------------------------------------- + | Unable to find the recipe: "unknown" in the tag. | + | All the recipe before "unknown" (if any) are successfully added from the tag. | + ---------------------------------------------------------------------------------------------------- + ``` + +3. Remove tag command with an unknown recipe + * Prerequisite: Complete test case 2 + * Test case 3: `tag testtag >> recipe1 && unknown` + * Expected: An error message is showed. `recipe1` is removed `testtag` but `unknown` is not removed. + * Expected output 3: + ``` + ---------------------------------------------------------------------------------------------------- + | Unable to find the recipe: "unknown" in the tag. | + | All the recipe before "unknown" (if any) are successfully removed from the tag. | + ---------------------------------------------------------------------------------------------------- + ``` +4. Successfully add a recipes into a tag + * Prerequisite: Add recipe named `recipe2` using the `add` command + * Test case 4: `tag testtag << recipe2` + * Expected: `recipe2` is added to `testtag`. + * Expected output 4: + ``` + ---------------------------------------------------------------------------------------------------- + | You have successfully added the recipe(s) to "testtag" tag. | + ---------------------------------------------------------------------------------------------------- + ``` + +5. Successfully remove a recipe from a tag + * Prerequisite: Complete test case 4 + * Test case 5: `tag testTag >> recipe2` + * Expected: `recipe2` is removed `testtag`. + * Expected output 5: + ``` + ---------------------------------------------------------------------------------------------------- + | You have successfully removed the recipe(s) from "testtag" tag. | + ---------------------------------------------------------------------------------------------------- + ``` + +#### List Recipes +1. Listing recipes when there is no recipe in the list. + * Prerequisite: Empty the list of recipes. + * Test case 1: `list` + * Expected output 1: + ``` + ---------------------------------------------------------------------------------------------------- + | There is nothing to list. | + ---------------------------------------------------------------------------------------------------- + ``` +2. List all recipes + * Prerequisite: Add one or more recipes using the `add` command. + * Test case 2: `list` + * Expected output 2: An ordered list of recipes is displayed. + The recipes' name that are added are listed out along with the number of ingredients needed. + + +3. List specific recipes + * Test case 3: `list a` + * Expected output 3: + * An ordered list of recipes that contain `a` in their name or ingredients is displayed. + The recipes' name that are added are listed out along with the number of ingredients needed. + * If there is no recipe or ingredient that contain `a` the expected output is identical + to expected output 1. + + +4. List recipes from a tag + * Prerequisite: Create a recipe named `recipefortag` using `add` command, and add the recipe to + `testtag1` using `tag` command. + * Test case 4: `list /t testtag1` + * Expected output 4: An ordered list of recipes that are in `testtag1` are listed out, including `recipefortag`. + The recipes' name that are added are listed out along with the number of ingredients needed. diff --git a/docs/UserGuide.md b/docs/UserGuide.md index a6cb239819..1527a50b6d 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,12 +1,15 @@ # User Guide + ## Introduction Meal360 is a desktop app for managing your recipes and weekly meal plans, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI apps. - +* [Quick Start](#quick-start) +* [Features](#features) +* [Command Summary](#command-summary) ___ ## Quick Start @@ -43,6 +46,8 @@ Format: `ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quan `meat=200 salt and spices=400` * Type the ingredient name followed by equal sign and quantity in positive integer values. +
+ ### Adding recipes: `add` Add new recipes to your list. @@ -57,6 +62,8 @@ Example of usage: `add /r chicken rice` `add /r noodles` +
+ ### Editing recipes: `edit` Edit recipes in your list partially, fully or add new ingredients to already existing recipe. @@ -73,6 +80,8 @@ Example of usage: `edit /r chicken rice` `edit /r noodles` +
+ ### Listing recipes: `list` List all recipes or filtered list recipes by the name or ingredients. @@ -96,6 +105,8 @@ Example of usage: * `list /t western && chinese` lists recipes that is under __both__ 'western' and 'chinese' tag. +
+ ### Viewing recipes: `view` Views the list of ingredients and their quantities for a recipe. @@ -110,6 +121,8 @@ Example of usage: `view 1` +
+ ### Deleting recipes: `delete` Deletes one, a range, or all recipes currently in list. @@ -127,11 +140,13 @@ Example of usage: `delete /r pizza` `delete /r all` +
+ ### Tagging/Categorising recipes: `tag` __Categorize recipes into a specific tag__ -Adding one or more recipes into a tag. +Adding one or more recipes into a tag, so that users can organize the recipes into categories Format: `tag LABEL << [RECIPE_NAME && RECIPE_NAME && ...]` @@ -165,6 +180,8 @@ Example of usage: * `tag breakfast >> milk && boilded egg && bread` removes milk, boiled egg, and bread from 'breakfast' tag. +
+ ### Adding single recipe this week's plan: `weekly /add` Adds an existing recipe to this week's plan. @@ -182,6 +199,8 @@ Example of usage: * `weekly /add pizza 2` adds pizza to this week's plan twice. * `weekly /add burger 1` adds burger to this week's plan once. +
+ ### Adding multiple recipes to this week's plan: `weekly /multiadd` Adds multiple existing recipe to this week's plan. @@ -202,6 +221,8 @@ Example of usage: * `weekly /multiadd /r pizza /q 2 /r burger /q 9` adds pizza twice and burger once to this week's plan. +
+ ### Deleting from this week's plan: `weekly /delete` Deletes an existing recipe from this week's plan. @@ -219,6 +240,8 @@ Example of usage: * `weekly /delete pizza 1` removes pizza from this week's plan once. +
+ ### Deleting multiple recipes from this week's plan: `weekly /multidelete` Deletes multiple existing recipe from this week's plan. @@ -242,12 +265,16 @@ Example of usage: week's plan. +
+ ### Clearing this week's plan: `weekly /clear` Clears this week's plan by removing all recipes listed in weekly plan. Format: `weekly /clear` +
+ ### Mark recipe in this week's plan as done: `weekly /done` Mark a recipe in the weekly plan as completed. A single count of the recipe and its corresponding @@ -264,18 +291,24 @@ Example of usage: * `weekly /done pizza` will mark pizza as done in the weekly plan, assuming the user has `pizza` in the weekly plan and there are sufficient ingredients. +
+ ### View this week's plan: `weeklyplan` View this week's plan. Format: `weeklyplan` +
+ ### View this week's ingredients: `weeklyingredients` View this week's ingredients. Format: `weeklyingredients` +
+ ### Random a recipe: `random` Random a recipe from all the recipes that user have, and show the list of @@ -283,12 +316,16 @@ ingredients and their quantities for a recipe. Format: `random` +
+ ### Exit the program: `bye` Exits the program. Format: `bye` +
+ ### Add user ingredient: `add_i` Add user's ingredients into the ingredient list. @@ -304,6 +341,8 @@ Example of usage: * `add_i /n chicken /c 1 /d 01/01/2020` adds chicken with quantity 1 and expiry date 01/01/2020 +
+ ### Delete user ingredient: `del_i` Delete user's ingredients from the ingredient list. @@ -319,11 +358,15 @@ Example of usage: * `del_i /n chicken /c 1` deletes chicken with quantity 1 +
+ ### View user ingredients: `view_ingredients` View user's ingredients from the ingredient list. Format : `view_ingredients` +--- + ## Command Summary | Action | Format, Examples | @@ -334,6 +377,7 @@ Format : `view_ingredients` | View recipe | `view INDEX`
e.g `view 1` | | Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | | Remove tag/Categorise from recipes | `tag LABEL >> RECIPE_NAME`
e.g `tag western >> pizza` | +| Random a recipe | `random` | | Add to weekly plan | `weekly /add RECIPE_NAME QUANTITY`
e.g `weekly /add pizza 2` | | Add multiple to weekly plan | `weekly /multiadd [/r RECIPE_NAME /q QUANTITY]`
e.g `weekly /multiadd /r pizza /q 1 /r burger /q 3` | | Delete from weekly plan | `weekly /delete RECIPE_NAME`
e.g `weekly /delete pizza` | diff --git a/docs/team/junenita.md b/docs/team/junenita.md index 8f4c5abbf7..9f98c95131 100644 --- a/docs/team/junenita.md +++ b/docs/team/junenita.md @@ -2,31 +2,46 @@ ## Project: Meal360 ### Overview -Meal360 is a desktop app for managing your recipes, optimized for use via a Command Line Interface (CLI) while still -having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management -tasks done faster than traditional GUI apps. - +Meal360 is a desktop app for managing your recipes and weekly meal plans, optimized for use via a Command +Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). +If you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI apps. ### Summary of Contributions * __Code contributed__: [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=junenita&breakdown=true) * __Enhancements implemented__ - * Added `list` feature to list relevant recipes by names or the ingredients + * Added `list` feature to list all recipes users have + * Updated `list` feature to list relevant recipes by names or the ingredients * Added `tag` feature to categorise recipe that users have into groups + * Categorise recipes into a specific tag + * Removing recipes from a tag * Updated `list` feature to be able to list menu in specific tags * Added `random` feature to random a recipe for users * Added exception handler for `list`, `tag`, and `random` features * Wrote tests for `list`, `tag` and `random` features * __Documentation__: * User Guide - * Added documentation for `list`, `tag`, and `random` features + * Added documentation for `list` feature + * Added documentation for `tag` feature + * Categorise recipes into a specific tag + * Removing recipes from a tag + * Added documentation for `random` features * Developer Guide - * Added documentation for `list`, `tag`, and `random` features + * Added documentation for `list` feature + * Added documentation for `tag` feature + * Added documentation for `random` features * Added UML diagrams for `list`, `tag`, and `random` features + * Added instruction for manual testing for list recipes and tag recipes +* __Contributions to the team-based tasks__: + * Maintaining issue tracker + * Updated User Stories in Developer Guide * __Review/Mentoring contributions__: * PRs reviewed: [#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20), [#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30), [#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48), [#53](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/53), [#64](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/64), - [#120](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/120) + [#120](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/120), + [#123](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/123), + [#124](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/124), + [#129](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/129) From 0249c2ecd0063736121f94d22ca3c3c6bd2e3567 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Sat, 8 Apr 2023 13:07:23 +0800 Subject: [PATCH 199/252] add JavaDoc --- src/main/java/seedu/meal360/Parser.java | 53 +++++++++++++++++++++ src/main/java/seedu/meal360/RecipeList.java | 41 ++++++++++++++++ src/main/java/seedu/meal360/Ui.java | 33 +++++++++++++ 3 files changed, 127 insertions(+) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 5ed8a86472..a58b35552a 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -354,6 +354,19 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } } + /** + * Extract inputs from users whether it is adding recipes to a tag or removing recipe from a tag. + * Then, proceed to add or remove the recipes from the tag, and returns a string whether + * the recipes are successfully add to or remove from the tag. + * + * @author junenita + * @param inputs array containing string of inputs + * @param recipeList list containing all recipes data + * @return a string whether successfully added or remove recipes from the tag + * @throws NoRecipeException If users entered invalid recipe. + * @throws RecipeNotFoundInTagException If users try to remove a recipe that is not in the tag. + * @throws TagNotFoundException If users try to remove recipes from a tag that has not been created. + */ public String parseTagRecipe(String[] inputs, RecipeList recipeList) throws RecipeNotFoundInTagException, TagNotFoundException, NoRecipeException { String returnMessage; @@ -387,6 +400,16 @@ public String parseTagRecipe(String[] inputs, RecipeList recipeList) throws Reci return returnMessage; } + /** + * Extract the tag label and recipes. Then, proceed to add the recipes to the tag, + * and returns the tag label that users modified + * + * @author junenita + * @param command string contain tag label and recipes that users want to add + * @param recipeList list containing all recipes data + * @return tag label that is modified + * @throws NoRecipeException If users entered invalid recipe. + */ public String parseAddRecipeTag(String command, RecipeList recipeList) throws NoRecipeException { String tag; Recipe recipe; @@ -416,6 +439,18 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) throws No return tag; } + /** + * Extract the tag label and recipes. Then, proceed to remove the recipes from the tag, + * and returns the tag label that users modified + * + * @author junenita + * @param command string contain tag label and recipes that users want to remove + * @param recipeList list containing all recipes data + * @return tag label that is modified + * @throws NoRecipeException If users entered invalid recipe. + * @throws RecipeNotFoundInTagException If users try to remove a recipe that is not in the tag. + * @throws TagNotFoundException If users try to remove recipes from a tag that has not been created. + */ public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws RecipeNotFoundInTagException, TagNotFoundException, NoRecipeException { String tag; @@ -461,6 +496,16 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws return tag; } + /** + * Extract the filters from users' input. Then, proceed to extract the recipes by the filters. + * + * @author junenita + * @param inputs array containing string of inputs, including the filter + * @param recipeList list containing all recipes data + * @return list of recipes that are filtered by the input + * @throws NoRecipeException If users entered invalid recipe. + * @throws TagNotFoundException If users try to remove recipes from a tag that has not been created. + */ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) throws TagNotFoundException, NoRecipeException { String[] filters; @@ -528,6 +573,14 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { return recipes.get(recipeIndex - 1); } + /** + * Returns a Recipe object that contain a recipe's name and ingredients. + * + * @author junenita + * @param recipes an object containing all recipes data + * @return a random recipe from the input recipes. + * @throws NoRecipeException If recipes.size() == 0. + */ public Recipe parseRandomRecipe(RecipeList recipes) throws NoRecipeException { if (recipes.size() == 0) { throw new NoRecipeException("There is no recipe in the list for random."); diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index a121118e12..0042f9eb8b 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -36,6 +36,13 @@ public Recipe deleteRecipe(int recipeNum) { return recipeToDelete; } + /** + * Add a recipe to a tag. If the tag has not been created, it will be created. + * + * @author junenita + * @param tag tag label that users want to modify + * @param recipe a recipe to be added to the tag + */ public void addRecipeToTag(String tag, Recipe recipe) { boolean hasTag = tags.containsKey(tag); int tagDummy = 0; @@ -50,6 +57,15 @@ public void addRecipeToTag(String tag, Recipe recipe) { } } + /** + * Remove a recipe from a tag. + * + * @author junenita + * @param tag tag label that users want to modify + * @param recipe a recipe to be removed from the tag + * @throws RecipeNotFoundInTagException If the recipe to be removed is not already in + * the tag + */ public void removeRecipeFromTag(String tag, Recipe recipe) throws RecipeNotFoundInTagException { HashMap tagRecipeList = tags.get(tag); boolean isAbleToFindTheRecipe = tagRecipeList.containsKey(recipe); @@ -62,6 +78,16 @@ public void removeRecipeFromTag(String tag, Recipe recipe) throws RecipeNotFound tagRecipeList.remove(recipe); } + /** + * Accumulate all recipes that pass the filters into a list of recipes. + * + * @author junenita + * @param filters array containing strings of filters + * @param isTag flag whether the filters are tags label + * @return RecipeList containing all recipes passing the filters + * @throws TagNotFoundException If the filter is a tag and the tag is invalid. + * @throws NoRecipeException If the filter is a tag and the tag contains no recipe + */ public RecipeList listRecipes(String[] filters, boolean isTag) throws TagNotFoundException, NoRecipeException { RecipeList filteredRecipeList = new RecipeList(); boolean isNoFilter = filters == null; @@ -87,6 +113,15 @@ public RecipeList listRecipes(String[] filters, boolean isTag) throws TagNotFoun return filteredRecipeList; } + /** + * Accumulate all recipes contains all tag from users' input into a list of recipes. + * + * @author junenita + * @param filters array containing strings of tag label + * @return RecipeList containing all recipes containing all tags + * @throws TagNotFoundException If the filter is a tag and the tag is invalid + * @throws NoRecipeException If the filter is a tag and the tag contains no recipe + */ public RecipeList listTagRecipes(String[] filters) throws TagNotFoundException, NoRecipeException { RecipeList filteredRecipeList = new RecipeList(); HashMap tagRecipes; @@ -134,6 +169,12 @@ public RecipeList availableRecipes() { return availableRecipeList; } + /** + * Returns a Recipe object that contain a recipe's name and ingredients. + * + * @author junenita + * @return a random recipe from this RecipeList. + */ public Recipe randomRecipe() { Random random = new Random(); Recipe randomRecipe = this.get(random.nextInt(this.size())); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index db26b87344..7ddada38c3 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -82,6 +82,15 @@ public void listAvailableRecipes(RecipeList recipeListToPrint) { "These are the recipes you can cook"); } + /** + * Print ordered list of recipes including recipes' name and ingredients + * + * @author notbingsu + * @author junenita + * @param recipeListToPrint list containing recipes to be printed + * @param emptyListMsg error message for empty list + * @param listHeaderMsg print list header message + */ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, String listHeaderMsg) { int numberOfRecipes = recipeListToPrint.size(); int order = 0; @@ -141,6 +150,13 @@ public void printUserIngredients(IngredientList userIngredients) { } } + /** + * Extract message received whether users added or removed recipes from a tag. + * Then, proceed to print a successful message. + * + * @author junenita + * @param receivedMessage string containing 'add' or 'remove' tag and tag label + */ public void printTagMessage(String receivedMessage) { String[] args = receivedMessage.split(" ", 2); String command = args[0].trim(); @@ -152,14 +168,31 @@ public void printTagMessage(String receivedMessage) { } } + /** + * Print successfully add recipes to the tag + * + * @author junenita + * @param tag tag label + */ public void printSuccessfullyAddTag(String tag) { printMessage("You have successfully added the recipe(s) to \"" + tag + "\" tag."); } + /** + * Print successfully remove recipes from the tag + * + * @author junenita + * @param tag tag label + */ public void printSuccessfullyRemoveTag(String tag) { printMessage("You have successfully removed the recipe(s) from \"" + tag + "\" tag."); } + /** + * Print random result header + * + * @author junenita + */ public void printRandomMessage() { printMessage("Random Result....."); } From 14ba6a6dc3b16b0ddba3b1c26752407c464ea81a Mon Sep 17 00:00:00 2001 From: JuneNita Date: Sat, 8 Apr 2023 13:24:10 +0800 Subject: [PATCH 200/252] edit ppp --- docs/team/junenita.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/team/junenita.md b/docs/team/junenita.md index 9f98c95131..8f1c1f4053 100644 --- a/docs/team/junenita.md +++ b/docs/team/junenita.md @@ -19,6 +19,10 @@ If you can type fast, Meal360 can get your recipe management tasks done faster t * Added `random` feature to random a recipe for users * Added exception handler for `list`, `tag`, and `random` features * Wrote tests for `list`, `tag` and `random` features + * Added custom exceptions class. + * `NoRecipeException` + * `RecipeNotFoundInTagException` + * `TagNotFoundException` * __Documentation__: * User Guide * Added documentation for `list` feature From 5eb47be73841a6d925819ea04fa172740ce527a5 Mon Sep 17 00:00:00 2001 From: JuneNita Date: Sat, 8 Apr 2023 13:28:56 +0800 Subject: [PATCH 201/252] edit DG --- docs/DeveloperGuide.md | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 85496573fc..4c6a0f0c43 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -728,17 +728,17 @@ Given below are instructions to test the app manually. with count `2` and `1` respectively. A success message should be displayed. Expected output: - ``` - ---------------------------------------------------------------------------------------------------- - | I've deleted the recipes from your weekly plan! | - ---------------------------------------------------------------------------------------------------- - >>> weeklyplan - ---------------------------------------------------------------------------------------------------- - | Here is your weekly plan: | - | chicken rice x1 | - | avocado toast x1 | - ---------------------------------------------------------------------------------------------------- - ``` + ``` + ---------------------------------------------------------------------------------------------------- + | I've deleted the recipes from your weekly plan! | + ---------------------------------------------------------------------------------------------------- + >>> weeklyplan + ---------------------------------------------------------------------------------------------------- + | Here is your weekly plan: | + | chicken rice x1 | + | avocado toast x1 | + ---------------------------------------------------------------------------------------------------- + ``` #### Tag/Categorize Recipes 1. Remove recipe from an unknown tag. @@ -830,15 +830,3 @@ Given below are instructions to test the app manually. * Test case 4: `list /t testtag1` * Expected output 4: An ordered list of recipes that are in `testtag1` are listed out, including `recipefortag`. The recipes' name that are added are listed out along with the number of ingredients needed. - - ``` - ---------------------------------------------------------------------------------------------------- - | I've deleted the recipes from your weekly plan! | - ---------------------------------------------------------------------------------------------------- - >>> weeklyplan - ---------------------------------------------------------------------------------------------------- - | Here is your weekly plan: | - | chicken rice x1 | - | avocado toast x1 | - ---------------------------------------------------------------------------------------------------- - ``` From d31055889349f74c53963652a7b48a28ff5818eb Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sat, 8 Apr 2023 21:32:02 +0800 Subject: [PATCH 202/252] Update DG - Add class diagrams for Meal360, RecipeList, IngredientList, Database, and WeeklyPlan components. - Update personal PPP - Fix AboutUs.md table --- docs/AboutUs.md | 15 +- docs/DeveloperGuide.md | 182 ++++++++++-------- docs/UML/Database/.$AddWeeklyPlanUML.png.bkp | Bin 29544 -> 0 bytes .../.$DatabaseClassDiagram.drawio.bkp | 1 + .../Database/.$DatabaseStartupUML.drawio.bkp | 2 +- .../Database/.$DatabaseStartupUML.drawio.dtmp | 1 - docs/UML/Database/DatabaseClassDiagram.drawio | 1 + docs/UML/Database/DatabaseClassDiagram.png | Bin 0 -> 26628 bytes docs/UML/Database/DatabaseStartupUML.drawio | 2 +- docs/UML/Database/DatabaseStartupUML.png | Bin 51768 -> 40662 bytes .../.$IngredientListClassDiagram.drawio.bkp | 1 + .../.$IngredientListClassDiagram.png.bkp | Bin 0 -> 29370 bytes .../.$RecipeListClassDiagram.drawio.bkp} | 2 +- .../IngredientListClassDiagram.drawio | 1 + .../IngredientListClassDiagram.png | Bin 0 -> 32616 bytes .../.$IngredientListClassDiagram.png.bkp | Bin 0 -> 29370 bytes .../Meal360/.$Meal360ClassDiagram.drawio.bkp | 1 + .../.$RecipeListClassDiagram.drawio.bkp} | 2 +- docs/UML/Meal360/Meal360ClassDiagram.drawio | 1 + docs/UML/Meal360/Meal360ClassDiagram.png | Bin 0 -> 27414 bytes .../parseDate2.drawio} | 0 .../.$IngredientListClassDiagram.drawio.bkp | 1 + .../.$RecipeListClassDiagram.drawio.bkp} | 2 +- .../RecipeList/RecipeListClassDiagram.drawio | 1 + .../UML/RecipeList/RecipeListClassDiagram.png | Bin 0 -> 35447 bytes .../WeeklyPlan/.$AddWeeklyPlanUML.drawio.dtmp | 1 - .../UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp | Bin 29544 -> 0 bytes .../.$WeeklyPlanClassDiagram.drawio.bkp | 1 + .../.$WeeklyPlanClassDiagram.png.bkp | Bin 0 -> 9238 bytes .../.$WeeklyPlanClassDiagram.png.dtmp | 1 + .../WeeklyPlan/WeeklyPlanClassDiagram.drawio | 1 + .../UML/WeeklyPlan/WeeklyPlanClassDiagram.png | Bin 0 -> 9238 bytes docs/team/jaredoong.md | 44 +++-- 33 files changed, 158 insertions(+), 106 deletions(-) delete mode 100644 docs/UML/Database/.$AddWeeklyPlanUML.png.bkp create mode 100644 docs/UML/Database/.$DatabaseClassDiagram.drawio.bkp delete mode 100644 docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp create mode 100644 docs/UML/Database/DatabaseClassDiagram.drawio create mode 100644 docs/UML/Database/DatabaseClassDiagram.png create mode 100644 docs/UML/IngredientList/.$IngredientListClassDiagram.drawio.bkp create mode 100644 docs/UML/IngredientList/.$IngredientListClassDiagram.png.bkp rename docs/UML/{Database/.$AddWeeklyPlanUML.drawio.bkp => IngredientList/.$RecipeListClassDiagram.drawio.bkp} (77%) create mode 100644 docs/UML/IngredientList/IngredientListClassDiagram.drawio create mode 100644 docs/UML/IngredientList/IngredientListClassDiagram.png create mode 100644 docs/UML/Meal360/.$IngredientListClassDiagram.png.bkp create mode 100644 docs/UML/Meal360/.$Meal360ClassDiagram.drawio.bkp rename docs/UML/{WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp => Meal360/.$RecipeListClassDiagram.drawio.bkp} (77%) create mode 100644 docs/UML/Meal360/Meal360ClassDiagram.drawio create mode 100644 docs/UML/Meal360/Meal360ClassDiagram.png rename docs/UML/{parseDate.drawio => Parser/parseDate2.drawio} (100%) create mode 100644 docs/UML/RecipeList/.$IngredientListClassDiagram.drawio.bkp rename docs/UML/{IngredientList/IngredientListUML.drawio => RecipeList/.$RecipeListClassDiagram.drawio.bkp} (66%) create mode 100644 docs/UML/RecipeList/RecipeListClassDiagram.drawio create mode 100644 docs/UML/RecipeList/RecipeListClassDiagram.png delete mode 100644 docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.dtmp delete mode 100644 docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp create mode 100644 docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.drawio.bkp create mode 100644 docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.png.bkp create mode 100644 docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.png.dtmp create mode 100644 docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio create mode 100644 docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.png diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 8aa80bfe1c..27fd9ad16e 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,8 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:------------------:|:--------------------------------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) -![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) + +| Display | Name | Github Profile | Portfolio | +|-----------------------------------------------------|:------------------:|:--------------------------------------:|:---------------------------------:| +| ![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) | diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 01da28b442..a91ca9ad53 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -3,36 +3,34 @@ - [Acknowledgements](#acknowledgements) - [Setting up, getting started](#setting-up-getting-started) - [Design](#design) - - [Architecture](#architecture) - - [UI Component](#ui-component) - - [Parser Component](#parser-component) - - [Recipe Component](#recipe-component) - - [RecipeList Component](#recipelist-component) - - [WeeklyPlan Component](#weeklyplan-component) - - [Database Component](#database-component) - - [Ingredient Component](#ingredient-component) + - [Architecture](#architecture) + - [Meal360 Component](#meal360-component) + - [UI Component](#ui-component) + - [Parser Component](#parser-component) + - [RecipeList Component](#recipelist-component) + - [WeeklyPlan Component](#weeklyplan-component) + - [Database Component](#database-component) + - [IngredientList Component](#ingredientlist-component) - [Implementation](#implementation) - - - [Add Recipes Feature](#add-recipes-feature) - - [Edit Recipes Feature](#edit-recipes-feature) - - [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) - - [List Recipes Feature](#list-recipes-feature) - - [Delete Recipes Feature](#delete-recipes-feature) - - [Add Ingredients Feature](#add-ingredients-feature) - - [Delete Ingredients Feature](#delete-ingredients-feature) - - [List Ingredients Feature](#list-ingredients-feature) - - [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) - - [List Weekly Plan Feature](#list-weekly-plan-feature) - - [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) - + - [Add Recipes Feature](#add-recipes-feature) + - [Edit Recipes Feature](#edit-recipes-feature) + - [Categorise/Tag Recipes Feature](#categorisetag-recipes-feature) + - [List Recipes Feature](#list-recipes-feature) + - [Delete Recipes Feature](#delete-recipes-feature) + - [Add Ingredients Feature](#add-ingredients-feature) + - [Delete Ingredients Feature](#delete-ingredients-feature) + - [List Ingredients Feature](#list-ingredients-feature) + - [Edit Weekly Meal Plan Feature](#edit-weekly-meal-plan-feature) + - [List Weekly Plan Feature](#list-weekly-plan-feature) + - [Mark Recipe as Done Feature](#mark-recipe-as-done-feature) - [Appendix: Requirements](#appendix-requirements) - - [Product scope](#product-scope) - - [Target user profile](#target-user-profile) - - [Value proposition](#value-proposition) - - [User Stories](#user-stories) - - [Non-Functional Requirements](#non-functional-requirements) - - [Glossary](#glossary) - - [Instructions for manual testing](#instructions-for-manual-testing) + - [Product scope](#product-scope) + - [Target user profile](#target-user-profile) + - [Value proposition](#value-proposition) + - [User Stories](#user-stories) + - [Non-Functional Requirements](#non-functional-requirements) + - [Glossary](#glossary) + - [Instructions for manual testing](#instructions-for-manual-testing) --- @@ -45,22 +43,26 @@ ## Setting up, getting started +- Refer to the + instructions [here](https://github.com/AY2223S2-CS2113-F10-3/tp/blob/master/README.md). + --- ## Design - [Architecture](#architecture) +- [Meal360 Component](#meal360-component) - [UI Component](#ui-component) - [Parser Component](#parser-component) -- [Recipe Component](#recipe-component) - [RecipeList Component](#recipelist-component) - [WeeklyPlan Component](#weeklyplan-component) - [Database Component](#database-component) +- [IngredientList Component](#ingredientlist-component) ### Architecture The Architecture Diagram below shows a high-level design of the Meal360 application: -![](../docs/UML/Architecture/ArchitectureUML.png) +![](./UML/Architecture/ArchitectureUML.png) **How the architecture components interact with each other:** @@ -78,18 +80,24 @@ plan. For the class diagrams, `Meal360` and the `Ui` component are not shown for Additionally, methods irrelevant to the subsystem shown are also omitted for simplicity. 1. Recipe related - ![](../docs/UML/Architecture/RecipeRelated.png) + +![](../docs/UML/Architecture/RecipeRelated.png) 2. Ingredient related - ![](../docs/UML/Architecture/IngredientRelated.png) + +![](../docs/UML/Architecture/IngredientRelated.png) 3. WeeklyPlan related - ![](../docs/UML/Architecture/WeeklyPlanRelated.png) + +![](../docs/UML/Architecture/WeeklyPlanRelated.png) ### Meal360 Component API: `Meal360.java` +The (partial) class diagram below shows the structure of the `Meal360` component: +![](../docs/UML/Meal360/Meal360ClassDiagram.png) + The `Meal360` component: - initializes the databases for the recipes, ingredients, and weekly plan upon program startup. @@ -130,28 +138,27 @@ The `Parser` component: - receives the user input from the `Meal360` component - checks and filters input string - catches `exceptions` and throws error messages via `UI` to - 1. prompts user to enter valid input - 2. prevent `Meal360` from crashing upon invalid input -- interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the commands. + 1. prompts user to enter valid input + 2. prevent `Meal360` from crashing upon invalid input +- interacts with the `RecipeList`, `WeeklyPlan`, and/or `Ingredient` components to execute the + commands. The sequence diagram below shows how `Parser` filters user input dates and parses them as valid `LocalDate` objects. ![](../docs/UML/Parser/parseDate.drawio.png) -### Recipe Component +### RecipeList Component -API: `Recipe.java` +API: `RecipeList.java` and `Recipe.java` -The `Recipe` component: +![](../docs/UML/RecipeList/RecipeListClassDiagram.png) + +`Recipe` is a class with the following characteristics: - contains `name` and `ingredients` attribute - store the ingredients details the user has added in `ingredients` -### RecipeList Component - -API: `RecipeList.java` - The `RecipeList` component: - extends from `ArrayList` @@ -168,6 +175,8 @@ The `RecipeList` component: API: `WeeklyPlan.java` +![](../docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.png) + The `WeeklyPlan` component: - extends from `HashMap` @@ -195,6 +204,8 @@ inputs `weekly /add burger 1`: API: `Database.java` +![](../docs/UML/Database/DatabaseClassDiagram.png) + The `Database` component: - stores the recipes, ingredients, and weeklyplan in a local database in json format @@ -220,7 +231,24 @@ How the `Database` component works at start up for the recipes: The activity diagram below shows how the `Database` component works at start up: ![](../docs/UML/Database/DatabaseStartupUML.png) -### Ingredient Component +### IngredientList Component + +API: `IngredientList.java` and `Ingredient.java` + +![](../docs/UML/IngredientList/IngredientListClassDiagram.png) + +`Ingredient` is a class with the following characteristics: + +- contains `name`, `quantity`, and `expiryDate` attribute. +- store the ingredients details the user has added in per ingredient. + +The `IngredientList` component: + +- extends from `HashMap` +- stores the ingredients the user has added as `Ingredient` objects +- allows users to add their own ingredients +- allows users to delete the existing ingredients +- allows users to view the entire list of ingredients that they have --- @@ -251,22 +279,22 @@ It is implemented through the following step: the `Parser` component. 2. In `Parser`, `parseTagRecipe()` is executed to identify whether user want to add recipes to a tag (`<<`), or remove recipes from a tag(`>>`). Then, - - If `isAddTag`, user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to - extract - the all the recipes to be added, separated by `&&`, and pass those recipes and tag label - to `RecipeList` - component. - - If `isRemoveTag`, user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be - executed to - extract the all the recipes to be removed, separated by `&&`, and pass those recipes and tag - label to - `RecipeList` component. - - If user enter invalid command, an error message will be thrown. + - If `isAddTag`, user want to add recipes to a tag, `parseAddRecipeTag()` will be executed to + extract + the all the recipes to be added, separated by `&&`, and pass those recipes and tag label + to `RecipeList` + component. + - If `isRemoveTag`, user want to remove recipes from a tag, `parseRemoveRecipeTag()` will be + executed to + extract the all the recipes to be removed, separated by `&&`, and pass those recipes and tag + label to + `RecipeList` component. + - If user enter invalid command, an error message will be thrown. 3. In `RecipeList`, - - If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in - to the tag. - - If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to remove recipes - from the tag. + - If user want to add recipes to a tag, `addRecipeToTag()` is executed to add recipes in + to the tag. + - If user want to remove recipes to a tag, `removeRecipeFromTag()` is executed to remove recipes + from the tag. The sequence diagram below shows how this feature works: @@ -286,21 +314,21 @@ It is implemented through the following step: 2. In `Parser`, `parseListRecipe()` is executed to first identify whether user want to filter by tag (`/t`). - - If user filters the recipes by tag (`/t`), `isTag` is set to `true`. - - Otherwise, `isTag` is set to `false`. + - If user filters the recipes by tag (`/t`), `isTag` is set to `true`. + - Otherwise, `isTag` is set to `false`. Then, it will extract all the filters separated by `&&`, if any. All the filters are extracted out and passed to `RecipeList`component. 3. In `RecipeList`, `listRecipes()` is executed to first identify whether user want to filter by tag. - - If `isTag` is true, `listTagRecipes()` is called to filter all recipes that meet - all the filters by tag, and return the `recipeList` containing all relevant recipes - to `listRecipes()` - and `ParserRecipe()`, respectively. - - If user `isTag` is false, it filters all recipes that meet all the filters by name - and ingredients, and return `recipeList` containing all relevant recipes to - `ParselistRecipe()`. + - If `isTag` is true, `listTagRecipes()` is called to filter all recipes that meet + all the filters by tag, and return the `recipeList` containing all relevant recipes + to `listRecipes()` + and `ParserRecipe()`, respectively. + - If user `isTag` is false, it filters all recipes that meet all the filters by name + and ingredients, and return `recipeList` containing all relevant recipes to + `ParselistRecipe()`. The sequence diagram below shows how this feature works: @@ -353,9 +381,9 @@ It is implemented through the following steps: The current implementation: - There are 3 ways to edit: - - Edit all ingredients. - - Edit 1 particular ingredient. - - Add new ingredient. + - Edit all ingredients. + - Edit 1 particular ingredient. + - Add new ingredient. It is implemented through the following steps: @@ -598,10 +626,10 @@ Given below are instructions to test the app manually. 1. Initial launch - 1. Download the jar file and copy into an empty folder - 2. Run the jar file using the command `java -jar meal360.jar`. The GUI similar to the below - should appear in a few seconds. The app comes with a smaall sample data of 10 recipes to - allow for easy testing. + 1. Download the jar file and copy into an empty folder + 2. Run the jar file using the command `java -jar meal360.jar`. The GUI similar to the below + should appear in a few seconds. The app comes with a smaall sample data of 10 recipes to + allow for easy testing. Expected output: @@ -625,8 +653,8 @@ Given below are instructions to test the app manually. 2. Shutdown - 1. A user input of `bye` allows the user to exit the app. The app will then save the data for - recipes, ingredients and weekly meal plan automatically before exiting. + 1. A user input of `bye` allows the user to exit the app. The app will then save the data for + recipes, ingredients and weekly meal plan automatically before exiting. Expected output: diff --git a/docs/UML/Database/.$AddWeeklyPlanUML.png.bkp b/docs/UML/Database/.$AddWeeklyPlanUML.png.bkp deleted file mode 100644 index 88175f2772c0570e1cf33355edc8698c30bcbe52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29544 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 A)&Kwi diff --git a/docs/UML/Database/.$DatabaseClassDiagram.drawio.bkp b/docs/UML/Database/.$DatabaseClassDiagram.drawio.bkp new file mode 100644 index 0000000000..ab5a5e0134 --- /dev/null +++ b/docs/UML/Database/.$DatabaseClassDiagram.drawio.bkp @@ -0,0 +1 @@ +7Vlbb+I6EP41SN2VusoFUngs0Ju2bKtS6XTPy8olJrHq2BzHFOiv33FsE5yEQk/hrVJF4/F4bM8383nitMJBtrwSaJaOeIxpK/DiZSsctoKg3QvhVwlWWhD0Ai1IBIm1yCsFY/KGtdC30jmJcW5kWiQ5p5LMXOGEM4Yn0pEhIfjCVZtyGjuCGUpwTTCeIFqX/kNimRqpH/XKjmtMktRM3Q3OdEeGrLLZSZ6imC82ROFFKxwIzqV+ypYDTJXvXL9cbuldL0xgJvcZMBq+eTf+6HmxuMjw8D/278Pdz1Nj5RXRudmwWaxcWQ8IPmcxVka8VthfpETi8QxNVO8CIAdZKjMKLR8ecyn4Cx5wygVIGGeg1q+v1E6LhcTLDZFZ+RXmGZZiBSqmN/BMHJkw8rumvShBaUcdLUs38OgERhGZQEjWtktfwYNxV7PrulMyWt2torfRMEvR/Lr9+ylrcN0DnpAZviW5rDkxX5CMosIbU87k2PQolyFKEgbPE/AOBq/1lVcIROC56ZBcOXmSEhrfohWfq53lEk1ebKufckHewCwqYUBCmmQKIkdjrEYaMAXOQefeAuNXRCO0dBRvUS6NYMIpRbOcPK+3kSGRENbnUvLMKB0C98DFPfCiOu5BVMc9sMKD4x40pExf0RJKYKpzeLpGeTqCzAgiqtAZS0FY0goG9S4dMbrrBuBPIACCKJGF8+z/SiiB5+S2TJsSSisiG14UT+XW4MohoWGNt4XOsF1KHoxHlYjD2CktKCwlcYyZCgwukUQ6ChTkM06YLDze6cMfMNLA+9FpdYZqj52+X7bhT6kLOeAM9oJIESMYQmyBc9kYPe+m4e6QsiG0bwR1jxRA4W7OpaTATmNszx3/fwGcAVQUl4g+KsCHp34N9bCOetiAMEXPmN7znEjClX2hdSvI7wLXjV7CUizIMUHvtPcD/ViYt5tIY0pY3F/9Qhk+YfCjyUOzxTfdsPwAKw19Tal9FMdafCJ074amGfbKYTHOIBwTuXWU5h+YVYAaLlDcQWMVrto6LRSDWGJn4l/zTGtDTOyzy0f+iJITINdN9+hVfGD/AmdAX1rpUvDsEDYpHPRaJT+BvITDO3fs6TzQvs0f7WTPUL1ixJyt65KhahuG7DS/wwx6RYSq5LWGdugLxGKeGbwq6HwdQwdlpCjYj5H8qH0kTupsKWC/iteDFa+eU7y2u90GzL0GzO1L8sExj2qYn0KzevpskILqXrOI1ulrBqsolcdHQSuF5o0rc6jmcyfOFx29T0edvWP1vaq4ITTtO/bBI/Psqyr+bFX8YdB7/n6gH6sq7jZVxab6qHPSp4tUh38SLIvK+9sW4tMqJYOta6ePkFR1wnl2N20wqQLB0SX5ueVcq/NsWfeL+A6bA739cqB3tHvEPe5gMYvP1WU2tGKCMs7ix5Qoh0PHJaG2coKWrZsUQhv3su4lLl4S+aSewfe69XujZ7jcbKxsg8Fm9aB298wK1Dj/h+f5VlAOLlrO6HugM/CZqhPfL7FyPhcTvBtlKBQhq3a/duPYueSvx8IG+H5kwBeYIkle3e8ATegbc/e8SGNb/IVd3y3+zip1vN6kGbV5b18x1GnvMKS9UDNUBON6j3vFJwtGdHDFpmyOf/YGf56GLwluuOf+vo2Edn0IeIePtr5ArE/qpi8PblhvSf2GENtasrf9Sske1euiqIEdQu/D7ADN8uOPBqv8ghZe/AU= \ No newline at end of file diff --git a/docs/UML/Database/.$DatabaseStartupUML.drawio.bkp b/docs/UML/Database/.$DatabaseStartupUML.drawio.bkp index ed707033b3..06b67de9a1 100644 --- a/docs/UML/Database/.$DatabaseStartupUML.drawio.bkp +++ b/docs/UML/Database/.$DatabaseStartupUML.drawio.bkp @@ -1 +1 @@ -7VrLcqM4FP0aV/UsmpIQ4rEMcTxdU+maVGfRPUsZZJsKthjAHTtfP1cgngLbie30o8YLB10hAeeecx84E3K73v2ZsmT1WYQ8npgo3E3IdGKa2CQU/kjLvrQ4FioNyzQKS1PL8Bi9cLWysm6jkGfKVppyIeI8SrrGQGw2PMg7Npam4rl72kLEYceQsCXXDI8Bi3Xr1yjMV8qKba+Z+MSj5Upd2jWdcmLNqpPVk2QrFornloncTchtKkReHq13tzyW4HVxmY3M1jeW8k1+ygL/yz1dP/39uNr99fLwcv/JfxH3HytvfGfxVj2xutt8X0GwTMU2UafxNOe7IeDZvDod6TeG68cFnnCx5nm6h1OqjTy7XLKvXK+wfW4Ad03Fo1ULa2I7BlFrmfLzst6+gQIOFBqvQIbg48is8jXsOcUT4i+iOL4VsUiLGbJwAx4EYM/yVDzx1szcpRZFMDOKaBu5A04bxZMgrOFHTWsQvyuBh0+g1Th4IePuYhA8O3D5fHFN8CpBtLAzbfzO3MND3LNjuLQ/h4OlPHhgacbTygyXqWc0pAEjaW8BzuJouYHjALCCTYgvkYwg6t2oiXUUhnK5n/IselHilqxNRLTJi+el/oRO5V7bXGRl3MaazzZiw3sOVqbredCmBkWWDZEIUw9TsxtcTAMhZDq27XiuhT1EdK0MhBrzamHGPO7qr5w/xfuHmG3+d7eePUzXoD0X6+ljIPpdzaXY0l1Kbiq99pwFVUEiD7fr+D5a8Dgq0Ep4GsHNSF9NY2V+aGz+8yrK+WPCArn0GSqvrr8hJ+cMlqT1OI5ZkkWNX1MebNMs+s6/cOVMaRXbXF7ptq6lkB6cZzPTp/ZVBQwarUKucqlFDEpR89ETHKbIoO6Alz3PsOi1xDvo6bZcf3VvmzPfm90p+6N6EBkCrkkAjxpQBDYf61fgArZfVfLogbXNApHmK7EUGxa3efD+SnQAsG5sxcRwvBb6eqzF1EC2Dr5HjLovuzT2FdS/FfYeNqripALfsgB8HXCko12VsZeHmmhQJzKz3YTQvG+WMW+i3weoUNhaBqt/t7LJ9Z+LqYnsEGcsDOFgvk2XMilKEXfP/UNzIA+hMVfDxkd3jbUuc2K+kFtkEDHhlu6L0RSg9vkmvJHvBGA4j0XwJEOj2G5CHqroBx5L998UTYrBP2omZnMe+yx4WhYretVNi1zliSINeTpYAsnH6BAlZ4DBIaJUZD6XUchAFu6WSipIpjxmOaSHzn0NUUft/SAF1KYq1agKVVlF1WqjTGzTgKu1DQ3BI2zfOk2pc/RqFBLA+NVmr1jVyKlRRHk3vT2qWxOLRcbzSV9DNdRnVBJ6wwxJO0r4Z5YcCmWjhfxxqh+V02HK98Q2Qu5zOfsRSEvMXg6ytBDooosQmSI95rpAEtdrPr2uYYTUAxqxtK2hHCG9NzBlMLiARtCJDzKuF30HuN/xHX6cdqqY1k9J3Ux0Wg4azT4HNDcXeS7Wp2iu2yyHfMG2RTt/WGl8F+VFTjIQttW4SEuGLI3L8XRXyVoO9q1Bq4iZorOFCpgUhD8UyuhRRSPkXkvCJrINZLZI6nQ5jC3QXKt+JW+Us6yMEXGo6eHie+AqJsWO5cpv2nuMEZW/a8LR67g3JZwh8ouEw5QfsmxVUL8spqofd1xNFofpPyaaplYzShnU5ZphQZenDI0witG+Pbq0NI5WcidIg1j4MjWZq8VvEzlavjmZ7+ik7X4GYuvZ4BCfL9AL1u9IJtfqBbFt9uLLW7twWHq9Nrxiw28FvdOF3rT06vNdG3DiaiBDHSOrnOxDHcHf0j0P/F7w/o30WLAfCc3HI65zGRrI6HeZZhk73Yqk/sH8wm0yhOfB6/zwcp14r4oSP0/BcV55cIhaqMLkXG5Vb72Vz4lJT+JWs9HYwqsmdhg2/wZTnt78MxG5+w8= \ No newline at end of file +7Vvfc+IqFP5rfNxOCJCQx9b+2JndO7Mzfbjt0x1qULMbxUFs6/71FwyYIFFjq8ap9qVyQgj5zvkO5xxIB3ZH7w+CTob/8JTlnTBI3zvwthOGAAKo/mnJvJDEJCoEA5GlhSgoBY/ZX2butNJZlrKpkRUiyXkus4kr7PHxmPWkI6NC8De3W5/nqSOY0AHzBI89mvvSf7NUDo0UREl54TvLBkPzaBLGxYURtZ3Nm0yHNOVvFRG868Cu4FwWv0bvXZZr8Fxc7tdcXU5MsLFsdEPM58EkfHp8+PH637cfD/jl6fu3CBXDvNJ8Zt7YzFbOLQQDwWcT040Jyd7rgKcvtnvgTwwsX1fZCeMjJsVcdTEDJWYkYyEEF823Eu6EGFCHFaQjQIyajYoHy5FLFNQPA8QOoIB4OyhqGGWCqnEzlCM1+i1QP5WKJ/r6VFIhHyWV+no/y/Muz7lY3AiDxZ/uLAX/wypX7u/NlbVYO5iuV6ePtIEWhB60MPCRtbL9A0saAJsq/pkmF3LIB3xM87tSWgVcY5Qpsl7n2WCsZC9cSj5SF9g4vdbs14NM2LiQGO9C6sBfqkUZ+zhl+i2CxV3qvZ904yoIiBU8LwQIQiu4fa/2v51XW7+YyBR8TFjheyafzPz172IwbFrlSLphBypQ0tA49jDlM9FjmwCPdzIc5VupGLBNHUFSb2GC5VRmr+786gzI3PqLZ2pCSx8AEHGcQBi5IxTzMjetWOFyFp8wzMQzzO6Q9f7o+/p69aLKwVFFd7WCZLn+p9QzlZ7xlsajtfs2zCR7nNCFit7U+uga74pjSCkj/V6dbUY9wl76B3EMdhgceJ4BhDWuITqUa7AP2+QaxJCPXmbT7ci6HF7BmYEUs7gO5ySKIY0OiTMMsGPmse+QSQ3q5GCog304ZBfuss9PzidGI7+ZlHPjf+lM8pV1c603XuP4Gvuz7R4yaej4KjHbxxzf5xQVbnZQBhDlqTKhojG+mFq9j2rMnRPzURgihzsgat1nwXNnj4V7O3vCVtkT1bNnauljFvVMC9hoIudfhjUAuysOiFtnTZPs6sKa0m5bY01NtoZvDFVSzjRZxlwuFxp86+lRWbN0YacmU+spLHVK5KVwoyxNCw2zafbXlBW0WiY6+F+8I77Rz1JjKaVOC/36Gh3z8Wr2bUSHi+6S2OEaQT7VQE0lYzXZ2Z8G/bSm1OBCadOL1kIbAlqtAU9rMTqi0uB5ZEIwdFAPkb8uHTUVgmefClmL3roswVZTIWs4FUX95DTVUZzgo7pizVcJ5YhbKIfQr5QfN5SDZ58AwaahHGw1AYL+No/hTMr6dJZLhzZfhC8IQYcvGMZt8wVf+NKUL2t0eyS++AUDFb9WygNnHzWj0F2MQruBUyGX3SM/TthcU1bANyY/veis0FG0VWfxMfNTdBapTgzhCux+3HbUVAddUp2w4TKEWk11kB+2dQXTx0rqd3y+SOBGIreOBmHScuCGzj5wQ00DN9Rq4IZqA7dLfbqgB3T3gkIcebxCx4zZUG3MdtlaqHGJYbxVdckxVRf5VbjT8ojLk3ug45zaw50tZ/bM8bzySN6zHWTX43l79L6koff9dNpcfzwvjoOrBBCoYmUUJZC4h/UwWBnwwKf1kL8xuQyLvmrxNwZuEoFsu72Y6NSLv+XZ3d08wAnFUuQgbI5CchVgFQ4AHJMExW5UAG0lZQubr4Wg80o3s4hueOpKxcgc9L9v2N+Wc0ubLWawV9diz8Ee14Y/suZ8dH1rM4doesj803b/KceGm4Q2mz7/0J8a7PrxR79f+/3B/tcTu2YTv/Z31G9BMPFAbZdHFeo8O8w5OR7ZHfCtPCosuTUeJRt9qUmZ9qf0TvPvadY4zxNWeVPX2a7Ko5ryy2aWb4nH10P+4ex7Y5iN3TPmyM+yQZDgmig72R1S1Sy//iwCmPIbWnj3Pw== \ No newline at end of file diff --git a/docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp b/docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp deleted file mode 100644 index 03a697e1ec..0000000000 --- a/docs/UML/Database/.$DatabaseStartupUML.drawio.dtmp +++ /dev/null @@ -1 +0,0 @@ -7Vvfc+IqFP5rfNxOCJCQx9b+2JndO7Mzfbjt0x1qULMbxUFs6/71FwyYIFFjq8ap9qVyQgj5zvkO5xxIB3ZH7w+CTob/8JTlnTBI3zvwthOGAAKo/mnJvJDEJCoEA5GlhSgoBY/ZX2butNJZlrKpkRUiyXkus4kr7PHxmPWkI6NC8De3W5/nqSOY0AHzBI89mvvSf7NUDo0UREl54TvLBkPzaBLGxYURtZ3Nm0yHNOVvFRG868Cu4FwWv0bvXZZr8Fxc7tdcXU5MsLFsdEPM58EkfHp8+PH637cfD/jl6fu3CBXDvNJ8Zt7YzFbOLQQDwWcT040Jyd7rgKcvtnvgTwwsX1fZCeMjJsVcdTEDJWYkYyEEF823Eu6EGFCHFaQjQIyajYoHy5FLFNQPA8QOoIB4OyhqGGWCqnEzlCM1+i1QP5WKJ/r6VFIhHyWV+no/y/Muz7lY3AiDxZ/uLAX/wypX7u/NlbVYO5iuV6ePtIEWhB60MPCRtbL9A0saAJsq/pkmF3LIB3xM87tSWgVcY5Qpsl7n2WCsZC9cSj5SF9g4vdbs14NM2LiQGO9C6sBfqkUZ+zhl+i2CxV3qvZ904yoIiBU8LwQIQiu4fa/2v51XW7+YyBR8TFjheyafzPz172IwbFrlSLphBypQ0tA49jDlM9FjmwCPdzIc5VupGLBNHUFSb2GC5VRmr+786gzI3PqLZ2pCSx8AEHGcQBi5IxTzMjetWOFyFp8wzMQzzO6Q9f7o+/p69aLKwVFFd7WCZLn+p9QzlZ7xlsajtfs2zCR7nNCFit7U+uga74pjSCkj/V6dbUY9wl76B3EMdhgceJ4BhDWuITqUa7AP2+QaxJCPXmbT7ci6HF7BmYEUs7gO5ySKIY0OiTMMsGPmse+QSQ3q5GCog304ZBfuss9PzidGI7+ZlHPjf+lM8pV1c603XuP4Gvuz7R4yaej4KjHbxxzf5xQVbnZQBhDlqTKhojG+mFq9j2rMnRPzURgihzsgat1nwXNnj4V7O3vCVtkT1bNnauljFvVMC9hoIudfhjUAuysOiFtnTZPs6sKa0m5bY01NtoZvDFVSzjRZxlwuFxp86+lRWbN0YacmU+spLHVK5KVwoyxNCw2zafbXlBW0WiY6+F+8I77Rz1JjKaVOC/36Gh3z8Wr2bUSHi+6S2OEaQT7VQE0lYzXZ2Z8G/bSm1OBCadOL1kIbAlqtAU9rMTqi0uB5ZEIwdFAPkb8uHTUVgmefClmL3roswVZTIWs4FUX95DTVUZzgo7pizVcJ5YhbKIfQr5QfN5SDZ58AwaahHGw1AYL+No/hTMr6dJZLhzZfhC8IQYcvGMZt8wVf+NKUL2t0eyS++AUDFb9WygNnHzWj0F2MQruBUyGX3SM/TthcU1bANyY/veis0FG0VWfxMfNTdBapTgzhCux+3HbUVAddUp2w4TKEWk11kB+2dQXTx0rqd3y+SOBGIreOBmHScuCGzj5wQ00DN9Rq4IZqA7dLfbqgB3T3gkIcebxCx4zZUG3MdtlaqHGJYbxVdckxVRf5VbjT8ojLk3ug45zaw50tZ/bM8bzySN6zHWTX43l79L6koff9dNpcfzwvjoOrBBCoYmUUJZC4h/UwWBnwwKf1kL8xuQyLvmrxNwZuEoFsu72Y6NSLv+XZ3d08wAnFUuQgbI5CchVgFQ4AHJMExW5UAG0lZQubr4Wg80o3s4hueOpKxcgc9L9v2N+Wc0ubLWawV9diz8Ee14Y/suZ8dH1rM4doesj803b/KceGm4Q2mz7/0J8a7PrxR79f+/3B/tcTu2YTv/Z31G9BMPFAbZdHFeo8O8w5OR7ZHfCtPCosuTUeJRt9qUmZ9qf0TvPvadY4zxNWeVPX2a7Ko5ryy2aWb4nH10P+4ex7Y5iN3TPmyM+yQZDgmig72R1S1Sy//iwCmPIbWnj3Pw== \ No newline at end of file diff --git a/docs/UML/Database/DatabaseClassDiagram.drawio b/docs/UML/Database/DatabaseClassDiagram.drawio new file mode 100644 index 0000000000..0648ff7f56 --- /dev/null +++ b/docs/UML/Database/DatabaseClassDiagram.drawio @@ -0,0 +1 @@ +7Vnbbts4EP0aA+2DC4m6xH6M7aTZIsEGSRftPtISLRGhRC9F3/L1O5RI6+pba7dBEcOApeHMcDjnDDWie844WX8WeB4/8JCwHrLCdc+Z9BCyLceHHyXZFBLfdgtBJGhYiKxS8ExfibHU0gUNSaZlhUhyziSd14UBT1MSyJoMC8FXdbUZZ2FNMMcRaQmeA8za0m80lLGW2v6wHLgjNIr11AN0VQwk2CjrlWQxDvmqInJues5YcC6Lq2Q9Jkwlr56X2x2j28AESeUxBkmKvvCZJe5Hkzv6tLamkn7v62CXmC30gnWwcmMyIPgiDYlyYvWc0SqmkjzPcaBGV4A5yGKZMLiz4ZLhKWEjHLxEudmYMy5yN85t/gGVGU/lLU4oU4y4I2xJJA2wHtAEsJG+rziw8g/IMyn4CzEjKU/BYtTOhk7QkghJ1hWRzs5nwhMixQZUzOhAI6WpipBT3K9K4H1P68QVzNGVJjnWZIu2vks84EJD0g3PYEYfNn9v/NeHSRLjxZ377/ekb7fgmWCJpzgjLZiyFU0YznORJ1KPKFAwo1EK1wHkhkDORionkHN2rQckVzAGMWXhPd7whVpXJgFFczeKuaCv4BYboGFYGLSQX9N4VpaaLoJkoPNoYLEboge8rine40xqQcAZw/OMTrfLSLCIaDriUvJEK50BdWQN66i7Vy3U0cDtQN0U9tlRRy3U+3ArSEDnJDMEuKWMzPM95hoGn6WgadQDJJBjq8woixUhL2zzCKw4wWiREfFXGgkSUkjqgekaHISUy10FOqOMNUSGl4zM5E5WZrDXwFz3uc7ELSVPGgol4mA7Y/nuGtMwJKliFJcq9jw2tbg5p7AeFag3gi+AN7Y+eT0PAh/DvV3ew1epC9h9UlgLpjm5CHBzRRQ/O2i3t3oPc9Fwzz+Oer59IeY5hx8HjObYFRibR6L9QwAnABUjJaJfFeCTvt1C3Wmj7nQgnD98HnlGJeXKvyh0G8gfArfOXprGRNBLgj44cr8ZXAhztwNzWKzFOA6f6nvOh49F+Rfiewr5KjePwirDS7LDaskhjqa+muVba58yJuVI50S7DXfO9U/39mbsyqGdq9tj3TlrSGZ4wWSZs64svm+kZ62poXdcTdnI+/mq6mys250bEIOpNU8ZD17+W3BJapj7SpSnpHIV6d/cEOBKO02m2367HxTEUPQS0fQD8jwFCrKqFx/3zqKax85Z1EA/yzs+5d5G83XDkTUrXgtKWdnet+b7kvFt1YLaHBpT5ONEMTWPo7bHFPJanIBKEarfFBd5aomreTeDjbKrvMicobP0BqjeWQ7sNivtDla6lyJlu7F8J+VJpKw9j/4IUjrO8DeTsqvnfCflCaRs9Sx/BjGHHX3xLyVmuzG2WzkgaXitThnLXqySFRisnmflRyZGO6Q44Wn4NaZpr36aYrtGAO/cW1dhRMyRDvRTMY94itlNKT3UA071scmofpz304dxsEYd5t7zmIwvhGb83jMPWHZE5OG+SuXjGFZBI+qat2VBGJZ0WceyizXa26Pqc0tX7tBpPM4Hn+zGwV+xTG1YPYtt+PK9w76KVLR8AYHwpqKmu/GdYfuW25hquD+0/fpwUUTQsDbh8NksI7LXrL0tMj9ejt57Of66cnSPLEf0ZsrR8W0oIWv7aTg8ujId9xS3ZypSD7UWszfKA/q/r0j99yJ9e0XqvJkidR10iSI94PZcRerW/x90m3+4nqZ/iSKF2/IP5UK9/Fveufkf \ No newline at end of file diff --git a/docs/UML/Database/DatabaseClassDiagram.png b/docs/UML/Database/DatabaseClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7a306127c913e1f4b46d53d31815db5245adf2d2 GIT binary patch literal 26628 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

-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 J1qx=q{{=UG8>s*Q literal 0 HcmV?d00001 diff --git a/docs/UML/Database/DatabaseStartupUML.drawio b/docs/UML/Database/DatabaseStartupUML.drawio index 06b67de9a1..ecd27131df 100644 --- a/docs/UML/Database/DatabaseStartupUML.drawio +++ b/docs/UML/Database/DatabaseStartupUML.drawio @@ -1 +1 @@ -7Vvfc+IqFP5rfNxOCJCQx9b+2JndO7Mzfbjt0x1qULMbxUFs6/71FwyYIFFjq8ap9qVyQgj5zvkO5xxIB3ZH7w+CTob/8JTlnTBI3zvwthOGAAKo/mnJvJDEJCoEA5GlhSgoBY/ZX2butNJZlrKpkRUiyXkus4kr7PHxmPWkI6NC8De3W5/nqSOY0AHzBI89mvvSf7NUDo0UREl54TvLBkPzaBLGxYURtZ3Nm0yHNOVvFRG868Cu4FwWv0bvXZZr8Fxc7tdcXU5MsLFsdEPM58EkfHp8+PH637cfD/jl6fu3CBXDvNJ8Zt7YzFbOLQQDwWcT040Jyd7rgKcvtnvgTwwsX1fZCeMjJsVcdTEDJWYkYyEEF823Eu6EGFCHFaQjQIyajYoHy5FLFNQPA8QOoIB4OyhqGGWCqnEzlCM1+i1QP5WKJ/r6VFIhHyWV+no/y/Muz7lY3AiDxZ/uLAX/wypX7u/NlbVYO5iuV6ePtIEWhB60MPCRtbL9A0saAJsq/pkmF3LIB3xM87tSWgVcY5Qpsl7n2WCsZC9cSj5SF9g4vdbs14NM2LiQGO9C6sBfqkUZ+zhl+i2CxV3qvZ904yoIiBU8LwQIQiu4fa/2v51XW7+YyBR8TFjheyafzPz172IwbFrlSLphBypQ0tA49jDlM9FjmwCPdzIc5VupGLBNHUFSb2GC5VRmr+786gzI3PqLZ2pCSx8AEHGcQBi5IxTzMjetWOFyFp8wzMQzzO6Q9f7o+/p69aLKwVFFd7WCZLn+p9QzlZ7xlsajtfs2zCR7nNCFit7U+uga74pjSCkj/V6dbUY9wl76B3EMdhgceJ4BhDWuITqUa7AP2+QaxJCPXmbT7ci6HF7BmYEUs7gO5ySKIY0OiTMMsGPmse+QSQ3q5GCog304ZBfuss9PzidGI7+ZlHPjf+lM8pV1c603XuP4Gvuz7R4yaej4KjHbxxzf5xQVbnZQBhDlqTKhojG+mFq9j2rMnRPzURgihzsgat1nwXNnj4V7O3vCVtkT1bNnauljFvVMC9hoIudfhjUAuysOiFtnTZPs6sKa0m5bY01NtoZvDFVSzjRZxlwuFxp86+lRWbN0YacmU+spLHVK5KVwoyxNCw2zafbXlBW0WiY6+F+8I77Rz1JjKaVOC/36Gh3z8Wr2bUSHi+6S2OEaQT7VQE0lYzXZ2Z8G/bSm1OBCadOL1kIbAlqtAU9rMTqi0uB5ZEIwdFAPkb8uHTUVgmefClmL3roswVZTIWs4FUX95DTVUZzgo7pizVcJ5YhbKIfQr5QfN5SDZ58AwaahHGw1AYL+No/hTMr6dJZLhzZfhC8IQYcvGMZt8wVf+NKUL2t0eyS++AUDFb9WygNnHzWj0F2MQruBUyGX3SM/TthcU1bANyY/veis0FG0VWfxMfNTdBapTgzhCux+3HbUVAddUp2w4TKEWk11kB+2dQXTx0rqd3y+SOBGIreOBmHScuCGzj5wQ00DN9Rq4IZqA7dLfbqgB3T3gkIcebxCx4zZUG3MdtlaqHGJYbxVdckxVRf5VbjT8ojLk3ug45zaw50tZ/bM8bzySN6zHWTX43l79L6koff9dNpcfzwvjoOrBBCoYmUUJZC4h/UwWBnwwKf1kL8xuQyLvmrxNwZuEoFsu72Y6NSLv+XZ3d08wAnFUuQgbI5CchVgFQ4AHJMExW5UAG0lZQubr4Wg80o3s4hueOpKxcgc9L9v2N+Wc0ubLWawV9diz8Ee14Y/suZ8dH1rM4doesj803b/KceGm4Q2mz7/0J8a7PrxR79f+/3B/tcTu2YTv/Z31G9BMPFAbZdHFeo8O8w5OR7ZHfCtPCosuTUeJRt9qUmZ9qf0TvPvadY4zxNWeVPX2a7Ko5ryy2aWb4nH10P+4ex7Y5iN3TPmyM+yQZDgmig72R1S1Sy//iwCmPIbWnj3Pw== \ No newline at end of file +5Vtdd6o4FP01PrYLSMLHY7Ufd01v13RNH+bO06woUZiLxhVjq/31k0gihFClLSq2fak5hAD7nL1zTgI9MJiu7hieJw80JlnPc+JVD1z3PM91gC/+Scs6t/guzA0Tlsa5ySkMT+kr0Wcq6zKNyULZchOnNOPp3DSO6GxGRtywYcboi9ltTLPYMMzxhFiGpxHObOvfacwTZXX9qDjwg6STRF069IL8wBTrzupJFgmO6UvJBG56YMAo5fmv6WpAMgmeicvtG0e3N8bIjDc6IaBrZ+79erq7f/734v4ODX/9uPCVe55xtlRPrO6WrzUEjC5nMZGjOD3Qf0lSTp7meCSPvginC1vCp5loueLngjP6mwxoRpmwzOhMdOuP0yzTppiM8TITd9y3H0A90zNhnKxKJvVAd4ROCWdr0UUfBQptHV2q+VK4KojUEyUlLyEfqRBR4THZDl0gKH4oEN8BqBvsB1QMI8KXVIBL8FweX3DM+BPHvApczwPO5s9CWRy5vVVH2gAVmqBGyAIVODam2tY+pGEDSGPBWtWkjCd0Qmc4uymsZaglFKmg+FWWTmbCNqSc06k4QGbxldQMOciczHKL0qSwDvatQ0yOCOzZ+pdsXDpOqA3/bAwQAG24XpX7X6/LrUfCUgEfYdq4Snk+YuiHqp0PiDzdLsaTjXWpUR3tzShZ0CUbkV3OULEhonRC+K6OSiClZ3ZGHSMZ5umzqbd1QaROfaSpuOlttHogMqLVdStD5HeqzirrY2UgV1/7rYFybKyBNjG9fZ5PhHlkhfkgIaPf8ryxnEExx0MsZEPMYmkm/wnPLvgOuXb3y3VFYGJMwvGoLtL9UUiG43YExoMm0qEtMK5XozD+oRRGX2znLJjQ6XC52A+pKQUVgIkbIxLUARz5AcB+OwCLwcxQRva8GNYAHB4MYHc/wPsl3ES26POT0rkC/z/C+VopNl5yuis5Kev3JwQxaiiIOsjaE8TPucTbLTcKC6E7KROJNd3cWr3iNCbEyRQHQfcSGZTw4MlFB3ScE6UsBhk5zJ785eNc0vjv55LXLS7ZVdSGSwtNJjVhp9JApnO+PkMOechMtDrAoCa11nnOKs2Z4HeLCTW1Guqr8I8pkQSYUb6dStC15TERjtwEGKs6bSRglCWMVcBN0zjOfUkW6SseboaSDpjLZH3zjKgvryXGEu5b5J5stFyhTC3wBwaVpEwvIZX5o8urMn+0i9t3ll1xFM7a+GfxnRwEvP0OCuAR/QO+WFkCdcqjAAaObwF81LIEfN2yRAfl3gkEdKssAXZZ8pPiWOZQjE7rlkHOL5GqTASgbiI4aiIFvmopsl01NVdMd66XfpxzoGnSpoO8K5yDb3FOb9aUaXd2fIOOOe0g5J2ab6jjfDsGB2C3OFCzEYr6pYL9GyXCyPXMCcq1Jyg9Zx0nEa4p9FFf1ZHfzTugsntS553gQGXk+vXhr/Ef6D7586KPnYfVE7t5vACn0K6PzOxFFmHkEEVK0fqCJmyqhjBsWw03p14xhtelDiqOi5Ere6B+ZTMV+F45PPb2Rx6shFN+B61ulMIvVhb7QWiCrp/nVGUx/MJlsdeUkN0qi6Gdog8YkS8J1e/UnV2SHkSOSYIotEhw3CQddj1J/2xRrKfRwxbFzafAbhUEsLYg+Ha7Fj6orNnqdomX8Ji1AKytBb731lKgVzS2TrIX1qNjOsm3V3E7qp3u+0qB4jVMVFJP91DaGTbUzvYXU+rz/dB3LyM3BCL7hX4EQjNxRVElnt549bK1QsDebN4mRee/TeCH0EAXRvDEGRFyLBiPWem/g3IfpfchSg6d15xgDeBz3m6i4bu+ZJDvzr/3O4bxuPaF+hboBCqvd6Oab0WO+lkDCi04T8uVd5YRB9k9aFqe6+DsCleincqoMr3TLnp2QApBUyls3717lkObpyaiWXyzl3cvvnwEN/8D \ No newline at end of file diff --git a/docs/UML/Database/DatabaseStartupUML.png b/docs/UML/Database/DatabaseStartupUML.png index a19ded4600ea7f9e78b20b14cf6be62329483eef..62afae562d35d04722e58ac2a9c36a9dbd04c3c0 100644 GIT binary patch literal 40662 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 Cvzq+? literal 51768 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

-+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 X{kNZ2rkpqgf8=G9rC(h$di4JQl5*IP diff --git a/docs/UML/IngredientList/.$IngredientListClassDiagram.drawio.bkp b/docs/UML/IngredientList/.$IngredientListClassDiagram.drawio.bkp new file mode 100644 index 0000000000..b1ddbaa8a4 --- /dev/null +++ b/docs/UML/IngredientList/.$IngredientListClassDiagram.drawio.bkp @@ -0,0 +1 @@ +7Vltb+I4EP41SHsfWJFX4GOB7ou2vUNHpW0/euMhserYnGMK9NffmDgkIQFyt+UbEqri8czYM8/jycTtedN0+1WRVfIoKfCeO6Dbnjfrue4o9PCvEexyQeC4uSBWjOaiQSlYsHfIhU4hXTMKmZXlIi0l12xVF0ZSCIh0TUaUkpu62lJyWhOsSAwNwSIivCn9yahOrNQJx+XEN2BxYpceucN8IiWFso0kSwiVm4rIu+95UyWlzp/S7RS4yV09L19OzB42pkDoLgbz4Omf5/j1LZkMftBR7MDwJepbL2+Er23AdrN6V2RAybWgYJwMet5kkzANixWJzOwGIUdZolOOIwcfM63kK0wllwolQgpUm9g1QGnYnty8c0gJUglkClrtUKUwGNuNWRo5I+tiU4LijyzXkgoegTOyZLBEiA++y1zhg01Xe+pGS/a4+2sXvj/O0oSsv/kvz2lL6r6LWAFlGNIDy3QjkdmGpZzsM7KUQi/sjEkb4SwW+ByhLWDmJiZZDFl4Zye0NImOEsbpA9nJtYku0yR6LUaTRCr2jm5JCQVR2h4oN6xpLIylBVRBhjrzAgnnSPRItjXFB5JpK4gk52SVsV+HMFKiYiYmUmuZWqUTQLfQ4ST2ruvVsHcHYRN7N2xij6y5EvZuA/s+hpgZ6O5QPs+fjwmA8epTZ2TJOD8SFaTgsNQnKZHhUWQiftjrzPxS8rfNgxFJtF3yffFJGKUgDJxSE01y7AxQK8mE3ucpmOAPa8l08DnoBbjxKY6dcow/o670VAqMhbA9soDE2IAhRwvmZw/QZSIUwHfF/VpH3rtcLTnbY5djXLwxnP8FcIpQcSgRfTKAz/pOA3WvibrXgjAnv4DPZcY0k8a/ynWPkL8Ebp29TCSg2DVBD/xuoF8Lc7951DlW97LWZ5/+yE/9QitEoGc25zl57UPUBS1Vp/gq1Z/YYfwnSaFqax19x5dAbOrHsaf77Yqp3YxouOzkQSKVjGrdDaGV/VS8FCsXY+vlTWJyag5wWnfyYOoG5rYe/FGARgMOQbVE0Vwf+0vQcGYHBQyXVj+5wgrt2/A9obkHBWgng4gDUd01L7m+vV8+tNSEbrdS4wTDKxWb4ExPeesnP6qfHAxr/aQ/HjRx99twLz5CPhz3sPmSOV3gK4Wif768lnrHRbbt7dBnmS04uc4Ev7OBiFuZOV9mgs78O9PGttEtDK7EtuGtjf3dNvY/gz5uua9oA/1abeyoBfNJaxfVLDe/18fV2pqOfZuATddlDpXsaKX1iqLQFrRb23RNao+7UXvsXYnbTodbTBD0zlwH44gykkpBnxJmEo4TXxgvmhwcFS2OX7/ZrF+DwpbpZ/OMuc9HL5WZ2bY62BUDgcHmRv5oWAiMnfN5MHAKQWm8H9Ws51ilMGempTvfDWVyrSK4jDL2dDGcY4P9/AVauyZvcqECvhPafkoBJ5q91W/S29C37uaG62Wf5hV3vEWfNvTrLvIgrVX15vvIUeBfcJRnoeFoT8ZDjG38xGF5gZ+rl/8F8e7/BQ== \ No newline at end of file diff --git a/docs/UML/IngredientList/.$IngredientListClassDiagram.png.bkp b/docs/UML/IngredientList/.$IngredientListClassDiagram.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..73d87e8a2705b3546562f662d1036f8dd6b2ae93 GIT binary patch literal 29370 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�YBtO(}v5q0Kno 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/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file +ddHNEoIgEADgp+Gu0Fid7e/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file diff --git a/docs/UML/IngredientList/IngredientListClassDiagram.drawio b/docs/UML/IngredientList/IngredientListClassDiagram.drawio new file mode 100644 index 0000000000..4a9b3d524f --- /dev/null +++ b/docs/UML/IngredientList/IngredientListClassDiagram.drawio @@ -0,0 +1 @@ +7Vltb+I4EP41SHsrsco78LFAd7e69hYd1V370Y1NYtWxOccU6K+/MbFJQgJkd8s3JCTsx+OxZ57xeDA9f5Jtvkm0TB8EJqznOXjT86c9z3MdP4IvjWwLJHKDAkgkxQXklMCcvhM706AriklusAJSQjBFl3UwFpyTWNUwJKVY18UWguEasEQJaQDzGLEm+i/FKjWoG43Kge+EJqlZeugNioEMWWFjSZ4iLNYVyL/t+RMphCpa2WZCmHZe3S9fj4zuNyYJV10mzMLH/56S17d07PyJh4lLBs9x32h5Q2xlDDabVVvrASlWHBOtxOn543VKFZkvUaxH18A5YKnKGPRcaOZKilcyEUxIQLjgIDZu7tQuS6Qimwpkdv6NiIwouQUROzoyGzNh5A6NinVJSjD0Cyyt8BG6QxMMJhCSve7SV9Aw7mp33XBBH7Y/ttH7wzRL0ep78PyUtbjujieSYApW3tNcNRyZr2nG0M4jC8HV3IxotyFGEw7tGOYS8NxYe4ZCFN6YASW0o+OUMnyPtmKlrcsVil9tb5wKSd9BLSqpQFKZA+VFNYm5nmkIlSQHmZklxz2AHtCmJniPcmWAWDCGljl92ZuRIZlQPhZKicwIfQD3nufXuPecqMm9FzW5h6i5EPdeg/s+mJhr6m4AnxXtwwAAe9WxM7KgjB1ANigYWaijIZHDUaQ8ud/JTIMS+dv4QUMC5i7YLvmkFGPCNZ1CIYUK7jRRS0G52vkpHMMHcsnE+RL2Qtj4BPpu2YePFpdqIjjYguiOWQKBsSY6OFo4P3mAzgeCJb4r75c68v75bMnojruCY3tjuL9EcAZUMVIy+qgJn/bdBut+k3W/hWGGXgibiZwqKrR+WcgeMH+O3Hr0Up4SSS9Jehh0I/1SnAfNo84gu5e5Pv/0R3Hq50oCAz29Od8tch+wznEpOoGrVH2i+/5fKCPVuUbRHVwCic4fh5puN0sqt1OkyHkl9wJCSYvW1SBc2U9Fi13Z9o2WNwHOqSmAYdVJg84b4Nu68QcGagmyN6rFiub6UGASRU7swNJwbvWjKyxhfhu/RyR3pBDcaULMCJLdJc+pvt4vH5pqIq9bqnHDwYWSTXiiprzWkx9VTzqDWj0ZjJwm70Eb7/ZHyIfzHjUvmeMJvpIo+qfTayl3mGTbboc+zU3CKWTG8DubIH5NM6fTTNg5/k6UsW3hFoUXirbBtYz93TL2p0kftbxXtJF+qTJ22ML5uLWKaqab36vjamVNx7qNk3XXZfaZ7GCl1RIDaBLatWy6ZGiPuoX2yL9QbLsdXjEJxzf6ORh6mKJMcPyYUu1wGPhKmS1yoGdLnKD+sll/BiUbqp50G3xf9J4rI9NNtbO1HQ7GFpOC4cACep77xXFcC5STd73a7BlkKfCZLulOV0O5WMmYnGcZarqEnIoG8/OX4NozeTMWKuS7kamnJGFI0bf6S3ob+0bdTMd6Waf59o3X1mmDoK6iMNLMqr58HygKgzOKCi80FO2CcW9jp/i8e7lz5+u3m+FqNM4GL8//xD9Iy0vx52NJ6NxT+ol8dLTW31/AbW/39bA+cvRbQuxodR24B862ZUwlQmyAVLOD7/x0doBu+fdJQVb5J5R/+z8= \ No newline at end of file diff --git a/docs/UML/IngredientList/IngredientListClassDiagram.png b/docs/UML/IngredientList/IngredientListClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..be25774c257516a4d1b224c62fab205a14fd3e57 GIT binary patch literal 32616 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�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

>8WDYw-lS!{c+Yqj@2Qh~CA9>>CmK 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 XDy+hOetSg({@qg1Q7%@reDps6fO$M? literal 0 HcmV?d00001 diff --git a/docs/UML/Meal360/.$IngredientListClassDiagram.png.bkp b/docs/UML/Meal360/.$IngredientListClassDiagram.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..73d87e8a2705b3546562f662d1036f8dd6b2ae93 GIT binary patch literal 29370 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�YBtO(}v5q0Kno ze4Wzkn8+JJf(9oQWZ5P-FiJ_Z*Pwm6l5z*?XOgr&T;;n^KXdiuY8#B=>{aEuQyE4= z*4hwjj%Kp)Wh(^1LT@U_zg!6vWyCQ?Wc!!g>(CYV>D6XIhgDOK`7pPz5ClcWu|UhC zVhG?^T&rBT%!*2!%Eme8hBLYg_RX&`%%}tQP)a?2{RN&-Htp53ZeIav_gv?qbSRj! z?HXlG+nlI=xj$Nfji^GLq1+R;^XGupEj%Dt0RkBoO8ot4DKv9L9a(NIx0|x394hjM z6uQ3gW_pD%dIU<@#+qnX0;!lYDut|Z*!&nV!?xG0#r1Pa&rb?|`F=NBZ~8TSMv7pm zpsok%*T>jSEa*b+4NT^s#z#u1BvX0&Mq+B7F`@6xA+R>n8qL<4)8J&wAzbsr1Bdy$ z;Ox~|_@wlhnL;cHr<1rY<@Ncu5Qz>mP!l=W3hFkz;-Aua1?e%PofLYKD@+^JMik(_ z5z(b>fRsi25wNnPr&W4`vr`eeJ%_{i&O$YG z;S~!L`8(Ich|7fQcZvlyh(71(f#bzyY#l6iDGe9yMINs%a$r@KNB+Z<(yL)p0*U%< zI?SIDpcZWNV(pH0mBEnY_hz7j;rVqZ$ zHge`oPkk**#gBDQOS+st=d~ZTzCMZrBkvFHxw zQ~+4OvZQM8C)#RlOV!M)=x=QIpacCDwdEOx>li092)1rRj)Fbl?V-5Ztif4Kn>5R{ zOPM;`2*98t9@LAr!9o>ix{)oYocwulQ>}f@z>DnKPps@p;HKf~Z}UL%>GPa0Z9~a2 z?g+|m&TA8rcl`(cpy}#xSK{}C2@7wSMnbT7ka_XX7o^wH>L?`liKi=L=H;hx^@dXW z-+2x6wmZ-wB){#BJU?bjctXmj+7$M zJ^@-I&!B$NYs4fxiG#=IZiMFbPgLM#u=v|CUO}&qjLmU5E8SknVAjt7mZDEB{ogKJ z?%i_IN1BHX<;*Y<^=QnSsAVTX9-7&_q*%hv;2MfUdm-xPi3q{`0+8}+i+T6LMf z_Y#Q0SO`eZigp-d1jPIU-dl1;scr+j1?c+nc^ElJ9Op3c!_v5~Sg|6k z0eOmQ^DhvlBSVhhKvkv<61}r(q9UC<@!{g zQ1HOGr=G}7=+yy-D!q}AxEc*@NNHM0$|v(oamN}t`>>_YB^nUz{-isx?7FYg0&`fYooZ%^mQSoe$xsL?RbPRK^RxHcyI|Se(;zE2_7V25ZYB7 zad%gO3dt+5eqmQsgpd?pln8RAQna$|rEfx`%rfeQ{ga73=Q)*<5i72LCPt^K8Ky=n{C)OEE3m`qMs_k+ulkV5Jme zrab$##GAmUod^v}yG{QqMTdy)s!0Y@{b9#CBQ8x8p<-h!WkId##@5?QQ{}BL3{n}f z#!9(XHQ8ltWzwtf8`_k;rd{u^>k4WHVo9lJI%;TL+k+#e6yZX%sdlT4?rXK^x z4_rq8aovXAd~T~?KEOZ_CL2_wBP4>4z5U2 z@17D#CQ&t7uH&VhtXvdRdpkB*FRj{~b;$yql2vf>+Y&a=8l(f+z~=di;~)UPvwUnn z{WWU_-dr$nhf^wpIr(DdNpU%nR`IWc+yitfVdd7J{`GP%EEiD&0L( z4%vkgX`q6BpK#*C4SZIADu~6=(~wn-Tp*4HzU*4>oCv%tS@l<=Updm$dkMY*BA<+z zsHny^PmT%_r;T6?(+s+9N2;!xTL``Jny%L`l`GrONA<=~E+Px;Bj!1pF~=sJ zd$}WB?wY7q&>VXc_zjUa@Go>leG~&2vL2AW|^RS=uKiMpoFK5pJ5!t4L-hgL8UJW%6U#7Z^Z`}R}~ z&k{iO)(|Vh1|b05U*n9;yh`W4^$5SMqiVs5P-a^lLheMmRLh|5gyHjf|C90S2l4~e zL&P2OS`D&59on5bk$_4SWAo7mB|kV3th9n7f*bw5lNEOkDxA~5unaAaN*sp6_fsI(_69Y~?p)12bk}2PG z>Ev70ax{6c7safUNEJC6h!vXbQU7fHBL@@9a^QL2XB{gchU&Pwevs=_7I~|699`CFyB&@S%<}*8JpL#a# z-oX3*#2*#I@&3vwLtC$&+Xmdkh_%n>BvCOl-Zl=>pbD@)z1D)CLB1!H*ctShR;nt_8lvXrtXee+2ZGgore}DtXTUiJ!#E4 zm>CGcia+c2jk!X#9D)advW1*!-gk}irJ%Mm2NubU$qy7;p^27 zb|EU(#agHrpwb3kzO+6S?c0BotBksS_By0M(S$3u+q&DzCH6%=%g6oU{)fe}E|G|j zNgqQ8`P%QgQh#B+)~+CN1W;6c+JKj+Cid5DRIuFhb~6K*`+d-WQprs>uCCuBzBdiM z{KYvx(y8s3BUUWgw^pQ6?EP2Ihwt{MlaI>*r&ePx38ZHcKjr-oDL<;^1FA8E>0 z$5YkCOb4Jg{n>7BIGv!8_pQ(yOuvV-`BBEQAx(j_dhkX0+qC1XV|CdnT?D!!JU-}m zXhV&z@__X1>}aJNqclhCW@V4Z6`@me&mZy8S@?{7>f%bh6|0@|uoSX6Im+?MUDmG$ zyCMC%v5NM=gF!lf4A%~yhQihxx_YVBS~BqzOKbxZ54d4fe-JBb__m%EK(S!UD4!Z`gLS~t2O z8s|%gHYR?&Z@%(3vaiZDxW={)p1)>Ts#FTO9dQ25@EZf^_;8ZPo0)>JgdxV+pP3oO zmz6)Z@e1o$=CqNpuf8A4>$MuZC=&PPG_J7xcf0zYXu(HNPB^Ko2Km_27F?&qDyR3e z`m54jkzQ1JNkxjoy2pN$8I`F|LLr)SJqk*X?&m!E%Ia})`6H>gvJ2+^$-O>ZaWerjJ z;mO!DWEcHSr-sv4ICIL%l|Ym!l%p3{My7I@-7i3zc(3n%W&@wquw--SGVP1Vgw-e0 z71^#c!QUCOegt*~Vtm~UsOWv-c4g=C5-UpZfW>J|@?}^n;I`PdgQfruyxADt-_>7K zq@#5exqx5)wQKFF<7`&GWXoiS*YI*s&Avtxnd181Q^?Jjju7hSLO|JX-8h(G(Cu1l z4ZOJ03Cp#;3bHGH7nGjdfrqe+Wx!oQBvgM{XyN;iBd8iMlh`@@4iXd60c#WKP4F*8 z0_I~K?`x1^Tv_6O{|&@li zSsL<)v&!674J9(Oqr(n3vov8`*_l-CO`T=662P{)nqjnNLH9~64j@NGf$_76v!~I{ zo&{1ZU#*5&u0!MH(6<!Hn{*MGo^lM#K{W7_n~I*r7)xW2 z^Rld|;f}WeK}3H76tT}8>@MrPg~-nQ)J-t9%8RJUmOX>>mcec~(F9f>m|a*rH`EVn z|MmSYO|c|0x)8d#>0!w-V@A^6^;j>xf)tScT^$GjWrRMFjeW|PouwYw9)zWYqyK$t6$Yo zt@9&R<{x_$knoM%=KUu7?{zjtwW*&&L3|14zfKRz%1LudbZ7pe$l7t^_2-v z=z_*Cx`3K@iZ3a{@YmDQ9ywnvO>*0$QR4xZ5@#XirH~y@4B%hWU~kQ#Uas7P##0eF z34aJ0#A@#$EdAV`+3t7qSDA&|TK|Bz2ArW5GKd^}>R5hCn(SmVW4jY+Qp_Ls6yTl-1Ywr3sJ4a4 ze|%9Qk9i?N?q5-y?P(C^ME$1z&QGs6J?=<9@#>@J+gp@{QbWdaMyqUMD|IH5mQFQ8 zZUcOuYe}%POS?6e1Gd()&L!&cd%~^pUS$=n`SMEAc_y>loo8kvMl!qD6r_L4Q#My% zooqK`*OziG5;37V&W$jm*@fs7xO`+c8&Z~O3&*%^B=4*J8reANc4ok8!_#^ zbyK)&lmPwELWza1*c=PN%ES=>2c^4U$aI#GAd&?20fFQf zM$#T!%VYdc^*Gkmgi=@fk~8_b4hB~son~>Z;laN-nE6t}d!Uyd(fpddOqWq8{}kJO z)txEgyN~j#xXkiC&rk8I9b!5=3ieS#8Pk%p)^R&c-6Tr)`5v`C7|31_4d>br&?@2` zoD^U$%w>>D2jx)O2O4dk8roivD^}v?tMV1hab}Rxy_zd>Mj2@2Ql9+yb5UPRLoyYT z0c1lDkR@HCq6`l8)jJ!rkPU%Qx)a|KAfqaY?`OHKB(5FN@`Z6k#pk{C8KpTsQmbvZ zZ_lk{``EoB!!dY{10MZ)hv|XB)yN(tK>(a&sx6< z{RC(8cB9~m5+`u@SPkOYEJES+H=v2duOVwC-L-v>L~4Q=`RX1 zGcL;(nJld2Mb7?i6+LHVqm4s5X5K7k!zEp{k5Fd&TN{ZBwE1=_ycHwXafGZvLv&vBvC9B1^|Z{MOD=}T&GswGR!HjTOPXQY4c-Gv)i{2mBgmK6i2Dw64^X&EGM@$pRv|pkfGZ@QM8^6{z>m zNxyU>58eDL`)Ml`H0{E*CZKm1X>Kg&ru2sFu3i#bk%O0BmdS7yCOm~i)T`Obal4Gt zw;j1J7f0vzF7xCok*$TWmP=}_>=1aUY*KD4APV}|4Zz_?PyS=sPMOm9yy}0BF;5a?D~05!OWe{8>c2^UJD{>G%Eb4u z1@&&}9A)zysE<$ElxyM+rx=~*8|_90Ry4fky6_m}JQ8|>lLo{qPH2>cJ5t|VripYK3t%@h?a`d(XA9jG112jPY}> zAonI!De{A!B4^-?xd#Zey1 zzI@P=Az=sQngFy39T!`Tyk#jIomo#Uaf00QLRlS`xVj0f{5l55)jk;Q3#OcjnufYP z&#u3*EZ!s>W!);RA<->CVw6zaB6bp$Jx#$Z1r_edm{iK|4H;(2{6%us-;}k2x6Qy$ z31n)2rE}_R?7x4z)}>te_Ik+MvC-NnSdgzb*f-$P+ame_PEVSDxC~B3e(Xl>Ch|AR zE}i4JbYHOF>({r6gZL~G!zQNHiqw}05n1LKeXiP%jV^j)WqS7?Xl|WJ=vX=M_m|cP z{uVN|GMewwl-p61A;G2m;-EjRB|xjF)?Z~%6|&a%E4F0s`z+~Q5&vftg1sI|TTy1D zu0MoirT-uWP)0V8i^b(IdG>f4(BlCRgrL(^lh4N}LlWT~Fn6Ck=4!8>wPl>tx90R( z+=SoM-*{FYmZY&6n=YSU^o*q5sO^I1K>|PZM%uaf`1^lw!(P>~tCTjg=!JAn5vsJs zbBfIuY?rPo-i>xW1SneQnJ*%^EEPF(`$2YbTG-KP)Eym`gp`1HQ3f(1Q|Vm`HRST7 zU#~HW$jb4x_{f$oVuothc6bz@sk%sIt@gkk(p|=%Rf3Qk=Eso?6pKdCy7i9F*v40FA}>4k{SHliG-P6Pb8(2<^= zH0+8XHwW4H0`>EBr5Ws-Uz|qd{*h_^8IlI?IcFGETHWEr1<-~|HDnkm6W9`x} zB*PvpsZmhF;TPAhy;v2N&9ZmZob0%?2FM|ebt}Np{eWFc2W8aev!W5b_rxgHtMyqR+152p?nGgS@!hyBkZm@&G z)Eh#3y}*$g560I*A+GMT1ERa}E3Ck*ZczIoOP{4FZmelTWk1o_PB84D2;q`4rgIda zSF@xw@Zzh84G!zokS>b;!6APZEvp>Zc29B3qa_=)*N|~}OOp0(N-zyY<+sosPrbY+ zo20b$f?h+Wc)2jNBDOb6XE~5Pr`Jw>UU!eOG5~qi$im^e2`NIBa)xLs0OT4d02W!M zxyYT3M2sPVg-NN74!#-8(S5plMmVdEib-DVr^WM&(4}dM)TVl!P@{W3TlP_=Rv40I zDb1~CP2br8JAnh=g{HpN{95!i$h9ZMoY&fdM(-Xl`J^fr$lj@;V!HKoq?Cd3%=1hK zR)L~-NA!FnMrnJ#bx8n?Bs@LgB!Vk%{Yq;i#@sUeOL1M6kW~@f_6I{If{wJWrdbHp z3h&y##w7iL5V<&m>Q9Wl4RZDQ7ivyGJUN7Vltb+I4EP41SHsfWJFX4GOB7ou2vUNHpW0/euMhserYnGMK9NffmDgkIQFyt+UbEqri8czYM8/jycTtedN0+1WRVfIoKfCeO6Dbnjfrue4o9PCvEexyQeC4uSBWjOaiQSlYsHfIhU4hXTMKmZXlIi0l12xVF0ZSCIh0TUaUkpu62lJyWhOsSAwNwSIivCn9yahOrNQJx+XEN2BxYpceucN8IiWFso0kSwiVm4rIu+95UyWlzp/S7RS4yV09L19OzB42pkDoLgbz4Omf5/j1LZkMftBR7MDwJepbL2+Er23AdrN6V2RAybWgYJwMet5kkzANixWJzOwGIUdZolOOIwcfM63kK0wllwolQgpUm9g1QGnYnty8c0gJUglkClrtUKUwGNuNWRo5I+tiU4LijyzXkgoegTOyZLBEiA++y1zhg01Xe+pGS/a4+2sXvj/O0oSsv/kvz2lL6r6LWAFlGNIDy3QjkdmGpZzsM7KUQi/sjEkb4SwW+ByhLWDmJiZZDFl4Zye0NImOEsbpA9nJtYku0yR6LUaTRCr2jm5JCQVR2h4oN6xpLIylBVRBhjrzAgnnSPRItjXFB5JpK4gk52SVsV+HMFKiYiYmUmuZWqUTQLfQ4ST2ruvVsHcHYRN7N2xij6y5EvZuA/s+hpgZ6O5QPs+fjwmA8epTZ2TJOD8SFaTgsNQnKZHhUWQiftjrzPxS8rfNgxFJtF3yffFJGKUgDJxSE01y7AxQK8mE3ucpmOAPa8l08DnoBbjxKY6dcow/o670VAqMhbA9soDE2IAhRwvmZw/QZSIUwHfF/VpH3rtcLTnbY5djXLwxnP8FcIpQcSgRfTKAz/pOA3WvibrXgjAnv4DPZcY0k8a/ynWPkL8Ebp29TCSg2DVBD/xuoF8Lc7951DlW97LWZ5/+yE/9QitEoGc25zl57UPUBS1Vp/gq1Z/YYfwnSaFqax19x5dAbOrHsaf77Yqp3YxouOzkQSKVjGrdDaGV/VS8FCsXY+vlTWJyag5wWnfyYOoG5rYe/FGARgMOQbVE0Vwf+0vQcGYHBQyXVj+5wgrt2/A9obkHBWgng4gDUd01L7m+vV8+tNSEbrdS4wTDKxWb4ExPeesnP6qfHAxr/aQ/HjRx99twLz5CPhz3sPmSOV3gK4Wif768lnrHRbbt7dBnmS04uc4Ev7OBiFuZOV9mgs78O9PGttEtDK7EtuGtjf3dNvY/gz5uua9oA/1abeyoBfNJaxfVLDe/18fV2pqOfZuATddlDpXsaKX1iqLQFrRb23RNao+7UXvsXYnbTodbTBD0zlwH44gykkpBnxJmEo4TXxgvmhwcFS2OX7/ZrF+DwpbpZ/OMuc9HL5WZ2bY62BUDgcHmRv5oWAiMnfN5MHAKQWm8H9Ws51ilMGempTvfDWVyrSK4jDL2dDGcY4P9/AVauyZvcqECvhPafkoBJ5q91W/S29C37uaG62Wf5hV3vEWfNvTrLvIgrVX15vvIUeBfcJRnoeFoT8ZDjG38xGF5gZ+rl/8F8e7/BQ== \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp b/docs/UML/Meal360/.$RecipeListClassDiagram.drawio.bkp similarity index 77% rename from docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp rename to docs/UML/Meal360/.$RecipeListClassDiagram.drawio.bkp index 2db87a437c..edc1a7c2e6 100644 --- a/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.drawio.bkp +++ b/docs/UML/Meal360/.$RecipeListClassDiagram.drawio.bkp @@ -1 +1 @@ -ddHNEoIgEADgp+Gu0Fid7e/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file +ddHNEoIgEADgp+Gu0Fid7e/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file diff --git a/docs/UML/Meal360/Meal360ClassDiagram.drawio b/docs/UML/Meal360/Meal360ClassDiagram.drawio new file mode 100644 index 0000000000..0f76c6ff83 --- /dev/null +++ b/docs/UML/Meal360/Meal360ClassDiagram.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/UML/Meal360/Meal360ClassDiagram.png b/docs/UML/Meal360/Meal360ClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..1c309e69d18819872ef48a5f0705b3a996d332e6 GIT binary patch literal 27414 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 z z*cNcEPjv#u_-H=3M>D^{lyyNIF1S?nn}c*x@JMKtDT@^eFAqQS`T~n#YQS$~vTPxt zO zNPeZF{u3)S6_^KwB9+=5}70BJR-$^!7zux$Vb^ON`n-~kkDhtc(A7E z4^(P1V#{;E)kGOgZV%=}+SkI+G}Hs&YsjRa2t;90h5<{9KJbFK^*mwV_jP<;$jq2> zaf5!i4WuEmw!qMzhmY<@B}%cP?=8Z3v0POiA^=Bx&bl9k zkq7n?HCtI28v=AA)Ib(nPg~L^^BwBbn&OCy7%d-!^b*Jr-aqIF0GY?`e{ zUa<9vEZVXh$r2mnMcJtWSm2Rlvtzf!m2f4SN;5~T+Xad_PX5G=_Pk!3yQEH`<^BAKiAWN_%M~HQtd#y9m<0dXa=r!jZ z7Q*bplQJG)LWId%d)8BoVwgt4$$`h^#?&i;EPRE0xDw_5pbqAh-Zc<#u}7-cVXu%V zMjo6vxu$^oW(zToHwWcd5W)_DEGr!(@UBN1cypNURka%eTB$Z*FK!(bl{hGXH;-m_ z&p~PGG3`jo1&_(aqjuQG9!y`#w=$&5op~^0%;3ZXiXA3fQQ*p%Cn4pocI6Zaz&xfen`k z0S1a<_D=~q&|b6`R%^`<>8b0bLXlO-tqNF%9PeuqBF=t)*BqMzXU!_&W&-*4k&45U zaOQdAs#B=MBkT940YLFpfOzT+f>4;$%e`$`xVG@nv-1FPAAuIp19l}&v~y~srrreC z=@-$k6k(QNHSo^%x3xZ4wbktrMup*5S`vu|4C6QGA)Ck3Ux5#%qbvVtM+iT`nIKym z#QR~5wyy4Icd?wHI`QUvWwt;Q%4ex-dqL@PCA|;53B{G>~oDr zohuoPdoI@Iks^mCOKeKd^4m?mLU@6k{G{%Eaoo$enkViq_tIgK^(o~80ow0$SeYB` zA~=Uq~ZZ!eioC`FXH|6>-gO=hhy&^UoGC74%p6?Vc+x#l?*tb>b`T6 z%&Ngdh(0nnFY92krP>wp2{pREM1&6jgd=sWw63R(-|(#wgjtgluVrYc`jlSpKV5jE zBRzU}{EJ!%hvZph>#u|#+JkXNoy8^N=r0G{4nFKrB4`e-GtxR@7kV2gKI~I>BIts^ z-EQQ=*DiErWowu!va%tv;#+;92SY_+J$H|WWa73;eXvrz-y3kkFE#`%785f?1mAD2 z+ff+7H7PC;=hMoc04xWc`lt8sOZn=2Zc$~pY`A6gqWeBLSkpd#@{YTlBSBp;F)9zp znyZ%2kAgzGfGZXSM$uOHs!&}oN>sSMzpzZZDLrSHmxHVjiA@YsdU*fN3~uY{vZCQ) z<-zIagMO>{4XsY739Pp2YMPa(_+Y&^KQ*KBqN8dj&&9(Zg1Uyyd$!yujhn}M;MO6? z6ZuO6OW59EJqzjbQgt>S1bK2%z0DV;8}ViN@x-LzFMii)4@|97oydM0HO@5{`-eF% z&nLY5pz518nscXg7qCHi#Gl+yZw{!taD?58Ot7$-uX$|PA}DQi5pCBXN+YIJ);qfa zU(=A#XI`u|cBM`2p7)Tu5=)`WVF4$MM&}C{=#36Ny$K8|9U4m5&FNWn3In1?h|Ie% z+o2rn$y63X1G$+R5&cWS)?!U}3;nsHt4=`vU2YMHL8zks1(^_>-aJxNSW!~GW zl%OhC_EFUr+?4qZK-viow1z4zKEF0y_`><`z08k=|LW{dz9a53mI;4s>Ll_v0{;De rq@Ld&YiYsyY@PqAg|8h$^p9of%Cj{agM0H}Y}8IYBi%dO4hQ@LF92h9 literal 0 HcmV?d00001 diff --git a/docs/UML/parseDate.drawio b/docs/UML/Parser/parseDate2.drawio similarity index 100% rename from docs/UML/parseDate.drawio rename to docs/UML/Parser/parseDate2.drawio diff --git a/docs/UML/RecipeList/.$IngredientListClassDiagram.drawio.bkp b/docs/UML/RecipeList/.$IngredientListClassDiagram.drawio.bkp new file mode 100644 index 0000000000..6872fe0f78 --- /dev/null +++ b/docs/UML/RecipeList/.$IngredientListClassDiagram.drawio.bkp @@ -0,0 +1 @@ +7Vldb9owFP01SN1DJ5JACo8F1nVS2aoVaduji01izbGRY77663cd2yROQqFreUOq1vj4+ia+5/jkNutE42z7VaJlOhWYsE7YxdtONOmEYdCNYvilkZ1B4qBngERSbKBuCTzRF+JWWnRFMcktZiAlBFN06YNzwTmZKw9DUoqNH7YQDHvAEiWkATzNEWuivyhWqUWDeFhO3BOapPbWg/DGTGTIBdud5CnCYlOBoi+daCyFUOYq244J08Xz63J3YHb/YJJwdcqCwYJOdz928ct0kqVodd/78zu7tlnWiK3shn+SOV2SB5or+9hq52qRb2jGEIfRaCG4erIzAYwRowmH6zk8DJEArIlUFMp4ayeUWAI6TynDD2gnVvqRc4Xmf91olApJXyAtYjYnTEtlFRHGXsSTXglwF1BJcoh5dHUIatAUbb3AB5QrC8wFY2iZ0+f9NjIkE8pHQimR2aBmmV3NYIdkW4Fs2b8SkREldxBiZ8MwMkvsGQi79lBsSkX1QoulFTGFDkRWxck+d0k0XFiu38B72OC9E4702UIJ3OoWru5Rnk7RshPGTLPzpCTlSSccN6eMYszUN6A/AQGEcaKK4rnfNSlB5VRBsRR/yVgwAZqZcGG0RRmrQU5ejCzUQXHlSzSHZ3woYia9EvlpK6ohAWsXrDiHKcWYcC0MoZBCRgWa8qWgXBUV74/gB47VuPu53+lP9B77o6Acw48Ol2osOOwF0UIjBCS2IblqVc+rx/C4pJyETlXQ4EwCiloEVOOY0YI7w7Ezz+C/CM6AKkZKRmea8Ml10GA9arIetTDM0DNhjyKnigqdX5rYGvPHyPXVS3lKJD0n6f3eaaSfi/Nem2ksKMej3XeUkSsO/xjzMG7xyQycP8CTRoGx1BHC2MBX0sxWIu2ytYCH8RYRTNXBVcZ/4K4SwkjB4hEbq3nVwdtCS0MU8W78fZWZaNDEKbuciRlKrsBcq+UxT/GG/UuSgX2ZoDspso/IyeBFb0LyKziX8PLOvXzmHJja5jN3s2dowQji3tZNy1DPDUuOpj+SBq0RZfrwukRH4iXiWGSWrxo7l9fQhzpSHJ7mSEHcO5Mn9Q80sJfm9cOa167XvPYGgxbOuy2cD8MzcR43OL+GYf3tUzEFPb13ERMzMg5WCypfH4WtFJHffMyzmve9cS529Lod9U/W6mtdcYs04/6ZlHlz6Yrf2xW/mfRhcBrp5+qKB21dse0+mp707ibV85+EqKLz/nTA+ExI6WD73uktJlW/4Sr7sWhJqYXgxdL81nmui3l2rnsxvo89A8PTzsAwOtMhCJofEhskE45v9RdZGGGKMsHxLKW64DBxR5nrnGDk+ibNUKoyNyPFimOCLS1kS9VvfQ21N6M/lZnJtjrYuQGHzZpFvcGNA/S64HO3GzigXFyMvNWPYGdQM90nvt5i5WIl5+Q4y9Aowqk6/mc3wd6X6qYWKuQHsSVfEoYUXfsfs9vYt+keRXGMXfMXDQK/+bup9fFmk3ZV9eNzLVG/dySRqUIjUSHG/R7b9AnD8hu6CS//JyL68g8= \ No newline at end of file diff --git a/docs/UML/IngredientList/IngredientListUML.drawio b/docs/UML/RecipeList/.$RecipeListClassDiagram.drawio.bkp similarity index 66% rename from docs/UML/IngredientList/IngredientListUML.drawio rename to docs/UML/RecipeList/.$RecipeListClassDiagram.drawio.bkp index 61549e7a0e..edc1a7c2e6 100644 --- a/docs/UML/IngredientList/IngredientListUML.drawio +++ b/docs/UML/RecipeList/.$RecipeListClassDiagram.drawio.bkp @@ -1 +1 @@ -ddHNEoIgEADgp+Gu0Fid7e/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file +ddHNEoIgEADgp+Gu0Fid7e/SyUNnxt2EGXQdpNF6+nTAjLFOLN8ufwsTeT2crWzVlQAN4wkMTBwY52kisnGY5OklSzceKqvBU7JAoV84rwz60IBdME+OyDjdxlhS02DpIpPWUh+X3clABK2scAVFKc1abxqcCppm+yVxQV2pcPSOb32ilnNxeEmnJFD/ReLIRG6JnI/qIUczNS/uy+lP9nMxi437sWAMlr3HSfRD4vgG \ No newline at end of file diff --git a/docs/UML/RecipeList/RecipeListClassDiagram.drawio b/docs/UML/RecipeList/RecipeListClassDiagram.drawio new file mode 100644 index 0000000000..ab5a5e0134 --- /dev/null +++ b/docs/UML/RecipeList/RecipeListClassDiagram.drawio @@ -0,0 +1 @@ +7Vlbb+I6EP41SN2VusoFUngs0Ju2bKtS6XTPy8olJrHq2BzHFOiv33FsE5yEQk/hrVJF4/F4bM8383nitMJBtrwSaJaOeIxpK/DiZSsctoKg3QvhVwlWWhD0Ai1IBIm1yCsFY/KGtdC30jmJcW5kWiQ5p5LMXOGEM4Yn0pEhIfjCVZtyGjuCGUpwTTCeIFqX/kNimRqpH/XKjmtMktRM3Q3OdEeGrLLZSZ6imC82ROFFKxwIzqV+ypYDTJXvXL9cbuldL0xgJvcZMBq+eTf+6HmxuMjw8D/278Pdz1Nj5RXRudmwWaxcWQ8IPmcxVka8VthfpETi8QxNVO8CIAdZKjMKLR8ecyn4Cx5wygVIGGeg1q+v1E6LhcTLDZFZ+RXmGZZiBSqmN/BMHJkw8rumvShBaUcdLUs38OgERhGZQEjWtktfwYNxV7PrulMyWt2torfRMEvR/Lr9+ylrcN0DnpAZviW5rDkxX5CMosIbU87k2PQolyFKEgbPE/AOBq/1lVcIROC56ZBcOXmSEhrfohWfq53lEk1ebKufckHewCwqYUBCmmQKIkdjrEYaMAXOQefeAuNXRCO0dBRvUS6NYMIpRbOcPK+3kSGRENbnUvLMKB0C98DFPfCiOu5BVMc9sMKD4x40pExf0RJKYKpzeLpGeTqCzAgiqtAZS0FY0goG9S4dMbrrBuBPIACCKJGF8+z/SiiB5+S2TJsSSisiG14UT+XW4MohoWGNt4XOsF1KHoxHlYjD2CktKCwlcYyZCgwukUQ6ChTkM06YLDze6cMfMNLA+9FpdYZqj52+X7bhT6kLOeAM9oJIESMYQmyBc9kYPe+m4e6QsiG0bwR1jxRA4W7OpaTATmNszx3/fwGcAVQUl4g+KsCHp34N9bCOetiAMEXPmN7znEjClX2hdSvI7wLXjV7CUizIMUHvtPcD/ViYt5tIY0pY3F/9Qhk+YfCjyUOzxTfdsPwAKw19Tal9FMdafCJ074amGfbKYTHOIBwTuXWU5h+YVYAaLlDcQWMVrto6LRSDWGJn4l/zTGtDTOyzy0f+iJITINdN9+hVfGD/AmdAX1rpUvDsEDYpHPRaJT+BvITDO3fs6TzQvs0f7WTPUL1ixJyt65KhahuG7DS/wwx6RYSq5LWGdugLxGKeGbwq6HwdQwdlpCjYj5H8qH0kTupsKWC/iteDFa+eU7y2u90GzL0GzO1L8sExj2qYn0KzevpskILqXrOI1ulrBqsolcdHQSuF5o0rc6jmcyfOFx29T0edvWP1vaq4ITTtO/bBI/Psqyr+bFX8YdB7/n6gH6sq7jZVxab6qHPSp4tUh38SLIvK+9sW4tMqJYOta6ePkFR1wnl2N20wqQLB0SX5ueVcq/NsWfeL+A6bA739cqB3tHvEPe5gMYvP1WU2tGKCMs7ix5Qoh0PHJaG2coKWrZsUQhv3su4lLl4S+aSewfe69XujZ7jcbKxsg8Fm9aB298wK1Dj/h+f5VlAOLlrO6HugM/CZqhPfL7FyPhcTvBtlKBQhq3a/duPYueSvx8IG+H5kwBeYIkle3e8ATegbc/e8SGNb/IVd3y3+zip1vN6kGbV5b18x1GnvMKS9UDNUBON6j3vFJwtGdHDFpmyOf/YGf56GLwluuOf+vo2Edn0IeIePtr5ArE/qpi8PblhvSf2GENtasrf9Sske1euiqIEdQu/D7ADN8uOPBqv8ghZe/AU= \ No newline at end of file diff --git a/docs/UML/RecipeList/RecipeListClassDiagram.png b/docs/UML/RecipeList/RecipeListClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..f0dad56118111d0aec6ad70aad9d8a5b438b07a5 GIT binary patch literal 35447 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 \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp b/docs/UML/WeeklyPlan/.$AddWeeklyPlanUML.png.bkp deleted file mode 100644 index 88175f2772c0570e1cf33355edc8698c30bcbe52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29544 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 A)&Kwi diff --git a/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.drawio.bkp b/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.drawio.bkp new file mode 100644 index 0000000000..0648ff7f56 --- /dev/null +++ b/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.drawio.bkp @@ -0,0 +1 @@ +7Vnbbts4EP0aA+2DC4m6xH6M7aTZIsEGSRftPtISLRGhRC9F3/L1O5RI6+pba7dBEcOApeHMcDjnDDWie844WX8WeB4/8JCwHrLCdc+Z9BCyLceHHyXZFBLfdgtBJGhYiKxS8ExfibHU0gUNSaZlhUhyziSd14UBT1MSyJoMC8FXdbUZZ2FNMMcRaQmeA8za0m80lLGW2v6wHLgjNIr11AN0VQwk2CjrlWQxDvmqInJues5YcC6Lq2Q9Jkwlr56X2x2j28AESeUxBkmKvvCZJe5Hkzv6tLamkn7v62CXmC30gnWwcmMyIPgiDYlyYvWc0SqmkjzPcaBGV4A5yGKZMLiz4ZLhKWEjHLxEudmYMy5yN85t/gGVGU/lLU4oU4y4I2xJJA2wHtAEsJG+rziw8g/IMyn4CzEjKU/BYtTOhk7QkghJ1hWRzs5nwhMixQZUzOhAI6WpipBT3K9K4H1P68QVzNGVJjnWZIu2vks84EJD0g3PYEYfNn9v/NeHSRLjxZ377/ekb7fgmWCJpzgjLZiyFU0YznORJ1KPKFAwo1EK1wHkhkDORionkHN2rQckVzAGMWXhPd7whVpXJgFFczeKuaCv4BYboGFYGLSQX9N4VpaaLoJkoPNoYLEboge8rine40xqQcAZw/OMTrfLSLCIaDriUvJEK50BdWQN66i7Vy3U0cDtQN0U9tlRRy3U+3ArSEDnJDMEuKWMzPM95hoGn6WgadQDJJBjq8woixUhL2zzCKw4wWiREfFXGgkSUkjqgekaHISUy10FOqOMNUSGl4zM5E5WZrDXwFz3uc7ELSVPGgol4mA7Y/nuGtMwJKliFJcq9jw2tbg5p7AeFag3gi+AN7Y+eT0PAh/DvV3ew1epC9h9UlgLpjm5CHBzRRQ/O2i3t3oPc9Fwzz+Oer59IeY5hx8HjObYFRibR6L9QwAnABUjJaJfFeCTvt1C3Wmj7nQgnD98HnlGJeXKvyh0G8gfArfOXprGRNBLgj44cr8ZXAhztwNzWKzFOA6f6nvOh49F+Rfiewr5KjePwirDS7LDaskhjqa+muVba58yJuVI50S7DXfO9U/39mbsyqGdq9tj3TlrSGZ4wWSZs64svm+kZ62poXdcTdnI+/mq6mys250bEIOpNU8ZD17+W3BJapj7SpSnpHIV6d/cEOBKO02m2367HxTEUPQS0fQD8jwFCrKqFx/3zqKax85Z1EA/yzs+5d5G83XDkTUrXgtKWdnet+b7kvFt1YLaHBpT5ONEMTWPo7bHFPJanIBKEarfFBd5aomreTeDjbKrvMicobP0BqjeWQ7sNivtDla6lyJlu7F8J+VJpKw9j/4IUjrO8DeTsqvnfCflCaRs9Sx/BjGHHX3xLyVmuzG2WzkgaXitThnLXqySFRisnmflRyZGO6Q44Wn4NaZpr36aYrtGAO/cW1dhRMyRDvRTMY94itlNKT3UA071scmofpz304dxsEYd5t7zmIwvhGb83jMPWHZE5OG+SuXjGFZBI+qat2VBGJZ0WceyizXa26Pqc0tX7tBpPM4Hn+zGwV+xTG1YPYtt+PK9w76KVLR8AYHwpqKmu/GdYfuW25hquD+0/fpwUUTQsDbh8NksI7LXrL0tMj9ejt57Of66cnSPLEf0ZsrR8W0oIWv7aTg8ujId9xS3ZypSD7UWszfKA/q/r0j99yJ9e0XqvJkidR10iSI94PZcRerW/x90m3+4nqZ/iSKF2/IP5UK9/Fveufkf \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.png.bkp b/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.png.bkp new file mode 100644 index 0000000000000000000000000000000000000000..3fa6a0c6cb6fbc310c8b343fc763ba0e1dcd1551 GIT binary patch literal 9238 zcmc(Fc{r3`__t7$iZ)Bugt9gZ#wcMhma)$;W-M7|hMB>P8N(P+l*krBA%tuV%9bTX zNMwqNq)1sRL!=Ug{2t%$@7?}*uj_r^>vvu6AM-r-bIyJ4bD#U1^Eu~y&Rll1x7@Sq z@Gb!Xfj!n%=FS2F+n|74Ai4v1dR2dY3%s^5oh=apHP7W{1q60Thg!IW2C+%xK%#&u z)a+kL6#@#NF+)|M=Bf~gMIg~HltBvyL?AtgMj(^OM8dy$5D)~a4bs&H8DPLrRj4T# z1Uw*M9f*N0{$G6`e`4@|8q(7N0S1m^$-x9#I1>=10+OK!Kms!Kb^jIF`nu{s ziYc8QNW>C-QRGln2vQFU(}C&($;VMv7&}{4h#4RUlBq=CWl8j-(zc2a7(U@TWE!9j z0qGd%01iPwW&sRZ5TJzwgYeDYzP72YOYN_qleeE#A=iL083jsVMGR#48-Z5sQvfaw{k)w=)`}M3B)k6 zAK(f^6>0&5n?UyQXZQpGD#1R0hyRpx1VW|_{?{b=KjTccrubt5tZ;rvgf)zWHYYin zIsIz{hQ||p;k0n1H4tzl#s|Zq1=^`X5N7t~wl=}&(9jSYSG;Qo6wUDiQrQSS2M&Ub zL0bXJa0)HZ9F4H|38jU=&`uOQLl;m1GN3FHj_K@Z0U_djsA#M&+Mi)&;0n?A!=Y>d z6(lPF=mi7{kSzS@C^Ji1fGeJj1<`fGbq(N7WLN!A28E0a4+?Rmqg-5qwqogvBinMU z5ViymEdcEo3UUYng(9#9C^X&P)EVzjb#^0R5iSN0roKNYEQp5l)in#^xNKDhcOhV% zs2Bzg7UJw5V8;Ll2RQpVxL7jj_Rg*-LYRfMH5=;dY5;g-g{2T|UDyc5R`=7LP{B|K zb~u|D0HKEI`9lGPum~guWy5hWpkXY~EEvu=6z4|3IiPHVQ7C)>!p)3m4W_XfL1thZ zTp+`Zj0gwQDGmsGAl3+5ppg-#z7{SnA(rR}HpkqW!n8t}LVW#o!=MB@-XBG?vU5T) z(Ob$i2PE)x2qA+&6vuEf1NdNsAS@UZb99hB%+Z$PWI#5BSP*Op5Nog-))oPQyE37{ zVfJ)D)7Qn%k!lcZiFRNF8CW@5frA_gP6noCU@M{--Uf;><6s>v90@FQOE(rChDQe3 z;Vm#6dnP`@ABi(#Is4&glz>28A7>WG-V7H^F%8v6gF^J|C`^XE1r(AFgK#qXr@U;cPfu-`1XlF%R)`Bw4xn116y1<_69L7#xPTv?a0J zoM0R)OJLq2Ld~3mtn32Zr~zOre=<&A*B2ck&6cu?cWtg+p+3qK`flOmlJuY6&(6Gf7M~!NSImXw3#Q^n)oJT_=W> zAJY#GveiYB@&2|U9E6^QoughL$uR;R#`J;vn(KniVg76fXYheXzA13+`iP#WXW>w06*=hGVd9_+Yjx+gEq1t!!UE zLYQwvu(cJLuIof(F$oAO08S9rzz--z#5x7hLY@6!c38YW%_$6r1qLaCWJ9FcLrH)X z08Ae$1(+%bGy!TF0=)H1L2M?;*~dJ<%E^vuO7o9!!V<%rDM)K%r~#W3L2;wwp|rpN zmIIv`24@7ptcZ4KE2N{d0mD&`N%wdGlMM>4;=Hgl6p1n$)!iu{uB<$jVGCC28 z?S-{uxt^Sw#sR~XA75#53G2^CBRzX=P^;jd@zfd%CX+efI$qea`Pbv%Lx+t%|0VZ3 zpP&5J;v;{n1|5&e-q2Quop%4ew-6^fko~jPWPCkgU+>YoUyLDmORUBzj3f3cSalpytcf!E+JVOvtQM9E1X;pFpuJVS5c zWD`vZP);KvdEw$dkf0iL?mY0SHt8U|-UV(w09XNx3H@U%=5O!(r#xEC!#{kk>(8-# zkRa0gmqhbyS>Ejv?dy!ROUss|BuVYtpFaI;TUBEHkq3N9HaQ$~#Gr>jDun>rVL(mK zQnkkR138y~D)fcf(ZizBF{7q{e6o&?N*>p1h6MN@iV)GypdGTzAl zjU!%MuZWqfT&)TAR0_W+Ug5SjEbYK)8^^-vKjdrMWzJ1BQnAHM7U)*llife=#6ta_WAb3M8ri=?Xa|>-_mQ+GhlKmuHh#Suz8Cb4 zKhZ>+@G@HJKCs+wYA&)@?u*3kheFnm4m|)AP7)_uj#{P;1%G;UL4>=pwt{V6|BiZT zgh42iGscQfj+v95Tv5F9Ykm~nwA3^a&3$*M@36|*nJnzT6Tt@l&xoE;lhaBE*A=G)AzjDt2ujov zTw>4Z!~Xq`f8~zZHa;JEDqK{YFXb8PBsE*Wd=59N{Vr4=bG|Q7e;UNBR&uKHdeC~W z05nJ@FP)T-+^H5OP}^8|?r+P~>!tAhBY-q|1iFs&z5M!6b?yDdhxc_Hq;@!q3CO~N ztEx|=Ifh!-x}E1Jus_7;%%KY1+t{^zfu9;`t4!7EAvYw)&<%G}6^!udO7?}P$1kU( zXAWg0b92>UX(kX7@?{C};_xf!<|h-z>)*^a_%2w_;md`3S$A%&K0moQM4S{V_A~xs zlgoQs^j@t#tT$x(fkDJ~LVR=a@I@sTQuydOsdfUiJ{BBG7fpTbURIC53d4KyWMn(=+S}M6$ zgkRAYsPtz2R1{E`K+Jj{5FfAkS=NZy(63@R|IdX)f>p#0x}gtspttWWhC1{lgz zO%vuZVESG+64rURI%z1=DWG^p@RUG6^kZOxgO7l~{ecOIJwq%hDgX+364J4LfjN!V z`^Kb>f+qF>un@kpbpwEzp)I@-{jUeF|57CUe>dh`4B%?_*v>6*lZ9a*3?jQwWHA>E&-rT9#7L=YK@}>(A47{p+c#o)-2Y`5D*k21R`vMLLs@1z*ew7av z6q5oFsx#|BWUw$k?tEXB%Vem3a!02{2jL!_xL6yHOpXJ=IC8I5M*tS(fgnO z_hzeA>S+&um%VLeQJ3FGF1i57_;tVZ!?iziceo>7k<}bv&fhLCjBcG<(WAZ|TGaMx zYku1n!DOwBhht%5^se5x=jzu`)1OR;A2$GO z#*Umh7nRZv|9k@t`^d|I>g||_UJF|O7_aDx^$4+Ox1*j_fV9rn_21qjt3NbQD}Tl4 zm)l6VxbZrD8E{4%bFS*bo~KcF_VhrfUW$9K@t^~kl`-ak$p&9F!DI7gct>P^wzl7k zIj^sWKQD?E@C0;(`^6LHKNp^>QHc8aqBcV&^J}(yaL&#+!OQ1Ce^=T!T?UL+JpAb& zBX>7%jb?8M+1bn2ZXLYSXmkC?aN;3Ne%N`;(s+SUWUJM^!fjx!oD{V2`NflqZLemj z#v6x!;;!QMx4a-dJ6?-9o-lBFttxom!9t;!`ads9Eaw)%q5(M{C%CTFw?+E+!(1-9 z+@7UXUr{A@>Rl7m_HMbx7kL{o;u$_Xz^!uH z1Qt8A{3-U`*kH=LZ&mh`(rzyMc4}o+qt@d+%bVZ(Pu%0R!h`Av$e1x;smtGHwc!Css@PJBjXcMPt%m&D3UJ0PH5-Y&{q5g6 z#Rlr;2NiZJrQO-q@)r#)!oe0wBvb-Hr7R$P7K=5BZdKN9Xq_<~qg zj=zd8XJ7hwMe|PEcdZBI3NZ<@oh5tLy_Q*WAFp~Ssx55{jq?m%)xVNE2$%3Ka@@I; z+>;#IQ(oHXmZpK!Aob*+v($EZ_Mc}2oUQ4$OVKIQI2S5pH7Px)k}oZrv@!ha8|>$y z2`1!&z{O7H&8|kFqO@jjqu4fyuHw>L-vc^}bW_U-X4FI1V^GUmwg)MmK7|0Aa+ z+?(xs`q)K`teUCr)e1j8p~pVEIVXKJ;JH~v<+fzg&DruoeGN_n?@ht+pA~N~l-;LN zW-FA-JvxUvV_St^WVtfpQMWdxX?D}{eaSk9C*n{w+2b{y_bFUa;g~l^L@l(hIm_Af zC1>xPyY)`Y_x_LPC%G#V=h{=%^G`>$-a|bfo@VF#OikI+zH5Cm>h6 zcBWXdLFthDB@^d`0v(O4G@MFs@Ag{?Qmvt}$8sKhA3EROr)AB(%7T_WhG_Ixnd3@i z_i1Oy<;+w`yNMlMzd|URE+S5g7WY9)I{ng$3x@cCXE#f(oW4Dk$d;_x{qDfA6t(^; zvITBU7#>TPz{aA)lC}%&l|B;v3m9>)FF4J}V_leFcwZ50E>io zUENzleGW;Iw7YXXC)mkx#QehROoxO-iCipQ zQt6RC(flFSKJbJENnMVytlyU%0!=FqMsK^P1aU*D+>z4(msNt5Q{-o?E`1+wKX-0K zG84noDpj;0bsu^|<=IOCj0E69kv)Igj9^oSAHwf(<#n7+&)jvKCG;4IbR++Zea9`4 zbVqQg%jaS2nd-QKM@0+j@7I8Sr;MmJ;CL1Bc z_EYhd!`$ZFN-no@7`l*Ota%H1$~tjdXk&u3hsdRW9LCvaa(mjoc|NV9cB;m+oSdM_ks+m&3MIp|5r= z5Y2hz6aH!>{X!F23->AIj^j^NcJ8h}K^+Xc)$2W2SGMGJAU&CDq`FiWGCbbHup^-} zD1EU{lwR$+37pgFLZ3dAkw z$j0a^1B+=1X8hREy8`>JHxXPp-uG0pUp2&Avy_{P^cpp!>siT&rb%#x&r_{OrIlxE z6!^d0PB|ohTg1H1@OgU!zlU)0=Q?Fpp$X&8$g@G|=kaaov!4xr@c}D-jx|MZUV6lo zj#yc%>6>rgcKuyNt}@iF(3vq-ai-{2fnvF`_{-DB4HD+temtMEG0I$vPBU~~>~^t~ z`1C~aoQG%B@^Jnwp$GS3bsLFpkfhnf(Bf{%Tpw(%CA=u>X*WSKjsG}Tl^bbSzR4UF z3e`8i>Z_mF9B&Kz*fYNyPIVlR;>)}+g{XfCInu}p)f5Tmlo)p$TBg@i$7mP*59SSl zwF=I3pH^SL){iV+yPiNDtG^hgbLL^&pUI>XhAJZ$g`V5>aPqWfjyv2a?f&Gjuy(X_!6N#JA-k&^EDGqidv|=r;H_x427wmRaIv;qBtiCu-^HVRTk!Ka^CBxAWsz}$kdAg^+uhx|W;JDG&^yxMlv zkiF;eg}U-OoiD$;tlaQd7Jk|{HqO#n)@s}3Pqj{{w_Z0ix$akm-PF6F#di`rR&deV z9qi4?ikygAaXIner*nMs-Fh$ansUg-_nV<(K4&HskS$LdYz%TAcTGw+R|X#DxmUpmjUsCRx&J2k%ssg>IO)SlB&JFoK6lzjg!UWH_=!m8C%^QbT z%t{2D=&w@O+q>h~^X+^~D8(ekid0!8#u3dSWJlJh&(Qg9j_o-IhgAEwryeDjsR{qu z{PwZSQz%#30)pO-h0MiiYVA*xQQJkL4AvK%QWzE!Y2aSut;(&%*ecs*?DQ4drunF} zj{I#fO5=j4h~87Il;M7R-h)f}-PUS&xkPxi>Ba4S^8g`?zNAD7l`N&SY>X@hCnPDpk)A&&k;FS|mgf+TUd zZ#R5(YGo*?kvbAq8cb_F8+U-J0v-3-Uq4r-RsWLtVE0dIv0!gAmZ#O)dU&dl=<1!5 zCE@Gw3u%#9tG;L1^v86!3GK^h1n{#DoeovPRm%yz_ zEyK3Y(1rak)4N>yOcoD%OQxvFIWK3=uO%(%w-#2;%g#r>iW2pBl;SG;?)&Q0l@V@^ zos2t58(Nm?d*2aux{`NyUsAKc%Z5@bsTN%kk9KYjSj?`^Ex!k9CT&~d`RoSr^JjGa z)R@1d=N0RZkZO+Qi}td|1x}fTnk6c$#?Sxww*+1t)j}O>2=YigrR|*K`k*WE6pQcu z27-F8`1zu%^JbN?A0&^pvn2{RO&$aeLYlFC;s9L+ngdQ%Bu_+eAwYCli1H#Kntde4 zix*Gb;u@{zYWh@iC;w!8i&iN}%mR|Zk^N>k5G*ZF_g!2H^=puV=Y z*gi+?aa2p~`fwqoWW9UOl`-1EEBj~Rryf)vUwAQ@F8ftVT>P`^@5z1KrCRl4wc_JT z`6r7yp53iF+IT_s)`6Wmy9_OCTeL*ljGY#jgU^w{34oG-IePur2Qkz%vcGj*TzcEKN)cs4I(gwi~+MOfRiJT4u9 z4wctX8+gvJ{E~;j?y6_wu0)KuU*J-JoyL)y+VxJmrLKYdMR~h(vd-U&|t9TA+NxtwcYK+^QqmZ6HOI{IClHbF8 zLFFH56wXPEOdGash>`vh8<*kHCUg^+NuL%ASwz-avdIC#ABnuT%1?1`{9j9Ijf)>O z0S@!%mvPql0@s~aJgWCyHvo?Gm(3P-0W6HP2q1^t-aI zulkj$(KNgFd`4C4AKTed)snPpzsN%~dz9l%C%`$|ry0BC!$+qYGk6D7ZRB7->#S85 zGeCL4%?cR!j;K3Qk5-f`ogpYsuj0JxB0-xs7nfTHZ(&ne78W zC+s?LO;0HDVc6HVEgqx9ht~x*z;o_hA-|k!J4aCu&~Pli=J7eL4zgg(Ax z-aF+MGNBOt5=QEYETCPlmgWvHO3OkMY?4C8ReA*KT}SI2ZhS z=H_SZw-qq2jQ*oexpBflf-T3@>ozHNJ&eefoRAX6{6K{kG$`KdzT^pxEBt$dF#Qd% zuXnwYa3MQsk+DLmOWiu1q82gHFZM5fZqs?rFV?aR4itKOU^zLj8nrNxe2ju=`neas z>{xty>ekLDC2FqHB9(UeJY<&M1>A|rBUDuxqb}+2F9$sE;&+kW;Euyd?J>GXWp2}* zo33ddc`^A>dx}y!?Mrf+)mzB{_95rtkv+*um1{Die>1dHRN62tr|gFbIi>cVcmLkl zzCX+O5EPZa`oUasEz7V=cIIZ(p!qgR(G%IhHC5xv z8Wk3&R=%99ukBvL4?D-{Nu7|;X%S*!y7gHQKTFQe8Wrk}suU|yi`Lm5McQ z2BBJ>If0MPBIoSZlKdM7>g)5;hRV;U^FDBT z7+WmBE69{;-`(pH`<+H;(vVk~7_DQ!pido+9kp}X?um?8o$e8j_EStS= z_qM7~k%<5#>gEb=z~e}=ptX*(Wr8yh#`GA^YQHL>=cwbgGtm*O$?nVcr!;CfrM+5N zk=4Qj22dz6L0X<~oyDy`i{>SV$l5D$q@yKZP=$N6!{()RScDqxle59c(U;eAG{T=I zmcs_Au_Jx)-M6ye9@nZLTD|=GCV#&+l;0BzL>i6upTN9MwjzN^l2gL`{dWVK0}m?s zn!czii!6CWSA{<7O+N}vvB>P^Rg6`+H!0roCA}!Vd8qRqIc(3~HwO!DbQzPrmN-M1fcJH9(D{d5c)MAT zCgYx`YLa@Ey84oZZD>8&xSdHGE4J3JlMN1hp(OWU0`?6iFJxiTU3c`m-wz9VV)&Fe zJviKlktk$wQCu)ILrUlym?l#l0~{&|NR)bG-H@0=8+S!oxBAj-VpdIobK9!tv0Y_K zor{KGy7!0Q0AcQjOn+nS8Ddxc{qeymfFyHZef#jJ-nExGbGxQ?VyFdRdRV@g!;5I! zk~R^~XG49#ncSQu1u@SE#5=Vhq92m2ya|`BVXt2|F-b@fMuI@Li|83_2bH zJ~m#4yF(*M3XtS0$W7uGl7b!D2E08IX^{I>RK3UyLr~35N=DT6P*1gb>!S;Qwr;n? z0CcbI;3KxsT^Er5|D+!{TAxRI*aBSS-BBAi9`P3j4!Wiv%JPD5KV1LbZ^~I4D+ah} zf9`D#DXnQE71$^ty^&j&cL_>kySFay%zz6!x#;M30Jkr*b$NF*mJZ!&-d=!^rmy}E z+Tyo`0XbQ;^VwEm17OAL`uMqNtJ(Vi8LBJ_>jDaY1dQ&9FPzZ-KdvBVZ_XZU@>YQk fQCpdqO`-m0Y2RoG5=+1zeFUs6?9FQs-m(7yzhZz5 literal 0 HcmV?d00001 diff --git a/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.png.dtmp b/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.png.dtmp new file mode 100644 index 0000000000..e646ffd72d --- /dev/null +++ b/docs/UML/WeeklyPlan/.$WeeklyPlanClassDiagram.png.dtmp @@ -0,0 +1 @@ +7ZZdb9owFIZ/TaTuolM+CNDLJnSttqJVZVq3Szc+xB5OzBxTSH/9jolDSBNatoq7SQjZr4+/3ufYsRPE2eZakSWbSgrC8V26cYKJ4/uh6+K/EcpKCGohVZxW0p4w489QiV6trjiFwmqVpKUUmi/bYiLzHBLd0ohSct0Om0tBW8KSpNARZgkRXfWBU82s6g0vmoYb4CmzU4/9UdWQkTrY7qRghMr1nhRcOUGspNRVKdvEIIx3bV8+HWjdLUxBro/pQKn3Oxwxeh2kv5g3+vyFTKJzO8oTESu7YbtYXdYOKLnKKZhBXCeI1oxrmC1JYlrXiBw1pjOBNQ+LhVZyAbEUUqGSyxzDIjsHKA2bg4v3dpZgKoHMQKsSQ+oOF+Oqi00jPwir+rqBErjDSmN7PLzQ8iA2EdLd2I1XWLB29Vs3nvNp+bUcPk8nGSOrm8HPH1mPdQ8AC1HeCZJ3TCzWPEPduDGXuZ7ZFmMZETzNsZygFYCuRcYojhl4aRu0NCYnjAt6S0q5MjsrNEkWdS1iUvFnHJY0GIjS9jD5w1bEzPS0MBUUGHNXU/BeSFOyaQXekkJbIZFCkGXBH3fbyIhKeR5JrWVmgw5A7kmFg9x996LNfTDqcPfHXg/3wD8Rd797ZGLfuXQ7zHGL+tCRmHMhXkh1HgiY64NZUODJ43l6u42ZDBrl3m7dSBL7zsX2rmGcUsgNQamJJhUuw2Ypea631oQR/nD1sfsxdEJceIx1r6njz4QrHcsc90L4FiZgLqzB5EMP5lfPy9vsa9bD41D7gxORDt6+HAXfsqsY1x8I758AZ4hKQEP0mwE+Ofc61IMu9aCHsCCPIO5kwTWXZnxVxb4g/xbcdvbynIHip4QeusdBH5+I+aCHeWQmotRc7MWZgoQvYWo+fJeoN3f+h0p4kji+Sd3Aq+5A0xsfRaDhHQMkAogyQWevRjFIFt8xzyjXpZ3olhuOpsv9rm7HeMSHFPR8rP5fXO/M4fFxOTz6+4sLq82Lcdu29+wOrv4A \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio b/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio new file mode 100644 index 0000000000..028e675920 --- /dev/null +++ b/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio @@ -0,0 +1 @@ +7ZZdb9owFIZ/TaTuolM+CNDLJnSttqJVZVq3Szc+xB5OzBxTSH/9jolDSBNatoq7SQjZr4+/3ufYsRPE2eZakSWbSgrC8V26cYKJ4/uh6+K/EcpKCGohVZxW0p4w489QiV6trjiFwmqVpKUUmi/bYiLzHBLd0ohSct0Om0tBW8KSpNARZgkRXfWBU82s6g0vmoYb4CmzU4/9UdWQkTrY7qRghMr1nhRcOUGspNRVKdvEIIx3bV8+HWjdLUxBro/pQKn3Oxwxeh2kv5g3+vyFTKJzO8oTESu7YbtYXdYOKLnKKZhBXCeI1oxrmC1JYlrXiBw1pjOBNQ+LhVZyAbEUUqGSyxzDIjsHKA2bg4v3dpZgKoHMQKsSQ+oOF+Oqi00jPwir+rqBErjDSmN7PLzQ8iA2EdLd2I1XWLB29Vs3nvNp+bUcPk8nGSOrm8HPH1mPdQ8AC1HeCZJ3TCzWPEPduDGXuZ7ZFmMZETzNsZygFYCuRcYojhl4aRu0NCYnjAt6S0q5MjsrNEkWdS1iUvFnHJY0GIjS9jD5w1bEzPS0MBUUGHNXU/BeSFOyaQXekkJbIZFCkGXBH3fbyIhKeR5JrWVmgw5A7kmFg9x996LNfTDqcPfHXg/3wD8Rd797ZGLfuXQ7zHGL+tCRmHMhXkh1HgiY64NZUODJ43l6u42ZDBrl3m7dSBL7zsX2rmGcUsgNQamJJhUuw2Ypea631oQR/nD1sfsxdEJceIx1r6njz4QrHcsc90L4FiZgLqzB5EMP5lfPy9vsa9bD41D7gxORDt6+HAXfsqsY1x8I758AZ4hKQEP0mwE+Ofc61IMu9aCHsCCPIO5kwTWXZnxVxb4g/xbcdvbynIHip4QeusdBH5+I+aCHeWQmotRc7MWZgoQvYWo+fJeoN3f+h0p4kji+Sd3Aq+5A0xsfRaDhHQMkAogyQWevRjFIFt8xzyjXpZ3olhuOpsv9rm7HeMSHFPR8rP5fXO/M4fFxOTz6+4sLq82Lcdu29+wOrv4A \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.png b/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e3cd2e5b9af1603370f9b5433c479089adbde2 GIT binary patch literal 9238 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 eRw{N&VBlH$H)^8TGVn(qK5Gkm^IEuf+ Date: Sat, 8 Apr 2023 21:44:44 +0800 Subject: [PATCH 203/252] Fix filepath for DG images --- docs/DeveloperGuide.md | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 6aff44f725..8e1c3c83ce 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -71,7 +71,7 @@ if the user inputs `view 1`, the `Parser` component will call the `RecipeList` c the recipe at index 0, following which the `Ui` component will then display it to the user. The sequence diagram below shows how the interaction described above: -![](../docs/UML/Architecture/ArchitectureExampleUML.png) +![](./UML/Architecture/ArchitectureExampleUML.png) Depending on whether the user input is to make changes to the recipes, ingredients, or weekly plan, the `Parser` component will call the `RecipeList`, `Ingredient`, and/or `WeeklyPlan` component @@ -81,22 +81,22 @@ Additionally, methods irrelevant to the subsystem shown are also omitted for sim 1. Recipe related -![](../docs/UML/Architecture/RecipeRelated.png) +![](./UML/Architecture/RecipeRelated.png) 2. Ingredient related -![](../docs/UML/Architecture/IngredientRelated.png) +![](./UML/Architecture/IngredientRelated.png) 3. WeeklyPlan related -![](../docs/UML/Architecture/WeeklyPlanRelated.png) +![](./UML/Architecture/WeeklyPlanRelated.png) ### Meal360 Component API: `Meal360.java` The (partial) class diagram below shows the structure of the `Meal360` component: -![](../docs/UML/Meal360/Meal360ClassDiagram.png) +![](./UML/Meal360/Meal360ClassDiagram.png) The `Meal360` component: @@ -116,7 +116,7 @@ API: `Ui.java` The `Ui` component: -![](../docs/UML/Ui/UiClassDiagram.drawio.png) +![](./UML/Ui/UiClassDiagram.drawio.png) - displays the welcome message upon startup of the program. - formats all the output to be displayed to the user. @@ -127,7 +127,7 @@ The `Ui` component: The sequence diagram below shows how the `Ui` component works together with `Parser` when the user inputs `list`. -![](../docs/UML/Ui/commandList.drawio.png) +![](./UML/Ui/commandList.drawio.png) ### Parser Component @@ -146,13 +146,13 @@ The `Parser` component: The sequence diagram below shows how `Parser` filters user input dates and parses them as valid `LocalDate` objects. -![](../docs/UML/Parser/parseDate.drawio.png) +![](./UML/Parser/parseDate.drawio.png) ### RecipeList Component API: `RecipeList.java` and `Recipe.java` -![](../docs/UML/RecipeList/RecipeListClassDiagram.png) +![](./UML/RecipeList/RecipeListClassDiagram.png) `Recipe` is a class with the following characteristics: @@ -175,7 +175,7 @@ The `RecipeList` component: API: `WeeklyPlan.java` -![](../docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.png) +![](./UML/WeeklyPlan/WeeklyPlanClassDiagram.png) The `WeeklyPlan` component: @@ -198,13 +198,13 @@ How the `WeeklyPlan` component works: The sequence diagram below shows how the `WeeklyPlan` component works when the user inputs `weekly /add burger 1`: -![](../docs/UML/WeeklyPlan/AddWeeklyPlanUML.png) +![](./UML/WeeklyPlan/AddWeeklyPlanUML.png) ### Database Component API: `Database.java` -![](../docs/UML/Database/DatabaseClassDiagram.png) +![](./UML/Database/DatabaseClassDiagram.png) The `Database` component: @@ -229,13 +229,13 @@ How the `Database` component works at start up for the recipes: ingredient list and weekly plan are empty. The activity diagram below shows how the `Database` component works at start up: -![](../docs/UML/Database/DatabaseStartupUML.png) +![](./UML/Database/DatabaseStartupUML.png) ### IngredientList Component API: `IngredientList.java` and `Ingredient.java` -![](../docs/UML/IngredientList/IngredientListClassDiagram.png) +![](./UML/IngredientList/IngredientListClassDiagram.png) `Ingredient` is a class with the following characteristics: @@ -296,7 +296,7 @@ It is implemented through the following step: The sequence diagram below shows how this feature works: -![](../docs/UML/Implementation/TagFunction/TagFunction.png) +![](./UML/Implementation/TagFunction/TagFunction.png) ### List Recipes Feature @@ -328,7 +328,7 @@ It is implemented through the following step: The sequence diagram below shows how this feature works: -![](../docs/UML/Implementation/ListFunction/ListFunction.png) +![](./UML/Implementation/ListFunction/ListFunction.png) ### Delete Recipes Feature @@ -349,7 +349,7 @@ It is implemented through the following step: a parameter, and return the `Recipe` object at that index/the one just deleted. -![](../docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg) +![](./UML/Implementation/DeleteFunction/DeleteFunction.jpg) ### Add Recipes Feature @@ -408,7 +408,7 @@ It is implemented through the following step: The sequence diagram below shows how this feature works: -![](../docs/UML/Implementation/RandomFunction/RandomFunction.png) +![](./UML/Implementation/RandomFunction/RandomFunction.png) ### Add Ingredients Feature @@ -433,7 +433,7 @@ It is implemented through the following steps: The simplified sequence diagram below shows how this feature works assuming all inputs are correct: -![](../docs/UML/Implementation/AddIngredientFunction/AddIngredientFunction.png) +![](./UML/Implementation/AddIngredientFunction/AddIngredientFunction.png) ### Delete Ingredients Feature @@ -476,7 +476,7 @@ It is implemented through the following steps: The sequence diagram below shows how this feature works: -![](../docs/UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.png) +![](./UML/Implementation/ViewIngredientFunction/ViewIngredientFunction.png) ### Edit Weekly Meal Plan Feature @@ -508,7 +508,7 @@ It is implemented through the following steps: The sequence diagram below shows how this feature works: -![](../docs/UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png) +![](./UML/Implementation/EditWeeklyPlan/EditWeeklyPlan.png) ### List Weekly Plan Feature @@ -527,7 +527,7 @@ It is implemented through the following steps: The sequence diagram below shows how this feature works: -![](../docs/UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.png) +![](./UML/Implementation/ViewWeeklyPlan/ViewWeeklyPlan.png) ### Mark Recipe as Done Feature @@ -555,7 +555,7 @@ It is implemented through the following steps: The simplified sequence diagram below shows how this feature works assuming no counts of the recipe is left after the deletion: -![](../docs/UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png) +![](./UML/Implementation/MarkDoneWeeklyPlan/MarkDoneWeeklyPlan.png) --- From 73bfe5338654ea0ac16fd3fd3aaa5dbdc09ec239 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sat, 8 Apr 2023 23:47:55 +0800 Subject: [PATCH 204/252] Refactor adding,deleting of ingredients, and marking recipe as done --- .../java/seedu/meal360/IngredientList.java | 31 ++- src/main/java/seedu/meal360/Meal360.java | 10 +- src/main/java/seedu/meal360/Parser.java | 180 +++++++++++++----- src/main/java/seedu/meal360/WeeklyPlan.java | 52 ++++- src/test/java/seedu/meal360/Meal360Test.java | 104 ++++++---- 5 files changed, 283 insertions(+), 94 deletions(-) diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index d09fb32b73..14c50efebf 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -24,6 +24,13 @@ public LocalDate findExpiryDate(String ingredientName) throws IngredientNotFound throw new IngredientNotFoundException("Ingredient not found"); } + /** + * Adds an ingredient to the ingredient list. If the ingredient already exists, the count of the + * ingredient is updated, and the expiry date is also updated. + * + * @author jaredoong + * @param ingredient Ingredient to be added. + */ public void addIngredient(Ingredient ingredient) { if (this.containsKey(ingredient.ingredientName)) { int currentCount = this.get(ingredient.ingredientName).ingredientCount; @@ -46,15 +53,27 @@ public void editIngredient(Ingredient ingredient, Integer ingredientCount, Strin throw new IngredientNotFoundException("Ingredient not found"); } - public void deleteIngredient(String ingredient, Integer ingredientCount) - throws IngredientNotFoundException { - if (this.containsKey(ingredient)) { - int currentCount = this.get(ingredient).ingredientCount; + /** + * Deletes an ingredient from the ingredient list. If the ingredient count is greater than the count to be + * deleted, the count of the ingredient is updated. If the ingredient count is equal or less than to the + * count to be deleted, the ingredient is removed from the list. + * + * @author jaredoong + * @param ingredient Ingredient to be deleted. + * @throws IngredientNotFoundException If the ingredient is not found in the list. + */ + public void deleteIngredient(Ingredient ingredient) throws IngredientNotFoundException { + String ingredientName = ingredient.ingredientName; + int ingredientCount = ingredient.ingredientCount; + + if (this.containsKey(ingredientName)) { + int currentCount = this.get(ingredientName).ingredientCount; int newCount = currentCount - ingredientCount; if (newCount > 0) { - this.put(ingredient, new Ingredient(ingredient, newCount, this.get(ingredient).expiryDate)); + this.put(ingredientName, + new Ingredient(ingredientName, newCount, this.get(ingredientName).expiryDate)); } else { - this.remove(ingredient); + this.remove(ingredientName); } } else { throw new IngredientNotFoundException("Ingredient not found"); diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 24b6df7588..9aa04b491a 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -188,7 +188,9 @@ public static void receiveInput(String input) { ui.printMessage("I've cleared your entire weekly plan!"); break; case "/done": - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipeList); + String recipeName = parser.parseMarkDone(command, userIngredients, weeklyPlan, + recipeList); + weeklyPlan.markDone(recipeName, recipeList, userIngredients); ui.printMessage("I've recorded that you've done this recipe!"); ui.printMessage("Ingredients list has been updated accordingly!"); break; @@ -218,7 +220,8 @@ public static void receiveInput(String input) { } else if (command[0].equals("add_i")) { ui.printSeparator(); try { - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); ui.printMessage("Ingredient successfully added!"); } catch (IllegalArgumentException | IndexOutOfBoundsException | InvalidValueException e) { ui.printMessage(e.getMessage()); @@ -227,7 +230,8 @@ public static void receiveInput(String input) { } else if (command[0].equals("del_i")) { ui.printSeparator(); try { - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); ui.printMessage("Ingredients successfully deleted!"); } catch (IllegalArgumentException | IndexOutOfBoundsException | IngredientNotFoundException | InvalidValueException e) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index d9656f8517..75cd820bd7 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -20,8 +20,8 @@ public class Parser { Ui ui = new Ui(); - String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly!" + - "[eg:chicken=100]"; + String recipeErrorMessage = + "Wrong Format or Invalid Quantity. Please enter ingredients properly!" + "[eg:chicken=100]"; public String combineWords(String[] input, int startIndex, int length) { StringBuilder word = new StringBuilder(input[startIndex].trim()); @@ -32,22 +32,26 @@ public String combineWords(String[] input, int startIndex, int length) { return word.toString(); } - // @@author jaredoong + /** + * Parses the user input into an array of strings. Trims away leading and trailing whitespaces, and + * converts all words to lowercase. + * + * @author jaredoong + * @param input the user input + * @return an array of strings representing the user input + */ public String[] cleanUserInput(String input) { input = input.replaceAll("\\s+", " "); input = input.toLowerCase(); return input.trim().split(" "); } - // @@author - /** * Parses an array of strings representing ingredients and their quantities. * * @param commands an array of strings in the format "name=quantity" * @return a map of ingredient names to their quantities - * @throws IllegalArgumentException if an ingredient quantity is negative or an - * ingredient name is empty + * @throws IllegalArgumentException if an ingredient quantity is negative or an ingredient name is empty */ public HashMap parseIngredientName(String[] commands) { HashMap ingredients = new HashMap<>(); @@ -107,7 +111,8 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { - ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printMessage( + "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { break; @@ -171,7 +176,8 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { - ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printMessage( + "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { break; @@ -274,7 +280,8 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { - ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printMessage( + "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { break; @@ -380,8 +387,8 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { * @throws RecipeNotFoundInTagException If users try to remove a recipe that is not in the tag. * @throws TagNotFoundException If users try to remove recipes from a tag that has not been created. */ - public String parseTagRecipe(String[] inputs, RecipeList recipeList) throws RecipeNotFoundInTagException, - TagNotFoundException, NoRecipeException { + public String parseTagRecipe(String[] inputs, RecipeList recipeList) + throws RecipeNotFoundInTagException, TagNotFoundException, NoRecipeException { String returnMessage; String tag; boolean isOnlyTagWordInCommand = inputs.length == 1; @@ -464,8 +471,8 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) throws No * @throws RecipeNotFoundInTagException If users try to remove a recipe that is not in the tag. * @throws TagNotFoundException If users try to remove recipes from a tag that has not been created. */ - public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws RecipeNotFoundInTagException, - TagNotFoundException, NoRecipeException { + public String parseRemoveRecipeTag(String command, RecipeList recipeList) + throws RecipeNotFoundInTagException, TagNotFoundException, NoRecipeException { String tag; Recipe recipe; String[] recipesToRemove; @@ -482,7 +489,7 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws isUnableToFindTag = !recipeList.tags.containsKey(tag); if (isUnableToFindTag) { throw new TagNotFoundException("There is no \"" + tag + "\" tag found. Please make sure you have " - + "entered the correct tag."); + + "entered the correct tag."); } recipesToRemove = args[1].split("&&"); @@ -503,7 +510,8 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws String errorMessage1 = "Unable to find the recipe: \"" + recipeName + "\" in the" + " tag."; String errorMessage2 = "All the recipe before \"" + recipeName + "\" (if any) are " + "successfully removed from the tag."; - throw new RecipeNotFoundInTagException(String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); + throw new RecipeNotFoundInTagException( + String.format("%-97s|\n| %-97s", errorMessage1, errorMessage2)); } } return tag; @@ -519,8 +527,8 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) throws * @throws NoRecipeException If users entered invalid recipe. * @throws TagNotFoundException If users try to remove recipes from a tag that has not been created. */ - public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) throws TagNotFoundException, - NoRecipeException { + public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) + throws TagNotFoundException, NoRecipeException { String[] filters; RecipeList recipeListToPrint; boolean hasTagArgs = inputs.length > 2; @@ -549,7 +557,18 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) throws return recipeListToPrint; } - // @@author jaredoong + /** + * Extract the recipe index that the users wishes to view. Then, proceed to extract the recipe and returns + * the recipe. + * + * @author jaredoong + * @param command string contain `view` and recipe index + * @param recipes list containing all recipes data + * @return recipe that user wishes to view + * @throws NumberFormatException If users entered invalid recipe index. + * @throws ArrayIndexOutOfBoundsException If users did not enter a recipe index. + * @throws IndexOutOfBoundsException If users entered a recipe index that is out of bounds. + */ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { assert command[0].equals("view"); Recipe requestedRecipe; @@ -574,7 +593,6 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { return requestedRecipe; } - // @@author public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { int recipeIndex = 1; for (Recipe recipe : recipes) { @@ -601,9 +619,21 @@ public Recipe parseRandomRecipe(RecipeList recipes) throws NoRecipeException { return recipes.randomRecipe(); } - // @@author jaredoong + /** + * Checks whether the user wants to edit single, multiple, or clear all the recipes in the weekly plan. + * Then, return a WeeklyPlan object that contains the recipes that the user wants to add or delete. + * + * @author jaredoong + * @param command an array containing the user input + * @param recipes an object containing all recipes data + * @return a WeeklyPlan object that contains the recipes that the user wants to add or delete + * @throws NumberFormatException If users entered invalid character for the quantity. + * @throws InvalidRecipeNameException If users entered invalid recipe name. + * @throws InvalidValueException If users entered invalid quantity. + * @throws IllegalArgumentException If users did not enter a valid command. + **/ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) - throws ArrayIndexOutOfBoundsException, NumberFormatException, InvalidRecipeNameException, + throws IllegalArgumentException, NumberFormatException, InvalidRecipeNameException, InvalidValueException { WeeklyPlan updatedWeeklyPlan; switch (command[1]) { @@ -627,8 +657,23 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) return updatedWeeklyPlan; } + /** + * Parses the user input to extract the single recipe that the user wants to add or delete from the weekly + * plan. + * + * @author jaredoong + * @param command an array containing the user input + * @param recipes an object containing all recipes data + * @return a WeeklyPlan object that contains the single recipe and the quantity that the user wants to add + * or delete + * @throws NumberFormatException If users entered invalid character for the quantity. + * @throws InvalidRecipeNameException If users entered invalid recipe name. + * @throws InvalidValueException If users entered invalid quantity. + * @throws IllegalArgumentException If users did not enter a valid command. + */ private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidValueException, InvalidRecipeNameException { + throws IllegalArgumentException, NumberFormatException, InvalidValueException, + InvalidRecipeNameException { int numDays; if (command.length < 4) { @@ -660,8 +705,23 @@ private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipe } } + /** + * Parses the user input to extract the multiple recipes that the user wants to add or delete from the + * weekly plan. + * + * @author jaredoong + * @param command an array containing the user input + * @param recipes an object containing all recipes data + * @return a WeeklyPlan object that contains the multiple recipes and the quantities that the user wants + * to add or delete + * @throws NumberFormatException If users entered invalid character for the quantity. + * @throws InvalidRecipeNameException If users entered invalid recipe name. + * @throws InvalidValueException If users entered invalid quantity. + * @throws IllegalArgumentException If users did not enter a valid command. + */ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes) - throws InvalidValueException, InvalidRecipeNameException { + throws IllegalArgumentException, NumberFormatException, InvalidValueException, + InvalidRecipeNameException { int quantity; if (command.length < 6) { throw new IllegalArgumentException("Please enter the command in the correct format."); @@ -723,7 +783,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, - StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { + StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { recipeName.append(command[nameStartIndex].toLowerCase().trim()); for (int j = nameStartIndex + 1; j <= nameEndIndex; j++) { recipeName.append(" ").append(command[j].toLowerCase().trim()); @@ -746,9 +806,19 @@ public LocalDate parseDate(String input) { } } - // @@author jaredoong - public void parseAddUserIngredients(String[] command, IngredientList ingredientList) - throws InvalidValueException { + /** + * Parses the user input to extract the ingredient name, quantity, and expiry date that the user wants to + * add to the ingredient list. Returns the Ingredient object that contains parsed data. + * + * @author jaredoong + * @param command an array containing the user input + * @return an Ingredient object that contains the ingredient name, quantity, and expiry date + * @throws NumberFormatException If users entered invalid character for the quantity. + * @throws InvalidValueException If users entered invalid quantity. + * @throws IllegalArgumentException If users did not enter a valid command. + */ + public Ingredient parseAddUserIngredients(String[] command) + throws NumberFormatException, IllegalArgumentException, InvalidValueException { String ingredientName = null; Integer ingredientCount = null; String expiryDate = null; @@ -792,11 +862,24 @@ public void parseAddUserIngredients(String[] command, IngredientList ingredientL throw new IllegalArgumentException("Missing required information. Please use /n, /c, and /d."); } - ingredientList.addIngredient(new Ingredient(ingredientName, ingredientCount, expiryDate)); + return new Ingredient(ingredientName, ingredientCount, expiryDate); } - public void parseDeleteUserIngredients(String[] command, IngredientList userIngredients) - throws IngredientNotFoundException, InvalidValueException { + /** + * Parses the user input to extract the ingredient name and quantity that the user wants to delete from + * the ingredient list. Returns the Ingredient object that contains parsed data. + * + * @author jaredoong + * @param command an array containing the user input + * @return an Ingredient object that contains the ingredient name, quantity, and dummy expiry date + * @throws NumberFormatException If users entered invalid character for the quantity. + * @throws IngredientNotFoundException If users entered invalid ingredient name. + * @throws InvalidValueException If users entered invalid quantity. + * @throws IllegalArgumentException If users did not enter a valid command. + */ + public Ingredient parseDeleteUserIngredients(String[] command) + throws NumberFormatException, IllegalArgumentException, IngredientNotFoundException, + InvalidValueException { String ingredientName = null; Integer ingredientCount = null; @@ -836,11 +919,28 @@ public void parseDeleteUserIngredients(String[] command, IngredientList userIngr throw new IllegalArgumentException("Missing required information. Please use /n and /c."); } - userIngredients.deleteIngredient(ingredientName, ingredientCount); + return new Ingredient(ingredientName, ingredientCount, "01/01/2020"); } - public void parseMarkDone(String[] command, IngredientList userIngredients, WeeklyPlan weeklyPlan, - RecipeList recipes) throws IngredientNotFoundException, InvalidRecipeNameException { + /** + * Parses the user input to extract the recipe which the user wants to mark as done. Returns the recipe + * name to be deleted from the weekly plan. + * + * @author jaredoong + * @param command an array containing the user input + * @param userIngredients an object containing all ingredients data + * @param weeklyPlan an object containing all weekly plan data + * @param recipes an object containing all recipes data + * @return a string containing the recipe name to be deleted from the weekly plan. + * @throws NumberFormatException If users entered invalid character for the quantity. + * @throws IngredientNotFoundException If users entered invalid ingredient name. + * @throws IllegalArgumentException If users enter a recipe name that does not exist in the weekly + * plan, or if the user does not have enough ingredients to make the + * recipe. + */ + public String parseMarkDone(String[] command, IngredientList userIngredients, WeeklyPlan weeklyPlan, + RecipeList recipes) + throws IllegalArgumentException, IngredientNotFoundException, InvalidRecipeNameException { if (command.length == 2) { throw new IllegalArgumentException("Please enter a recipe name."); } @@ -862,16 +962,6 @@ public void parseMarkDone(String[] command, IngredientList userIngredients, Week } } - // If all ingredients are present, mark recipe as done - for (String ingredient : ingredients.keySet()) { - userIngredients.deleteIngredient(ingredient, ingredients.get(ingredient)); - } - - // Remove count of recipe from weekly plan - if (weeklyPlan.get(recipeName) == 1) { - weeklyPlan.remove(recipeName); - } else { - weeklyPlan.put(recipeName, weeklyPlan.get(recipeName) - 1); - } + return recipeName; } } diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index f0c269b22c..00158461f2 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -2,10 +2,18 @@ import java.util.ArrayList; import java.util.HashMap; +import seedu.meal360.exceptions.IngredientNotFoundException; public class WeeklyPlan extends HashMap { - public void addPlans(WeeklyPlan recipeMap) { + /** + * Adds a recipe to the weekly plan. + * + * @author jaredoong + * @param recipeMap the recipe to be added. + * @throws IllegalArgumentException if the total quantity of the recipe exceeds 1000. + */ + public void addPlans(WeeklyPlan recipeMap) throws IllegalArgumentException { final boolean[] validNumber = {true}; recipeMap.forEach((recipe, count) -> { if (validNumber[0] && this.containsKey(recipe)) { @@ -27,7 +35,14 @@ public void addPlans(WeeklyPlan recipeMap) { } } - public void deletePlans(WeeklyPlan recipeMap) { + /** + * Deletes a recipe from the weekly plan. + * + * @author jaredoong + * @param recipeMap the recipe to be deleted. + * @throws IllegalArgumentException if the recipe does not exist in the weekly plan. + */ + public void deletePlans(WeeklyPlan recipeMap) throws IllegalArgumentException { recipeMap.forEach((recipe, count) -> { if (this.containsKey(recipe)) { int currentCount = this.get(recipe); @@ -46,6 +61,13 @@ public void clearPlan() { this.clear(); } + /** + * Checks if the weekly plan contains any invalid recipes. + * + * @author jaredoong + * @param recipeList the list of recipes. + * @return true if the weekly plan contains no invalid recipes, false otherwise. + */ public boolean checkValidity(RecipeList recipeList) { ArrayList toRemove = new ArrayList<>(); this.forEach((recipe, count) -> { @@ -60,4 +82,30 @@ public boolean checkValidity(RecipeList recipeList) { toRemove.forEach(recipe -> this.remove(recipe)); return false; } + + /** + * Marks a recipe in the weekly plan as done. + * + * @author jaredoong + * @param recipeName the name of the recipe to be marked as done. + * @param recipeList the list of recipes. + * @param userIngredients the list of ingredients. + * @throws IngredientNotFoundException if the ingredient does not exist in the list of ingredients. + */ + public void markDone(String recipeName, RecipeList recipeList, IngredientList userIngredients) + throws IngredientNotFoundException { + HashMap ingredients = recipeList.findByName(recipeName).getIngredients(); + + for (String ingredient : ingredients.keySet()) { + Ingredient ingredientToDelete = new Ingredient(ingredient, ingredients.get(ingredient), + "01/01/2023"); + userIngredients.deleteIngredient(ingredientToDelete); + } + + if (this.get(recipeName) == 1) { + this.remove(recipeName); + } else { + this.put(recipeName, this.get(recipeName) - 1); + } + } } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index 28603e6997..d1e4c42796 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -841,7 +841,8 @@ public void testViewNonEmptyWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); weeklyPlan.put("salad", 1); ui.printWeeklyPlan(weeklyPlan); - assertEquals(ui.formatMessage("Here is your weekly plan:") + System.lineSeparator() + ui.formatMessage( + assertEquals( + ui.formatMessage("Here is your weekly plan:") + System.lineSeparator() + ui.formatMessage( "salad x1"), outContent.toString().trim()); } @@ -931,7 +932,7 @@ public void testPrintAddTagMessage() { String addTagReturnMessage = parser.parseTagRecipe(addTagInputs, recipes); ui.printTagMessage(addTagReturnMessage); assertEquals(ui.formatMessage("You have successfully added the recipe(s) to \"breakfast\" tag."), - outContent.toString().trim()); + outContent.toString().trim()); } catch (Exception e) { assert false; } @@ -945,7 +946,8 @@ public void testPrintRemoveTagMessage() { String[] removeTagInputs = new String[]{"tag", "breakfast", ">>", "salad"}; String removeTagReturnMessage = parser.parseTagRecipe(removeTagInputs, recipes); ui.printTagMessage(removeTagReturnMessage); - assertEquals(ui.formatMessage("You have successfully removed the recipe(s) from \"breakfast\" tag."), + assertEquals( + ui.formatMessage("You have successfully removed the recipe(s) from \"breakfast\" tag."), outContent.toString().trim()); } catch (Exception e) { assert false; @@ -1007,8 +1009,7 @@ public void testRemoveTagAndAddTag() { assertThrows(TagNotFoundException.class, () -> parser.parseTagRecipe(invalidTagInputs, recipes)); String[] noRecipeInTagInputs = new String[]{"tag", "western", ">>", "random"}; - assertThrows(NoRecipeException.class, - () -> parser.parseTagRecipe(noRecipeInTagInputs, recipes)); + assertThrows(NoRecipeException.class, () -> parser.parseTagRecipe(noRecipeInTagInputs, recipes)); try { inputs = new String[]{"tag", "western", ">>", "pizza"}; @@ -1047,7 +1048,8 @@ public void testWeeklyDone() { try { String userInput = "weekly /done burger"; String[] command = parser.cleanUserInput(userInput); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + String recipeToDelete = parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + weeklyPlan.markDone(recipeToDelete, recipes, userIngredients); assertEquals(8, userIngredients.findIngredientCount("buns")); assertEquals(9, userIngredients.findIngredientCount("meat patty")); assertEquals(7, userIngredients.findIngredientCount("lettuce")); @@ -1060,7 +1062,8 @@ public void testWeeklyDone() { try { String userInput = "weekly /done Pizza"; String[] command = parser.cleanUserInput(userInput); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + String recipeToDelete = parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + weeklyPlan.markDone(recipeToDelete, recipes, userIngredients); assertEquals(9, userIngredients.findIngredientCount("dough")); assertEquals(9, userIngredients.findIngredientCount("tomato sauce")); assertEquals(9, userIngredients.findIngredientCount("cheese")); @@ -1074,7 +1077,8 @@ public void testWeeklyDone() { try { String userInput = "WEEKLY /DONE pizza"; String[] command = parser.cleanUserInput(userInput); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + String recipeToDelete = parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + weeklyPlan.markDone(recipeToDelete, recipes, userIngredients); assertEquals(8, userIngredients.findIngredientCount("dough")); assertEquals(8, userIngredients.findIngredientCount("tomato sauce")); assertEquals(8, userIngredients.findIngredientCount("cheese")); @@ -1088,7 +1092,8 @@ public void testWeeklyDone() { try { String userInput = "weekly /done chicken rice"; String[] command = parser.cleanUserInput(userInput); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + String recipeToDelete = parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + weeklyPlan.markDone(recipeToDelete, recipes, userIngredients); assertEquals(9, userIngredients.findIngredientCount("chicken")); assertEquals(9, userIngredients.findIngredientCount("rice")); assertEquals(99, weeklyPlan.get("chicken rice")); @@ -1100,7 +1105,8 @@ public void testWeeklyDone() { try { String userInput = "weekly /done pizzaandburgers"; String[] command = parser.cleanUserInput(userInput); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + String recipeToDelete = parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + weeklyPlan.markDone(recipeToDelete, recipes, userIngredients); assert false; // should not reach here } catch (Exception e) { assertEquals(InvalidRecipeNameException.class, e.getClass()); @@ -1111,7 +1117,8 @@ public void testWeeklyDone() { try { String userInput = "weekly /done salad"; String[] command = parser.cleanUserInput(userInput); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + String recipeToDelete = parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + weeklyPlan.markDone(recipeToDelete, recipes, userIngredients); assert false; // should not reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); @@ -1122,9 +1129,10 @@ public void testWeeklyDone() { try { String userInput = "weekly /done burger"; String[] command = parser.cleanUserInput(userInput); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); - parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + for (int i = 0; i < 3; i++) { + String recipeToDelete = parser.parseMarkDone(command, userIngredients, weeklyPlan, recipes); + weeklyPlan.markDone(recipeToDelete, recipes, userIngredients); + } assert false; // should not reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); @@ -1139,7 +1147,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n fish /c 10 /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assertEquals(10, userIngredients.findIngredientCount("fish")); } catch (Exception e) { assert false; @@ -1149,7 +1158,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c 10 /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assertEquals(20, userIngredients.findIngredientCount("chicken")); } catch (Exception e) { assert false; @@ -1159,7 +1169,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n CHICKEN /c 10 /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assertEquals(30, userIngredients.findIngredientCount("chicken")); } catch (Exception e) { assert false; @@ -1169,7 +1180,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c 10 /d 21/10/2025"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assertEquals(40, userIngredients.findIngredientCount("chicken")); assertEquals(parser.parseDate("21/10/2025"), userIngredients.findExpiryDate("chicken")); } catch (Exception e) { @@ -1180,7 +1192,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n peas and corn and carrot /c 10 /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assertEquals(10, userIngredients.findIngredientCount("peas and corn and carrot")); } catch (Exception e) { assert false; @@ -1190,7 +1203,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c 0 /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assert false; // should not reach here } catch (Exception e) { assertEquals(InvalidValueException.class, e.getClass()); @@ -1202,7 +1216,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c -10 /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assert false; // should not reach here } catch (Exception e) { assertEquals(InvalidValueException.class, e.getClass()); @@ -1214,7 +1229,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c 1001 /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assert false; // should not reach here } catch (Exception e) { assertEquals(InvalidValueException.class, e.getClass()); @@ -1226,7 +1242,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c abc /d 10/10/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assert false; // should not reach here } catch (Exception e) { assertEquals(NumberFormatException.class, e.getClass()); @@ -1238,7 +1255,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c 10 /d 10/10/202"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assert false; // should not reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); @@ -1249,7 +1267,8 @@ public void testAddUserIngredients() { try { String userInput = "add_i /n chicken /c 10 /d 10/13/2024"; String[] command = parser.cleanUserInput(userInput); - parser.parseAddUserIngredients(command, userIngredients); + Ingredient ingredientToAdd = parser.parseAddUserIngredients(command); + userIngredients.addIngredient(ingredientToAdd); assert false; // should not reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); @@ -1264,7 +1283,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n chicken /c 5"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assertEquals(5, userIngredients.findIngredientCount("chicken")); } catch (Exception e) { assert false; @@ -1274,7 +1294,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n CHEESE /c 5"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assertEquals(5, userIngredients.findIngredientCount("cheese")); } catch (Exception e) { assert false; @@ -1284,7 +1305,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n peas and corn /c 5"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assertEquals(5, userIngredients.findIngredientCount("peas and corn")); } catch (Exception e) { assert false; @@ -1294,7 +1316,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n chicken /c 100"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assertNull(userIngredients.get("chicken")); } catch (Exception e) { assert false; @@ -1304,7 +1327,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n chicken /c 0"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assert false; // should not reach here } catch (Exception e) { assertEquals(InvalidValueException.class, e.getClass()); @@ -1316,7 +1340,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n chicken /c -5"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assert false; // should not reach here } catch (Exception e) { assertEquals(InvalidValueException.class, e.getClass()); @@ -1328,7 +1353,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n chicken /c 1001"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assert false; // should not reach here } catch (Exception e) { assertEquals(InvalidValueException.class, e.getClass()); @@ -1340,7 +1366,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n chicken /c abc"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assert false; // should not reach here } catch (Exception e) { assertEquals(NumberFormatException.class, e.getClass()); @@ -1352,7 +1379,8 @@ public void testDeleteUserIngredients() { try { String userInput = "del_i /n beef /c 5"; String[] command = parser.cleanUserInput(userInput); - parser.parseDeleteUserIngredients(command, userIngredients); + Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); + userIngredients.deleteIngredient(ingredientToDelete); assert false; // should not reach here } catch (Exception e) { assertEquals(IngredientNotFoundException.class, e.getClass()); @@ -1391,14 +1419,14 @@ public void testLoadDatabase() { @Test - public void testCombineWords(){ - String[] input1 = {"One", "Two" , "Three"}; + public void testCombineWords() { + String[] input1 = {"One", "Two", "Three"}; assertEquals("One Two Three", parser.combineWords(input1, 0, 3)); - String[] input2 = {"Pizza ", "Burger " , " Ice Cream"}; + String[] input2 = {"Pizza ", "Burger ", " Ice Cream"}; assertEquals("Pizza Burger Ice Cream", parser.combineWords(input2, 0, 3)); - String[] input3 = {"1 1 1", "2 2 2" , "3 3 3"}; + String[] input3 = {"1 1 1", "2 2 2", "3 3 3"}; assertEquals("1 1 1 2 2 2 3 3 3", parser.combineWords(input3, 0, 3)); } From 27703a959f0f5e97d7667b06c1021fd25feea98f Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sun, 9 Apr 2023 00:06:37 +0800 Subject: [PATCH 205/252] Update CG to reflect refactored code --- .../UML/Architecture/IngredientRelated.drawio | 2 +- docs/UML/Architecture/IngredientRelated.png | Bin 28975 -> 28806 bytes .../UML/Architecture/WeeklyPlanRelated.drawio | 2 +- docs/UML/Architecture/WeeklyPlanRelated.png | Bin 38196 -> 43124 bytes .../IngredientListClassDiagram.drawio | 2 +- .../IngredientListClassDiagram.png | Bin 32616 -> 35084 bytes .../WeeklyPlan/WeeklyPlanClassDiagram.drawio | 2 +- .../UML/WeeklyPlan/WeeklyPlanClassDiagram.png | Bin 9238 -> 12308 bytes 8 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/UML/Architecture/IngredientRelated.drawio b/docs/UML/Architecture/IngredientRelated.drawio index 1cf0a8625a..27f388e91e 100644 --- a/docs/UML/Architecture/IngredientRelated.drawio +++ b/docs/UML/Architecture/IngredientRelated.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/UML/Architecture/IngredientRelated.png b/docs/UML/Architecture/IngredientRelated.png index f77b3353603303fed94bded7b7d7671b674d3c41..9372e0f17e672b0c7105f2d156d90f94fb7c9110 100644 GIT binary patch literal 28806 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 Z=BGF-56nWriv^FF7+73>2fO{`e*ydJ?a2TD literal 28975 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 A7XSbN diff --git a/docs/UML/Architecture/WeeklyPlanRelated.drawio b/docs/UML/Architecture/WeeklyPlanRelated.drawio index 0e00a62c2b..1efbab1276 100644 --- a/docs/UML/Architecture/WeeklyPlanRelated.drawio +++ b/docs/UML/Architecture/WeeklyPlanRelated.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/UML/Architecture/WeeklyPlanRelated.png b/docs/UML/Architecture/WeeklyPlanRelated.png index bfaaab437449540fc1354065ab7fb96c8dc1e945..253a18dff3090c6e7a58ab8abd23e1c7032da744 100644 GIT binary patch literal 43124 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 diff --git a/docs/UML/IngredientList/IngredientListClassDiagram.drawio b/docs/UML/IngredientList/IngredientListClassDiagram.drawio index 4a9b3d524f..36a74567b5 100644 --- a/docs/UML/IngredientList/IngredientListClassDiagram.drawio +++ b/docs/UML/IngredientList/IngredientListClassDiagram.drawio @@ -1 +1 @@ -7Vltb+I4EP41SHsrsco78LFAd7e69hYd1V370Y1NYtWxOccU6K+/MbFJQgJkd8s3JCTsx+OxZ57xeDA9f5Jtvkm0TB8EJqznOXjT86c9z3MdP4IvjWwLJHKDAkgkxQXklMCcvhM706AriklusAJSQjBFl3UwFpyTWNUwJKVY18UWguEasEQJaQDzGLEm+i/FKjWoG43Kge+EJqlZeugNioEMWWFjSZ4iLNYVyL/t+RMphCpa2WZCmHZe3S9fj4zuNyYJV10mzMLH/56S17d07PyJh4lLBs9x32h5Q2xlDDabVVvrASlWHBOtxOn543VKFZkvUaxH18A5YKnKGPRcaOZKilcyEUxIQLjgIDZu7tQuS6Qimwpkdv6NiIwouQUROzoyGzNh5A6NinVJSjD0Cyyt8BG6QxMMJhCSve7SV9Aw7mp33XBBH7Y/ttH7wzRL0ep78PyUtbjujieSYApW3tNcNRyZr2nG0M4jC8HV3IxotyFGEw7tGOYS8NxYe4ZCFN6YASW0o+OUMnyPtmKlrcsVil9tb5wKSd9BLSqpQFKZA+VFNYm5nmkIlSQHmZklxz2AHtCmJniPcmWAWDCGljl92ZuRIZlQPhZKicwIfQD3nufXuPecqMm9FzW5h6i5EPdeg/s+mJhr6m4AnxXtwwAAe9WxM7KgjB1ANigYWaijIZHDUaQ8ud/JTIMS+dv4QUMC5i7YLvmkFGPCNZ1CIYUK7jRRS0G52vkpHMMHcsnE+RL2Qtj4BPpu2YePFpdqIjjYguiOWQKBsSY6OFo4P3mAzgeCJb4r75c68v75bMnojruCY3tjuL9EcAZUMVIy+qgJn/bdBut+k3W/hWGGXgibiZwqKrR+WcgeMH+O3Hr0Up4SSS9Jehh0I/1SnAfNo84gu5e5Pv/0R3Hq50oCAz29Od8tch+wznEpOoGrVH2i+/5fKCPVuUbRHVwCic4fh5puN0sqt1OkyHkl9wJCSYvW1SBc2U9Fi13Z9o2WNwHOqSmAYdVJg84b4Nu68QcGagmyN6rFiub6UGASRU7swNJwbvWjKyxhfhu/RyR3pBDcaULMCJLdJc+pvt4vH5pqIq9bqnHDwYWSTXiiprzWkx9VTzqDWj0ZjJwm70Eb7/ZHyIfzHjUvmeMJvpIo+qfTayl3mGTbboc+zU3CKWTG8DubIH5NM6fTTNg5/k6UsW3hFoUXirbBtYz93TL2p0kftbxXtJF+qTJ22ML5uLWKaqab36vjamVNx7qNk3XXZfaZ7GCl1RIDaBLatWy6ZGiPuoX2yL9QbLsdXjEJxzf6ORh6mKJMcPyYUu1wGPhKmS1yoGdLnKD+sll/BiUbqp50G3xf9J4rI9NNtbO1HQ7GFpOC4cACep77xXFcC5STd73a7BlkKfCZLulOV0O5WMmYnGcZarqEnIoG8/OX4NozeTMWKuS7kamnJGFI0bf6S3ob+0bdTMd6Waf59o3X1mmDoK6iMNLMqr58HygKgzOKCi80FO2CcW9jp/i8e7lz5+u3m+FqNM4GL8//xD9Iy0vx52NJ6NxT+ol8dLTW31/AbW/39bA+cvRbQuxodR24B862ZUwlQmyAVLOD7/x0doBu+fdJQVb5J5R/+z8= \ No newline at end of file +7Vltj9o4EP41SL2TqHDeFj7ysm1X2r1ypep175s3NomvTowcs5D99R0Th8QkgfS6fFsJiXg8M87M83g8mIE7T/YfJd7ED4JQPnBGZD9wFwPHQSM3gC8tyQtJgLxCEElGCtGoEqzYCy0tjXTLCM2MrBApIbhiG1sYijSlobJkWEqxs9XWghNLsMERbQhWIeZN6T+MqNhIUTCpJj5RFsVm6bFzU0wkuFQ2kWQxJmJXE7m3A3cuhVDFU7KfU66TZ+flQ8fs8cUkTVUfg285mT7+nXxZ/pv/97j4+BKMonzoFF6eMd+agM3LqrzMgBTblFDtZDRwZ7uYKbra4FDP7gBzkMUq4TBC8JgpKX7QueBCgiQVKajNzBpUKrrvfHl0TAlwiYqEKpmDSmkwMfk2NEJj86K7ChTfNamPa3j4ruEbNkSIjr6rXMGDSVd76sZr9pB/zoOXh0US4+0n7/F7MkSN1N2lkaSEQUj3LFONRGY7lnB8yMhapGplZnTaMGdRCs8h2FLI3EwniwELp2ZCCZ3oMGac3ONcbHV0mcLhj3I0i4VkL+AWV1BgqcyGcgJLY6UtDaCSZqCzLJFAJ6IHvLcU73GmjCAUnONNxp6OYSRYRiydCaVEYpQ6gG6hQyf2juNa2DujoIG9N/aa2DvIuRL2zW0zhBAzDd0U5Mvi+ZQAEK/q2iNrxvmJqCQFp2vVSYkMtiJLo/uDzsKrJF9MHrRIgO2aH4pPzAihqYZTKKxwgZ0GaiNYqg558mfwgVoyH733Bz68+BzGqBrDR6tLNRcpxILZAVkKxNhRTY4WzM9uoMtEKIHvi/v4SrC7l6slZwfsCozLEwP9L4ATgIrTCtGvGvDFEDVQd5uouy0Ic/xE+VJkTDGh/ctC9wT5S+Da7GVpTCW7Jui+1w/0a2HuNbc6h+pe1frs3R/Frl8pCQgMNEtdVNQ+QD0lleocjlL1jh3Hf+GE1m2Nozs4BCJdP0493e43TOYLrOhlJ/cCqKRVbTeY1N6n5qVcuRwbL88CkmM5gGnVy4OuG5BbO/iTALUGPQbVEkVzfWgwqaJn3qCE4dLqnStswL4N3w7NAyiU9DIIOcWyv+Yl12/ny6uWmqDZU7aWGuSPrlRs/DM95Vs/+Vr9pOtb/aQ3GTdx94IW3CfX6ieD5iHTXeBrhWJ4vrxWeqdFtu10GLLMFJxCZwa/sylO38rM+TLj9+bfmTa2jW6BfyW23by1sb/bxv4y6BPUD/RrtbHjFsxnrV1Us9z8Xh9ntTU9+7aU7vouc6xkJyttNwSEpqC9tU3XpPakH7Un7pW4jZpXcQ2QaUqm+joYRoThRKTka8x0wmHiA+NlkwOjssXx7JtN+xqU7pn6rp8h98XosTaz2NcHeTlIIdjCyBvflAJth96PRqgUVMaHkWW9hCoFOdMt3fluKBNbGdLLKENPF9FzbDDtLyXWNXmTCzXwUWDaY0k5VuzZvklvQ9+4W2quV32aO0Z2n3ZzcpVbBGms6jffJ45874KjIgsNRwcyHmPsxc+7pzu02j1Px9vJLLl5evwWfqYtN8V/dhWhS1fpZ+pRZ69/PIDb7u5tWr9Cd+2V/3cck91sd0qC1KuD++u/qWBY/X1SgFX9CeXe/gQ= \ No newline at end of file diff --git a/docs/UML/IngredientList/IngredientListClassDiagram.png b/docs/UML/IngredientList/IngredientListClassDiagram.png index be25774c257516a4d1b224c62fab205a14fd3e57..2be6b7bc4a40b66eea035186c8b403e372025f9d 100644 GIT binary patch literal 35084 zcmd42by!qi6gFz0Vjuz%4hTvr9RouM$Rs&53@r>Xz`#&L3}pZk0wPEXNH<7Js~~C6 z9Y0c1ly2`C->qYrkvl5Dhen>JsSEsZ*z@loa7w zr%s�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�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

>8WDYw-lS!{c+Yqj@2Qh~CA9>>CmK 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 XDy+hOetSg({@qg1Q7%@reDps6fO$M? diff --git a/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio b/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio index 028e675920..9221fd3069 100644 --- a/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio +++ b/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.drawio @@ -1 +1 @@ -7ZZdb9owFIZ/TaTuolM+CNDLJnSttqJVZVq3Szc+xB5OzBxTSH/9jolDSBNatoq7SQjZr4+/3ufYsRPE2eZakSWbSgrC8V26cYKJ4/uh6+K/EcpKCGohVZxW0p4w489QiV6trjiFwmqVpKUUmi/bYiLzHBLd0ohSct0Om0tBW8KSpNARZgkRXfWBU82s6g0vmoYb4CmzU4/9UdWQkTrY7qRghMr1nhRcOUGspNRVKdvEIIx3bV8+HWjdLUxBro/pQKn3Oxwxeh2kv5g3+vyFTKJzO8oTESu7YbtYXdYOKLnKKZhBXCeI1oxrmC1JYlrXiBw1pjOBNQ+LhVZyAbEUUqGSyxzDIjsHKA2bg4v3dpZgKoHMQKsSQ+oOF+Oqi00jPwir+rqBErjDSmN7PLzQ8iA2EdLd2I1XWLB29Vs3nvNp+bUcPk8nGSOrm8HPH1mPdQ8AC1HeCZJ3TCzWPEPduDGXuZ7ZFmMZETzNsZygFYCuRcYojhl4aRu0NCYnjAt6S0q5MjsrNEkWdS1iUvFnHJY0GIjS9jD5w1bEzPS0MBUUGHNXU/BeSFOyaQXekkJbIZFCkGXBH3fbyIhKeR5JrWVmgw5A7kmFg9x996LNfTDqcPfHXg/3wD8Rd797ZGLfuXQ7zHGL+tCRmHMhXkh1HgiY64NZUODJ43l6u42ZDBrl3m7dSBL7zsX2rmGcUsgNQamJJhUuw2Ypea631oQR/nD1sfsxdEJceIx1r6njz4QrHcsc90L4FiZgLqzB5EMP5lfPy9vsa9bD41D7gxORDt6+HAXfsqsY1x8I758AZ4hKQEP0mwE+Ofc61IMu9aCHsCCPIO5kwTWXZnxVxb4g/xbcdvbynIHip4QeusdBH5+I+aCHeWQmotRc7MWZgoQvYWo+fJeoN3f+h0p4kji+Sd3Aq+5A0xsfRaDhHQMkAogyQWevRjFIFt8xzyjXpZ3olhuOpsv9rm7HeMSHFPR8rP5fXO/M4fFxOTz6+4sLq82Lcdu29+wOrv4A \ No newline at end of file +7Zffb5swEMf/mkjdQyd+JLR9LKRrJyVrtGzrujcXLmDF2Mg4JfSv3xlMCCFps615mxSp9vfOh32f80EHbpCubyXJkqmIgA0cK1oP3PHAcWzL9fCPVspa8exhLcSSRrVktcKcvkCz0qgrGkFutFpSQjBFs64YCs4hVB2NSCmKrttCsKgjZCSGnjAPCeurDzRSiVFt76o13AGNE/PoS+eiNqSkcTYnyRMSiWJLcm8GbiCFUPUoXQfAdPK6efl0wLrZmASujlkQ3Ge/vpe+B9ZY8fmjd19Es3MT5ZmwlTmw2awqmwxIseIR6CDWwPWLhCqYZyTU1gKZo5aolOHMxmGupFhCIJiQqHDB0c3v77R5LEgF6y3J7PwWRApKluhirI5llpgyclyT5qKF4rrGJ9niYV+Z9BNTCPEmdpsrHJh07U/d5YJOy/vSe5mO04Ss7oaPP9M9qXsAWLJyxgjvJTEvaIq6zsZCcDU3Fp0ywmjMcRxidgCz5uusUKzAa2NQQic5TCiLJqQUK32yXJFw2cz8REj6gmFJi4FIZS6T43U85nqlgSkhR59ZA8bekaZk3XGckFwZIRSMkSynT5tjpETGlPtCKZEap3fhftXlPtzDvWkpHe4Xp+Lu9K9M4AyurR5zPKI6dCUWlLEdqakDBgt1sApyvHmUx5PKZzxsla/m6FoSuHbBql6T0CgCrgkKRRSpcWk2maBcVakZ+fjD3QfWx9FghBsPcG63c/xpd6kCwfEshFYwAWuhAF0PezC/el/eZt+w9o5D7QxPRNp9uzkyWrGrGTcvCPuvAKeIikFL9JsGPj63e9TdPnV3D2FGnoDNRE4VFTq+rH13yL8Ft1u9lCcg6Smhj6zjoF+eiPlwD3NfPyiKdGPPzySENIOpfvFdo972/A+18Cwwvi5d1657oF6NX0Wg4B8ChAyI1E5nr3olEC5/YJ1FVJXmQROqOeolXzdzE+MJP6RAv6x2wmArX46xZk2ELySFesFcSSw63SEc63D0yt6GNM3ROtFglYP8zGMJEYWqrvVmWmHruHXK/jfp972vl0e+j23nj28sTtvP48q29U+Ge/Mb \ No newline at end of file diff --git a/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.png b/docs/UML/WeeklyPlan/WeeklyPlanClassDiagram.png index a2e3cd2e5b9af1603370f9b5433c479089adbde2..37b164360128834a1e91da624af3003e4a0d6e48 100644 GIT binary patch literal 12308 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 eRw{N&VBlH$H)^8TGVn(qK5Gkm^IEuf+ Date: Sat, 8 Apr 2023 23:58:56 +0700 Subject: [PATCH 206/252] fix DeleteFunction diagram in DG --- .../DeleteFunction/DeleteFunction.jpg | Bin 46986 -> 64144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg b/docs/UML/Implementation/DeleteFunction/DeleteFunction.jpg index b03bccbb96635db1ac03d7ebba1184b4ee000ed3..ebe41a428847fc5e9db37136dbbd26ae21f501eb 100644 GIT binary patch literal 64144 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 From b998bc62d7eda7def27581134ed7fdb210071168 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Sun, 9 Apr 2023 02:09:53 +0700 Subject: [PATCH 207/252] fix bug with adding recipe & update PPP --- docs/DeveloperGuide.md | 1 + docs/UserGuide.md | 10 +++++++--- docs/team/gurmankalkat.md | 6 +++++- src/main/java/seedu/meal360/Parser.java | 16 ++++++++++++---- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 4c6a0f0c43..5f812ac3c5 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -175,6 +175,7 @@ The `WeeklyPlan` component: - stores the number of times the user plans to prepare each recipe as `Integer` - allows users to add single or multiple recipes from the weekly plan - allows users to delete single, multiple, or all recipes from the weekly plan +- allows users to see all ingredients for the week How the `WeeklyPlan` component works: diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 1527a50b6d..20e1319343 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -40,11 +40,15 @@ ___ * Please follow the below-mentioned format. -Format: `ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ...` +Format: `ingredient1_name=ingredient1_quantity and ingredient2_name=ingredient2_quantity ...` -* Examples: `chicken=100 oil and sauce=200 vegetables=300` - `meat=200 salt and spices=400` * Type the ingredient name followed by equal sign and quantity in positive integer values. +* Type done when finished inputting all ingredients for the recipe. +* Example: +``` +chicken=100 and oil and sauce=200 and vegetables=300 +done +```
diff --git a/docs/team/gurmankalkat.md b/docs/team/gurmankalkat.md index 952b337009..3221172fd7 100644 --- a/docs/team/gurmankalkat.md +++ b/docs/team/gurmankalkat.md @@ -25,5 +25,9 @@ apps. * __Review/Mentoring contributions__: * PRs reviewed: [#4](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/4), [#15](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/15), - [#39](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/39), + [#39](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/39), + [#125](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/125), + [#127](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/127), + [#135](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/135) + diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index d9656f8517..8d730fe89f 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -107,16 +107,23 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { - ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printMessage( + "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { break; } } else { addedIngredient = 1; - String[] command = line.trim().split(" "); + String[] command = line.trim().split(" and "); ingredients = parseIngredientName(command); - if (ingredients.size() == 0) { + boolean ingredientsInCorrectFormat = true; + for (int i = 0; i < command.length; i++) { + if (!command[i].contains("=")) { + ingredientsInCorrectFormat = false; + } + } + if (ingredients.size() == 0 || !ingredientsInCorrectFormat) { ui.printSeparator(); ui.printMessage(recipeErrorMessage); ui.printSeparator(); @@ -124,7 +131,8 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { } } catch (IllegalArgumentException e) { ui.printSeparator(); - ui.printMessage(e.getMessage()); + System.out.println("here"); + ui.printMessage(recipeErrorMessage); ui.printSeparator(); } } From 5f520bc7f8ac2c4ac87cfe3e5534c125e98f607f Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Sun, 9 Apr 2023 02:15:03 +0700 Subject: [PATCH 208/252] clean up code --- src/main/java/seedu/meal360/Parser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 8d730fe89f..11fc723673 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -131,7 +131,6 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { } } catch (IllegalArgumentException e) { ui.printSeparator(); - System.out.println("here"); ui.printMessage(recipeErrorMessage); ui.printSeparator(); } From 4f13ce164e2afa80d5738ae3a414c87f9b4dfb54 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Sun, 9 Apr 2023 02:23:00 +0700 Subject: [PATCH 209/252] add more clarification to recipe error message --- src/main/java/seedu/meal360/Parser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 11fc723673..c896d7c433 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -20,8 +20,8 @@ public class Parser { Ui ui = new Ui(); - String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly!" + - "[eg:chicken=100]"; + String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly " + + "[eg:chicken=100] and \"done\" when finished entering ingredients!"; public String combineWords(String[] input, int startIndex, int length) { StringBuilder word = new StringBuilder(input[startIndex].trim()); From 8761cbc4bfe9dd8f76936fc2037b451e00c00afe Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Sun, 9 Apr 2023 02:37:18 +0700 Subject: [PATCH 210/252] add to DG --- docs/DeveloperGuide.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 5f812ac3c5..e5e658e6d1 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -186,7 +186,8 @@ How the `WeeklyPlan` component works: 3. `Parser` component then returns a `WeeklyPlan` object to indicate the recipe(s) to be added or deleted from the weekly plan. 4. `WeeklyPlan` component then uses either `addPlans` or `deletePlans` method to add or delete - the recipe(s) from the weekly plan. + the recipe(s) from the weekly plan, `clearPlan` to clear the entire plan for the week, and `checkValidity` to + check the validness of the weekly plan (i.e. make sure all recipes are valid). The sequence diagram below shows how the `WeeklyPlan` component works when the user inputs `weekly /add burger 1`: From 59c0aa8c7607e0a9e0745f87ce8b10294a9d5331 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 13:17:32 +0800 Subject: [PATCH 211/252] Added UML diagrams for add and edit functions. Updated User guide. Updated Developer Guide, added Parser component diagram to Parser class in DG. --- Parser.puml | 24 -------- docs/DeveloperGuide.md | 6 ++ .../Implementation/AddRecipe/addRecipe.png | Bin 0 -> 15566 bytes .../Implementation/EditRecipe/editRecipe.png | Bin 0 -> 15494 bytes docs/UML/Parser/ParserClassDiagram.png | Bin 0 -> 47184 bytes docs/UserGuide.md | 53 +++++++++++------- 6 files changed, 40 insertions(+), 43 deletions(-) delete mode 100644 Parser.puml create mode 100644 docs/UML/Implementation/AddRecipe/addRecipe.png create mode 100644 docs/UML/Implementation/EditRecipe/editRecipe.png create mode 100644 docs/UML/Parser/ParserClassDiagram.png diff --git a/Parser.puml b/Parser.puml deleted file mode 100644 index 04698e5967..0000000000 --- a/Parser.puml +++ /dev/null @@ -1,24 +0,0 @@ -@startuml -class seedu.meal360.Parser { -~ Ui ui -+ String combineWords(String[],int,int) -+ HashMap parseIngredientName(String[]) -+ Recipe parseAddRecipe(String[],RecipeList) -+ Recipe parseEditRecipe(String[],RecipeList) -+ String parseDeleteRecipe(String[],RecipeList) -+ String parseTagRecipe(String[],RecipeList) -+ String parseAddRecipeTag(String,RecipeList) -+ String parseRemoveRecipeTag(String,RecipeList) -+ RecipeList parseListRecipe(String[],RecipeList) -+ Recipe parseViewRecipe(String[],RecipeList) -+ Recipe parseViewRecipe(String,RecipeList) -+ Recipe parseRandomRecipe(RecipeList) -+ WeeklyPlan parseWeeklyPlan(String[],RecipeList) -- WeeklyPlan parseEditSingleWeeklyPlan(String[],RecipeList) -- WeeklyPlan parseEditMultiWeeklyPlan(String[],RecipeList) -- StringBuilder getRecipeNames(String[],ArrayList,StringBuilder,int,int) -+ LocalDate parseDate(String) -+ void parseAddUserIngredients(String[],IngredientList) -+ void parseDeleteUserIngredients(String[],IngredientList) -} -@enduml \ No newline at end of file diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 8e1c3c83ce..c064527498 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -134,9 +134,11 @@ when the user inputs `list`. API: `Parser.java` The `Parser` component: +![](./UML/Parser/ParserClassDiagram.png) - receives the user input from the `Meal360` component - checks and filters input string +- executes the appropriate methods in Parser class; eg:parseAddRecipe, parseEditRecipe, etc. - catches `exceptions` and throws error messages via `UI` to 1. prompts user to enter valid input 2. prevent `Meal360` from crashing upon invalid input @@ -372,6 +374,8 @@ It is implemented through the following steps: to `recipeList.addRecipe()` to store the new recipe data. +![](./UML/Implementation/AddRecipe/addRecipe.png) + ### Edit Recipes Feature The current implementation: @@ -393,6 +397,8 @@ It is implemented through the following steps: to `recipeList.editRecipe()` to update the new recipe data. +![](./UML/Implementation/EditRecipe/editRecipe.png) + ### Random a Recipe Feature - randomly pick a recipe and display to the user diff --git a/docs/UML/Implementation/AddRecipe/addRecipe.png b/docs/UML/Implementation/AddRecipe/addRecipe.png new file mode 100644 index 0000000000000000000000000000000000000000..0ac286033ca5c809c96aa6079084f6cdcfefb300 GIT binary patch literal 15566 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

Rjy9uX=!EXiTOf9J-kiRuJEmHl|g!1?} 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 Wv9VtZh0u1=7@)OJu29B2;C}&oVcUBE literal 0 HcmV?d00001 diff --git a/docs/UML/Parser/ParserClassDiagram.png b/docs/UML/Parser/ParserClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..cdd0ad69e988bfcd003f88b91235922b749ea4e8 GIT binary patch literal 47184 zcmce;WmJ@5+cgX*iXak7DIwh{AuT1{-Q6iEjUdv3z<@}X)X?229n#GZk^>Aqz%a}= zp!ah>Ki;*zAMg6U)8&He0_Qrev-Yv~u}>pZl%%mSUt*%5pkT|&NUEWrJRm?pLH&vG z2zdu{spt~<1=USWS{$Wplynz)@z7dKQ49s8G8XH`6dif}#6?Ee4F%;{_uXIAKIcLU z6qNc+SxGUCk46V@MH>T1^7a#QY~eWU)}7!zanuVc{E_v{=*U46!e^b%-@bj!;z|)^ zKqDc|d1Sz5r}~puZn`77ORqoM=xnF_7f10(9{BMahNq%d$Wk!>M%sJGLS??!Kwkwc)UOJI9A>||-173emK{G;VWjE0OB z*@F15Ky!!(e=j-=-WC1*4u$2jSD>D*?)dY6*Bmh%kyL6-U0DCFiu}|L$KdD%6qKVFD!E_1 zw-9w0qDir~-CUVT+x-|JlD~p@H+7@EJr$^0yN!x`yUn;6vb)$i_##!Aez;%fD<4Q- z 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 @@ -120,6 +133,7 @@ Format: `view INDEX` Example of usage: `view 1` +`view 8`
@@ -182,7 +196,7 @@ Example of usage:
-### Adding single recipe this week's plan: `weekly /add` +### Add single recipe to weekly plan: `weekly /add` Adds an existing recipe to this week's plan. @@ -201,7 +215,7 @@ Example of usage:
-### Adding multiple recipes to this week's plan: `weekly /multiadd` +### Add multiple recipes to weekly plan: `weekly /multiadd` Adds multiple existing recipe to this week's plan. @@ -223,7 +237,7 @@ Example of usage:
-### Deleting from this week's plan: `weekly /delete` +### Delete single recipe from weekly plan: `weekly /delete` Deletes an existing recipe from this week's plan. @@ -242,7 +256,7 @@ Example of usage:
-### Deleting multiple recipes from this week's plan: `weekly /multidelete` +### Delete multiple recipes from weekly plan: `weekly /multidelete` Deletes multiple existing recipe from this week's plan. @@ -267,7 +281,7 @@ Example of usage:
-### Clearing this week's plan: `weekly /clear` +### Clear weekly plan: `weekly /clear` Clears this week's plan by removing all recipes listed in weekly plan. @@ -275,7 +289,7 @@ Format: `weekly /clear`
-### Mark recipe in this week's plan as done: `weekly /done` +### Mark recipe in weekly plan as done: `weekly /done` Mark a recipe in the weekly plan as completed. A single count of the recipe and its corresponding ingredients will be removed from the weekly plan and the list of ingredients. @@ -293,7 +307,7 @@ Example of usage:
-### View this week's plan: `weeklyplan` +### View weekly plan: `weeklyplan` View this week's plan. @@ -301,7 +315,7 @@ Format: `weeklyplan`
-### View this week's ingredients: `weeklyingredients` +### View weekly plan ingredients: `weeklyingredients` View this week's ingredients. @@ -320,7 +334,8 @@ Format: `random` ### Exit the program: `bye` -Exits the program. +* Exits the program. +* If any ingredients are added by the user, they get saved in JSON files for usage the next time. Format: `bye` @@ -369,10 +384,10 @@ Format : `view_ingredients` ## Command Summary -| Action | Format, Examples | +| Action | Format & Examples | |------------------------------------|-------------------------------------------------------------------------------------------------------------| -| Add recipe | `add /r [RECIPE_NAME]`
e.g `add /r chicken rice` | -| Edit recipe | `edit /r [RECIPE_NAME]`
e.g `edit /r chicken rice` | +| Add recipe | `add /r [RECIPE_NAME]`
e.g `add /r Chicken Rice` | +| Edit recipe | `edit /r [RECIPE_NAME]`
e.g `edit /r Chicken Rice` | | List recipe | `list [/t] [KEYWORD]`
e.g `list pizza` | | View recipe | `view INDEX`
e.g `view 1` | | Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | @@ -387,5 +402,5 @@ Format : `view_ingredients` | View weekly plan | `weeklyplan` | | View weekly ingredients | `weeklyingredients` | | View user ingredients | `view_ingredients` | -| Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Rice /c 100 /d 04/09/2023` | -| Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Rice /c 50` | +| Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Chicken Rice /c 100 /d 04/09/2023` | +| Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Chicken Rice /c 50` | From 16cf25838878aa428c432ea51b0f2f6fc6c7a2de Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 13:42:28 +0800 Subject: [PATCH 212/252] Updated the HELP commands. --- src/main/java/seedu/meal360/Ui.java | 42 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 7ddada38c3..388a6943ae 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -109,28 +109,34 @@ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, Stri public void printHelp() { printMessage("These are the operations you can do. Please follow the proper input" + " formats while typing."); - printMessage("1. Add Recipe: add /r {recipe name}"); - printMessage("2. View Recipe: view {index number}"); - printMessage("3. Edit Recipe: edit {recipe name}"); - printMessage("4. Delete Recipe: delete {index number} or delete {starting index-ending index} or"); - printMessage("delete /r {recipe name} or delete /r all"); + printMessage("1. Add Recipe: add /r {RECIPE_NAME}"); + printMessage("2. Edit Recipe: edit /r {RECIPE_NAME}"); + printMessage("3. View Recipe: view {RECIPE_INDEX}"); + printMessage("4. Delete Recipe: delete {RECIPE_INDEX} or delete {START_INDEX-END_INDEX} or"); + printMessage(" delete /r {RECIPE_INDEX} or delete /r all"); printMessage("5. List All Recipes: list"); - printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); - printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); - printMessage(" /r {recipe2 name} /q {quantity2}"); - printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); - printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); - printMessage(" /q {quantity1} /r {recipe2 name} /q {quantity2}"); + printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {RECIPE_NAME} {QUANTITY}"); + printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {RECIPE1_NAME} /q {QUANTITY1}"); + printMessage(" /r {RECIPE2_NAME} /q {QUANTITY2}"); + printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {RECIPE_NAME} {QUANTITY}"); + printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {RECIPE1_NAME}"); + printMessage(" /q {QUANTITY1} /r {RECIPE2_NAME} /q {QUANTITY2}"); printMessage("10. View Weekly Plan: weeklyplan"); - printMessage("11. Marking recipe in weekly plan as done: weekly /done RECIPE_NAME"); - printMessage("12. Clearing weekly plan: weekly /clear"); + printMessage("11. Marking recipe in weekly plan as done: weekly /done {RECIPE_NAME}"); + printMessage("12. Clear weekly plan: weekly /clear"); printMessage("13. View Weekly Ingredients: weeklyingredients"); printMessage("14. Give a random recipe: random"); - printMessage("15. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && " - + "...}"); - printMessage("16. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ." - + "..}"); - printMessage("17. Exit: bye"); + printMessage("15. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && ...}"); + printMessage("16. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ...}"); + printMessage("17. Add User Ingredient: add_i /n {INGREDIENT_NAME} /c {QUANTITY} /d {DATE}"); + printMessage("18. Delete User Ingredient: del_i /n {INGREDIENT_NAME} /c {QUANTITY}"); + printMessage("18. View User Ingredients: view_ingredients"); + printMessage("19. Exit Recipe Manager: bye"); + printMessage(" "); + printMessage("NOTE:"); + printMessage("*Curly brackets {} are just to indicate what goes inside the command!"); + printMessage("*No need to type them while entering commands!"); + printSeparator(); printMessage("HOW TO ADD INGREDIENTS?"); printMessage("ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ..."); } From 61f182b04f3a2bc48219c606d9eb1d9ba558901f Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 14:16:38 +0800 Subject: [PATCH 213/252] Updated my PPP. --- docs/team/topgun2001.md | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/docs/team/topgun2001.md b/docs/team/topgun2001.md index 3656aa6950..6c0ce4cef3 100644 --- a/docs/team/topgun2001.md +++ b/docs/team/topgun2001.md @@ -25,26 +25,47 @@ Given below are my contributions to the project: ([#51](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/51)) -* __Contributions to User Guide__ ([#69](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/69)): - * Added documentation for the following: - * HOW TO ADD INGREDIENTS TO A RECIPE? - * `add` - * `edit` - * `help` +* __Contributions to User Guide__ ([#69](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/69), + [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139)): + * Added anchor links for quick jump to respective tabs. + * Added documentation for the following: + * HOW TO ADD INGREDIENTS TO A RECIPE? + * `add` + * `edit` + * `help` -* __Contribtions to Developer Guide__ ([#54](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/54)): - * Added documentation for the following: +* __Contributions to Developer Guide__ ([#54](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/54), + [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139)): + * Added anchor links for quick jump to respective tabs. + * Added documentation for the following classes: + * `Parser` + * Added documentation for the following: * `Add Recipes` feature * `Edit Recipes` feature * `edit` * `help` +* __Pull Requests reviewed for Team Project:__ + * Gave comments on code quality and code suggestions. + * ([#15](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/15)), + ([#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20)), + ([#23](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/23)), + ([#29](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/29)), + ([#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30)), + ([#31](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/31)), + ([#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48)), + ([#47](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/47)), + ([#56](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/56)), + ([#127](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/127), + ([#129](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/129)) + + * __Community__: * Reported bugs and suggestions for other teams during Practical Dry-Run.([I](https://github.com/TopGun2001/ped/issues)) * Bugs: ([#1](https://github.com/TopGun2001/ped/issues/1)),([#2](https://github.com/TopGun2001/ped/issues/2)), ([#3](https://github.com/TopGun2001/ped/issues/3)),([#5](https://github.com/TopGun2001/ped/issues/5)), ([#7](https://github.com/TopGun2001/ped/issues/7)) * Suggestions: ([#4](https://github.com/TopGun2001/ped/issues/4)),([#6](https://github.com/TopGun2001/ped/issues/6)), - ([#10](https://github.com/TopGun2001/ped/issues/10)) \ No newline at end of file + ([#10](https://github.com/TopGun2001/ped/issues/10)) From 52b4a1c0e5d30117013ff9d6c59acd73d6078072 Mon Sep 17 00:00:00 2001 From: jaredoong <88092096+jaredoong@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:20:01 +0800 Subject: [PATCH 214/252] Update UserGuide.md Add explanation that current session saved only when program exits properly --- docs/UserGuide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 20e1319343..3035ad020f 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -21,6 +21,8 @@ ___ `tp.jar` file. This folder will contain all the data files that the app will use. Please do not touch these files to ensure smooth operation of the app. 4. To allow for immediate testing of features, the app comes preloaded with 10 recipes. +5. Take note that changes to the ingredient list, recipe list, and weekly meal plan would be saved + only when exiting the program properly using `bye` command. ___ From 675fcfd370024240b1079942e9863ddd686d59e7 Mon Sep 17 00:00:00 2001 From: jaredoong <88092096+jaredoong@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:23:23 +0800 Subject: [PATCH 215/252] Update UserGuide.md Add exiting of program to command summary --- docs/UserGuide.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3035ad020f..2f07d55cf4 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -395,3 +395,4 @@ Format : `view_ingredients` | View user ingredients | `view_ingredients` | | Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Rice /c 100 /d 04/09/2023` | | Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Rice /c 50` | +| Exit the program | `bye` | From a0c0e0d1e2ffba0f37f9e2cc1e3e03d9825f5308 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 14:29:04 +0800 Subject: [PATCH 216/252] Added documentation for methods. --- src/main/java/seedu/meal360/Parser.java | 41 +++++++++++++++++++++++++ src/main/java/seedu/meal360/Ui.java | 9 ++++++ 2 files changed, 50 insertions(+) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index faaf398a79..11806ccf4e 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -23,6 +23,17 @@ public class Parser { String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly " + "[eg:chicken=100] and \"done\" when finished entering ingredients!"; + + /** + * This method is designed to combine multiples words together to + * form 1 single sentence or word. It is helpful in combining words + * as our application trims the user input in 1 line using white space + * characters. + * + * @author AbijithRam + * @param input, startIndex, length + * @return String + */ public String combineWords(String[] input, int startIndex, int length) { StringBuilder word = new StringBuilder(input[startIndex].trim()); for (int i = startIndex + 1; i < length; i++) { @@ -94,6 +105,15 @@ public HashMap parseIngredientName(String[] commands) { return ingredients; } + + /** + * This method is designed to take in input from the user and + * add the recipe to the user's recipe manager. + * + * @author AbijithRam + * @param input, recipeList + * @return Recipe + */ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); @@ -144,6 +164,19 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { return newRecipe; } + /** + * This method is designed to take in input from the user and + * edit the recipes accordingly. + * + * There are 3 types of edit to a recipe: + * 1. Edit the ingredient list fully. + * 2. Edit the ingredient list partially.(1 ingredient edit at one time) + * 3. Edit the ingredient list by adding new ingredients. + * + * @author AbijithRam + * @param input, recipeList + * @return Recipe + */ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); @@ -599,6 +632,14 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { return requestedRecipe; } + /** + * This method is designed to find the index of a recipe from + * the recipe list of the user. + * + * @author AbijithRam + * @param recipeName, recipeList + * @return Recipe + */ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { int recipeIndex = 1; for (Recipe recipe : recipes) { diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 388a6943ae..de4c597897 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -106,6 +106,15 @@ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, Stri } } + /** + * This method is designed to display all the commands used in the Recipe Manager + * to assist the user in entering the correct commands. + * + * It also displays the command format in which the input is required to be + * entered by the user. + * + * @author AbijithRam + */ public void printHelp() { printMessage("These are the operations you can do. Please follow the proper input" + " formats while typing."); From fe133546b72d9e01644ba3b9283502812957e3c9 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 14:44:56 +0800 Subject: [PATCH 217/252] Added documentation for a few methods. --- src/main/java/seedu/meal360/Meal360.java | 19 +++++++++++++++++++ src/main/java/seedu/meal360/Parser.java | 14 ++++++++++---- src/main/java/seedu/meal360/Recipe.java | 2 -- src/main/java/seedu/meal360/Ui.java | 8 ++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 9aa04b491a..5b22ee2f8c 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -26,6 +26,13 @@ public class Meal360 { private static IngredientList userIngredients = new IngredientList(); + /** + * This method is designed to execute once the program is started. + * + * It loads the saved data from the database from the previous time + * if it exists. + */ + public static void startApp() { ui.printSeparator(); ui.printWelcomeMessage(); @@ -66,6 +73,12 @@ public static void startApp() { ui.printSeparator(); } + /** + * This method is designed to receive the user input and execute + * the respective methods. + * + * @param input user input + */ public static void receiveInput(String input) { String[] command = parser.cleanUserInput(input); @@ -253,6 +266,12 @@ public static void receiveInput(String input) { } } + /** + * This method is designed to exit the program once the user keys-in + * the input `bye`. + * + * It saves the user data into the database. + */ public static void exitApp() { ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 11806ccf4e..0970f119b8 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -31,7 +31,10 @@ public class Parser { * characters. * * @author AbijithRam - * @param input, startIndex, length + * @param input user input + * @param startIndex index of string to start with + * @param length length of string + * * @return String */ public String combineWords(String[] input, int startIndex, int length) { @@ -111,7 +114,8 @@ public HashMap parseIngredientName(String[] commands) { * add the recipe to the user's recipe manager. * * @author AbijithRam - * @param input, recipeList + * @param input user input + * @param recipeList recipeList of user * @return Recipe */ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { @@ -174,7 +178,8 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { * 3. Edit the ingredient list by adding new ingredients. * * @author AbijithRam - * @param input, recipeList + * @param input user input + * @param recipeList recipeList of user * @return Recipe */ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { @@ -637,7 +642,8 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { * the recipe list of the user. * * @author AbijithRam - * @param recipeName, recipeList + * @param recipeName name of recipe + * @param recipes recipe list of user * @return Recipe */ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 8fd5a46c0d..18664311ea 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -8,8 +8,6 @@ public class Recipe { private static IngredientList ingredientList = new IngredientList(); public HashMap ingredients; private String name; - private Boolean available; - public Recipe(String name, HashMap ingredients) { this.name = name; diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index de4c597897..6ccf6bd048 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -31,6 +31,13 @@ public void printMessage(String message) { System.out.println(outputMessage); } + /** + * This method is designed to print the contents of a recipe + * such as the name of the recipe and the ingredients of + * the recipe + * + * @param recipe the recipe that needs to be printed + */ public void printRecipe(Recipe recipe) { System.out.println(formatMessage("Name of recipe: " + recipe.getName())); int index = 1; @@ -114,6 +121,7 @@ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, Stri * entered by the user. * * @author AbijithRam + * @author Jaredoong */ public void printHelp() { printMessage("These are the operations you can do. Please follow the proper input" From 32a274c54cc975821f539d1c686380c302780475 Mon Sep 17 00:00:00 2001 From: Abijith Ram <88262428+TopGun2001@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:52:40 +0800 Subject: [PATCH 218/252] =?UTF-8?q?Revert=20"Added=20UML=20diagrams=20for?= =?UTF-8?q?=20add=20and=20edit=20functions.=20Updated=20User=20guide.=20Up?= =?UTF-8?q?=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Parser.puml | 24 +++++++ docs/DeveloperGuide.md | 6 -- .../Implementation/AddRecipe/addRecipe.png | Bin 15566 -> 0 bytes .../Implementation/EditRecipe/editRecipe.png | Bin 15494 -> 0 bytes docs/UML/Parser/ParserClassDiagram.png | Bin 47184 -> 0 bytes docs/UserGuide.md | 61 +++++++----------- docs/team/topgun2001.md | 39 +++-------- src/main/java/seedu/meal360/Meal360.java | 19 ------ src/main/java/seedu/meal360/Parser.java | 47 -------------- src/main/java/seedu/meal360/Recipe.java | 2 + src/main/java/seedu/meal360/Ui.java | 59 ++++++----------- 11 files changed, 78 insertions(+), 179 deletions(-) create mode 100644 Parser.puml delete mode 100644 docs/UML/Implementation/AddRecipe/addRecipe.png delete mode 100644 docs/UML/Implementation/EditRecipe/editRecipe.png delete mode 100644 docs/UML/Parser/ParserClassDiagram.png diff --git a/Parser.puml b/Parser.puml new file mode 100644 index 0000000000..04698e5967 --- /dev/null +++ b/Parser.puml @@ -0,0 +1,24 @@ +@startuml +class seedu.meal360.Parser { +~ Ui ui ++ String combineWords(String[],int,int) ++ HashMap parseIngredientName(String[]) ++ Recipe parseAddRecipe(String[],RecipeList) ++ Recipe parseEditRecipe(String[],RecipeList) ++ String parseDeleteRecipe(String[],RecipeList) ++ String parseTagRecipe(String[],RecipeList) ++ String parseAddRecipeTag(String,RecipeList) ++ String parseRemoveRecipeTag(String,RecipeList) ++ RecipeList parseListRecipe(String[],RecipeList) ++ Recipe parseViewRecipe(String[],RecipeList) ++ Recipe parseViewRecipe(String,RecipeList) ++ Recipe parseRandomRecipe(RecipeList) ++ WeeklyPlan parseWeeklyPlan(String[],RecipeList) +- WeeklyPlan parseEditSingleWeeklyPlan(String[],RecipeList) +- WeeklyPlan parseEditMultiWeeklyPlan(String[],RecipeList) +- StringBuilder getRecipeNames(String[],ArrayList,StringBuilder,int,int) ++ LocalDate parseDate(String) ++ void parseAddUserIngredients(String[],IngredientList) ++ void parseDeleteUserIngredients(String[],IngredientList) +} +@enduml \ No newline at end of file diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 2e52587898..0c6e1e6306 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -134,11 +134,9 @@ when the user inputs `list`. API: `Parser.java` The `Parser` component: -![](./UML/Parser/ParserClassDiagram.png) - receives the user input from the `Meal360` component - checks and filters input string -- executes the appropriate methods in Parser class; eg:parseAddRecipe, parseEditRecipe, etc. - catches `exceptions` and throws error messages via `UI` to 1. prompts user to enter valid input 2. prevent `Meal360` from crashing upon invalid input @@ -376,8 +374,6 @@ It is implemented through the following steps: to `recipeList.addRecipe()` to store the new recipe data. -![](./UML/Implementation/AddRecipe/addRecipe.png) - ### Edit Recipes Feature The current implementation: @@ -399,8 +395,6 @@ It is implemented through the following steps: to `recipeList.editRecipe()` to update the new recipe data. -![](./UML/Implementation/EditRecipe/editRecipe.png) - ### Random a Recipe Feature - randomly pick a recipe and display to the user diff --git a/docs/UML/Implementation/AddRecipe/addRecipe.png b/docs/UML/Implementation/AddRecipe/addRecipe.png deleted file mode 100644 index 0ac286033ca5c809c96aa6079084f6cdcfefb300..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15566 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

Rjy9uX=!EXiTOf9J-kiRuJEmHl|g!1?} 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 Wv9VtZh0u1=7@)OJu29B2;C}&oVcUBE diff --git a/docs/UML/Parser/ParserClassDiagram.png b/docs/UML/Parser/ParserClassDiagram.png deleted file mode 100644 index cdd0ad69e988bfcd003f88b91235922b749ea4e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47184 zcmce;WmJ@5+cgX*iXak7DIwh{AuT1{-Q6iEjUdv3z<@}X)X?229n#GZk^>Aqz%a}= zp!ah>Ki;*zAMg6U)8&He0_Qrev-Yv~u}>pZl%%mSUt*%5pkT|&NUEWrJRm?pLH&vG z2zdu{spt~<1=USWS{$Wplynz)@z7dKQ49s8G8XH`6dif}#6?Ee4F%;{_uXIAKIcLU z6qNc+SxGUCk46V@MH>T1^7a#QY~eWU)}7!zanuVc{E_v{=*U46!e^b%-@bj!;z|)^ zKqDc|d1Sz5r}~puZn`77ORqoM=xnF_7f10(9{BMahNq%d$Wk!>M%sJGLS??!Kwkwc)UOJI9A>||-173emK{G;VWjE0OB z*@F15Ky!!(e=j-=-WC1*4u$2jSD>D*?)dY6*Bmh%kyL6-U0DCFiu}|L$KdD%6qKVFD!E_1 zw-9w0qDir~-CUVT+x-|JlD~p@H+7@EJr$^0yN!x`yUn;6vb)$i_##!Aez;%fD<4Q- z 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 @@ -135,7 +126,6 @@ Format: `view INDEX` Example of usage: `view 1` -`view 8`
@@ -198,7 +188,7 @@ Example of usage:
-### Add single recipe to weekly plan: `weekly /add` +### Adding single recipe this week's plan: `weekly /add` Adds an existing recipe to this week's plan. @@ -217,7 +207,7 @@ Example of usage:
-### Add multiple recipes to weekly plan: `weekly /multiadd` +### Adding multiple recipes to this week's plan: `weekly /multiadd` Adds multiple existing recipe to this week's plan. @@ -239,7 +229,7 @@ Example of usage:
-### Delete single recipe from weekly plan: `weekly /delete` +### Deleting from this week's plan: `weekly /delete` Deletes an existing recipe from this week's plan. @@ -258,7 +248,7 @@ Example of usage:
-### Delete multiple recipes from weekly plan: `weekly /multidelete` +### Deleting multiple recipes from this week's plan: `weekly /multidelete` Deletes multiple existing recipe from this week's plan. @@ -283,7 +273,7 @@ Example of usage:
-### Clear weekly plan: `weekly /clear` +### Clearing this week's plan: `weekly /clear` Clears this week's plan by removing all recipes listed in weekly plan. @@ -291,7 +281,7 @@ Format: `weekly /clear`
-### Mark recipe in weekly plan as done: `weekly /done` +### Mark recipe in this week's plan as done: `weekly /done` Mark a recipe in the weekly plan as completed. A single count of the recipe and its corresponding ingredients will be removed from the weekly plan and the list of ingredients. @@ -309,7 +299,7 @@ Example of usage:
-### View weekly plan: `weeklyplan` +### View this week's plan: `weeklyplan` View this week's plan. @@ -317,7 +307,7 @@ Format: `weeklyplan`
-### View weekly plan ingredients: `weeklyingredients` +### View this week's ingredients: `weeklyingredients` View this week's ingredients. @@ -336,8 +326,7 @@ Format: `random` ### Exit the program: `bye` -* Exits the program. -* If any ingredients are added by the user, they get saved in JSON files for usage the next time. +Exits the program. Format: `bye` @@ -386,10 +375,10 @@ Format : `view_ingredients` ## Command Summary -| Action | Format & Examples | +| Action | Format, Examples | |------------------------------------|-------------------------------------------------------------------------------------------------------------| -| Add recipe | `add /r [RECIPE_NAME]`
e.g `add /r Chicken Rice` | -| Edit recipe | `edit /r [RECIPE_NAME]`
e.g `edit /r Chicken Rice` | +| Add recipe | `add /r [RECIPE_NAME]`
e.g `add /r chicken rice` | +| Edit recipe | `edit /r [RECIPE_NAME]`
e.g `edit /r chicken rice` | | List recipe | `list [/t] [KEYWORD]`
e.g `list pizza` | | View recipe | `view INDEX`
e.g `view 1` | | Add tag/Categorise to recipes | `tag LABEL << RECIPE_NAME`
e.g `tag western << pizza` | @@ -404,6 +393,6 @@ Format : `view_ingredients` | View weekly plan | `weeklyplan` | | View weekly ingredients | `weeklyingredients` | | View user ingredients | `view_ingredients` | -| Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Chicken Rice /c 100 /d 04/09/2023` | -| Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Chicken Rice /c 50` | +| Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Rice /c 100 /d 04/09/2023` | +| Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Rice /c 50` | | Exit the program | `bye` | diff --git a/docs/team/topgun2001.md b/docs/team/topgun2001.md index 6c0ce4cef3..3656aa6950 100644 --- a/docs/team/topgun2001.md +++ b/docs/team/topgun2001.md @@ -25,47 +25,26 @@ Given below are my contributions to the project: ([#51](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/51)) -* __Contributions to User Guide__ ([#69](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/69), - [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139)): - * Added anchor links for quick jump to respective tabs. - * Added documentation for the following: - * HOW TO ADD INGREDIENTS TO A RECIPE? - * `add` - * `edit` - * `help` +* __Contributions to User Guide__ ([#69](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/69)): + * Added documentation for the following: + * HOW TO ADD INGREDIENTS TO A RECIPE? + * `add` + * `edit` + * `help` -* __Contributions to Developer Guide__ ([#54](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/54), - [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139)): - * Added anchor links for quick jump to respective tabs. - * Added documentation for the following classes: - * `Parser` - * Added documentation for the following: +* __Contribtions to Developer Guide__ ([#54](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/54)): + * Added documentation for the following: * `Add Recipes` feature * `Edit Recipes` feature * `edit` * `help` -* __Pull Requests reviewed for Team Project:__ - * Gave comments on code quality and code suggestions. - * ([#15](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/15)), - ([#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20)), - ([#23](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/23)), - ([#29](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/29)), - ([#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30)), - ([#31](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/31)), - ([#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48)), - ([#47](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/47)), - ([#56](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/56)), - ([#127](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/127), - ([#129](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/129)) - - * __Community__: * Reported bugs and suggestions for other teams during Practical Dry-Run.([I](https://github.com/TopGun2001/ped/issues)) * Bugs: ([#1](https://github.com/TopGun2001/ped/issues/1)),([#2](https://github.com/TopGun2001/ped/issues/2)), ([#3](https://github.com/TopGun2001/ped/issues/3)),([#5](https://github.com/TopGun2001/ped/issues/5)), ([#7](https://github.com/TopGun2001/ped/issues/7)) * Suggestions: ([#4](https://github.com/TopGun2001/ped/issues/4)),([#6](https://github.com/TopGun2001/ped/issues/6)), - ([#10](https://github.com/TopGun2001/ped/issues/10)) + ([#10](https://github.com/TopGun2001/ped/issues/10)) \ No newline at end of file diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 5b22ee2f8c..9aa04b491a 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -26,13 +26,6 @@ public class Meal360 { private static IngredientList userIngredients = new IngredientList(); - /** - * This method is designed to execute once the program is started. - * - * It loads the saved data from the database from the previous time - * if it exists. - */ - public static void startApp() { ui.printSeparator(); ui.printWelcomeMessage(); @@ -73,12 +66,6 @@ public static void startApp() { ui.printSeparator(); } - /** - * This method is designed to receive the user input and execute - * the respective methods. - * - * @param input user input - */ public static void receiveInput(String input) { String[] command = parser.cleanUserInput(input); @@ -266,12 +253,6 @@ public static void receiveInput(String input) { } } - /** - * This method is designed to exit the program once the user keys-in - * the input `bye`. - * - * It saves the user data into the database. - */ public static void exitApp() { ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 0970f119b8..faaf398a79 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -23,20 +23,6 @@ public class Parser { String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly " + "[eg:chicken=100] and \"done\" when finished entering ingredients!"; - - /** - * This method is designed to combine multiples words together to - * form 1 single sentence or word. It is helpful in combining words - * as our application trims the user input in 1 line using white space - * characters. - * - * @author AbijithRam - * @param input user input - * @param startIndex index of string to start with - * @param length length of string - * - * @return String - */ public String combineWords(String[] input, int startIndex, int length) { StringBuilder word = new StringBuilder(input[startIndex].trim()); for (int i = startIndex + 1; i < length; i++) { @@ -108,16 +94,6 @@ public HashMap parseIngredientName(String[] commands) { return ingredients; } - - /** - * This method is designed to take in input from the user and - * add the recipe to the user's recipe manager. - * - * @author AbijithRam - * @param input user input - * @param recipeList recipeList of user - * @return Recipe - */ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); @@ -168,20 +144,6 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { return newRecipe; } - /** - * This method is designed to take in input from the user and - * edit the recipes accordingly. - * - * There are 3 types of edit to a recipe: - * 1. Edit the ingredient list fully. - * 2. Edit the ingredient list partially.(1 ingredient edit at one time) - * 3. Edit the ingredient list by adding new ingredients. - * - * @author AbijithRam - * @param input user input - * @param recipeList recipeList of user - * @return Recipe - */ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); @@ -637,15 +599,6 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { return requestedRecipe; } - /** - * This method is designed to find the index of a recipe from - * the recipe list of the user. - * - * @author AbijithRam - * @param recipeName name of recipe - * @param recipes recipe list of user - * @return Recipe - */ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { int recipeIndex = 1; for (Recipe recipe : recipes) { diff --git a/src/main/java/seedu/meal360/Recipe.java b/src/main/java/seedu/meal360/Recipe.java index 18664311ea..8fd5a46c0d 100644 --- a/src/main/java/seedu/meal360/Recipe.java +++ b/src/main/java/seedu/meal360/Recipe.java @@ -8,6 +8,8 @@ public class Recipe { private static IngredientList ingredientList = new IngredientList(); public HashMap ingredients; private String name; + private Boolean available; + public Recipe(String name, HashMap ingredients) { this.name = name; diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 6ccf6bd048..7ddada38c3 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -31,13 +31,6 @@ public void printMessage(String message) { System.out.println(outputMessage); } - /** - * This method is designed to print the contents of a recipe - * such as the name of the recipe and the ingredients of - * the recipe - * - * @param recipe the recipe that needs to be printed - */ public void printRecipe(Recipe recipe) { System.out.println(formatMessage("Name of recipe: " + recipe.getName())); int index = 1; @@ -113,47 +106,31 @@ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, Stri } } - /** - * This method is designed to display all the commands used in the Recipe Manager - * to assist the user in entering the correct commands. - * - * It also displays the command format in which the input is required to be - * entered by the user. - * - * @author AbijithRam - * @author Jaredoong - */ public void printHelp() { printMessage("These are the operations you can do. Please follow the proper input" + " formats while typing."); - printMessage("1. Add Recipe: add /r {RECIPE_NAME}"); - printMessage("2. Edit Recipe: edit /r {RECIPE_NAME}"); - printMessage("3. View Recipe: view {RECIPE_INDEX}"); - printMessage("4. Delete Recipe: delete {RECIPE_INDEX} or delete {START_INDEX-END_INDEX} or"); - printMessage(" delete /r {RECIPE_INDEX} or delete /r all"); + printMessage("1. Add Recipe: add /r {recipe name}"); + printMessage("2. View Recipe: view {index number}"); + printMessage("3. Edit Recipe: edit {recipe name}"); + printMessage("4. Delete Recipe: delete {index number} or delete {starting index-ending index} or"); + printMessage("delete /r {recipe name} or delete /r all"); printMessage("5. List All Recipes: list"); - printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {RECIPE_NAME} {QUANTITY}"); - printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {RECIPE1_NAME} /q {QUANTITY1}"); - printMessage(" /r {RECIPE2_NAME} /q {QUANTITY2}"); - printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {RECIPE_NAME} {QUANTITY}"); - printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {RECIPE1_NAME}"); - printMessage(" /q {QUANTITY1} /r {RECIPE2_NAME} /q {QUANTITY2}"); + printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); + printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); + printMessage(" /r {recipe2 name} /q {quantity2}"); + printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); + printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); + printMessage(" /q {quantity1} /r {recipe2 name} /q {quantity2}"); printMessage("10. View Weekly Plan: weeklyplan"); - printMessage("11. Marking recipe in weekly plan as done: weekly /done {RECIPE_NAME}"); - printMessage("12. Clear weekly plan: weekly /clear"); + printMessage("11. Marking recipe in weekly plan as done: weekly /done RECIPE_NAME"); + printMessage("12. Clearing weekly plan: weekly /clear"); printMessage("13. View Weekly Ingredients: weeklyingredients"); printMessage("14. Give a random recipe: random"); - printMessage("15. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && ...}"); - printMessage("16. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ...}"); - printMessage("17. Add User Ingredient: add_i /n {INGREDIENT_NAME} /c {QUANTITY} /d {DATE}"); - printMessage("18. Delete User Ingredient: del_i /n {INGREDIENT_NAME} /c {QUANTITY}"); - printMessage("18. View User Ingredients: view_ingredients"); - printMessage("19. Exit Recipe Manager: bye"); - printMessage(" "); - printMessage("NOTE:"); - printMessage("*Curly brackets {} are just to indicate what goes inside the command!"); - printMessage("*No need to type them while entering commands!"); - printSeparator(); + printMessage("15. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && " + + "...}"); + printMessage("16. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ." + + "..}"); + printMessage("17. Exit: bye"); printMessage("HOW TO ADD INGREDIENTS?"); printMessage("ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ..."); } From 1c6446bb9fc3bda9d04de4998e2a33fd40966daf Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 14:58:07 +0800 Subject: [PATCH 219/252] Updated user guide. --- docs/UserGuide.md | 34 ++++++++++++------------- gradlew | 0 src/main/resources/META-INF/MANIFEST.MF | 3 --- text-ui-test/runtest.sh | 0 4 files changed, 17 insertions(+), 20 deletions(-) mode change 100755 => 100644 gradlew delete mode 100644 src/main/resources/META-INF/MANIFEST.MF mode change 100755 => 100644 text-ui-test/runtest.sh diff --git a/docs/UserGuide.md b/docs/UserGuide.md index ee1a1f8435..5475919e4a 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -28,25 +28,25 @@ ___ ## Features -* [Add recipes](#adding-recipes--add) -* [Edit recipes](#editing-recipes--edit) +* [Add Recipes](#adding-recipes--add) +* [Edit Recipes](#editing-recipes--edit) * [Delete Recipes](#deleting-recipes--delete) * [View recipes](#viewing-recipes--view) -* [List relevant recipes](#listing-recipes--list) -* [Tag/Categorise recipes](#taggingcategorising-recipes--tag) -* [Add single recipe to weekly plan](#add-single-recipe-to-weekly-plan--weekly-add) -* [Add multiple recipe to weekly plan](#add-multiple-recipes-to-weekly-plan--weekly-multiadd) -* [Remove single recipe from weekly plan](#delete-single-recipe-from-weekly-plan--weekly-delete) -* [Remove multiple recipe from weekly plan](#delete-multiple-recipes-from-weekly-plan--weekly-multidelete) -* [Clear weekly plan](#clear-weekly-plan--weekly-clear) -* [Mark recipe in weekly plan as done](#mark-recipe-in-weekly-plan-as-done--weekly-done) -* [View weekly plan ingredients](#view-weekly-plan-ingredients--weeklyingredients) -* [View user ingredients](#view-user-ingredients--viewingredients) -* [View weekly plan](#view-weekly-plan--weeklyplan) -* [Random a recipe](#random-a-recipe--random) -* [Exit program](#exit-the-program--bye) -* [Add user ingredient](#add-user-ingredient--addi) -* [Delete user ingredient](#delete-user-ingredient--deli) +* [List Relevant Recipes](#listing-recipes--list) +* [Tag/Categorise Recipes](#taggingcategorising-recipes--tag) +* [Add Single Recipe To Weekly Plan](#add-single-recipe-to-weekly-plan--weekly-add) +* [Add Multiple Recipe To Weekly Plan](#add-multiple-recipes-to-weekly-plan--weekly-multiadd) +* [Remove Single Recipe From Weekly Plan](#delete-single-recipe-from-weekly-plan--weekly-delete) +* [Remove Multiple Recipe From Weekly Plan](#delete-multiple-recipes-from-weekly-plan--weekly-multidelete) +* [Clear Weekly Plan](#clear-weekly-plan--weekly-clear) +* [Mark Recipe In Weekly Plan As Done](#mark-recipe-in-weekly-plan-as-done--weekly-done) +* [View Weekly Plan Ingredients](#view-weekly-plan-ingredients--weeklyingredients) +* [View User Ingredients](#view-user-ingredients--viewingredients) +* [View Weekly Plan](#view-weekly-plan--weeklyplan) +* [Random A Recipe](#random-a-recipe--random) +* [Exit Program](#exit-the-program--bye) +* [Add User Ingredient](#add-user-ingredient--addi) +* [Delete User Ingredient](#delete-user-ingredient--deli) ### HOW TO ADD INGREDIENTS TO A RECIPE: diff --git a/gradlew b/gradlew old mode 100755 new mode 100644 diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF deleted file mode 100644 index d54b3b8812..0000000000 --- a/src/main/resources/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: seedu.meal360.Meal360 - diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh old mode 100755 new mode 100644 From edcb0ab43770dc816d1905a3a88f1627c5c9bb19 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 15:20:11 +0800 Subject: [PATCH 220/252] FINAL CHANGES. --- docs/UserGuide.md | 4 +--- gradlew | 0 src/main/java/seedu/meal360/Parser.java | 2 +- src/main/resources/META-INF/MANIFEST.MF | 3 +++ text-ui-test/runtest.sh | 0 5 files changed, 5 insertions(+), 4 deletions(-) mode change 100644 => 100755 gradlew create mode 100644 src/main/resources/META-INF/MANIFEST.MF mode change 100644 => 100755 text-ui-test/runtest.sh diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 5475919e4a..97a76c3fe7 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -58,9 +58,7 @@ Format: `ingredient1_name=ingredient1_quantity and ingredient2_name=ingredient2_ * After the ingredients are key-in in, please type `done` in the next line to finish the process. * **exception:** for editing ingredients partially, you just have to key in the 1 new ingredient and the recipe manager knows that you have entered 1 ingredient. No need to type `done`. - - - +
### Adding recipes: `add` diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 0970f119b8..44db43ad53 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -639,7 +639,7 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { /** * This method is designed to find the index of a recipe from - * the recipe list of the user. + * the recipe list of the user and return the recipe.git * * @author AbijithRam * @param recipeName name of recipe diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..d54b3b8812 --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: seedu.meal360.Meal360 + diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh old mode 100644 new mode 100755 From 7af427a3e45df563f9c7929ce681190a9b525274 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 15:25:37 +0800 Subject: [PATCH 221/252] Last Changes to UG. --- docs/UserGuide.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 8018316362..bae76132c0 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -56,20 +56,10 @@ ___ Format: `ingredient1_name=ingredient1_quantity and ingredient2_name=ingredient2_quantity ...` * Type the ingredient name followed by equal sign and quantity in positive integer values. -<<<<<<< HEAD * After the ingredients are key-in in, please type `done` in the next line to finish the process. * **exception:** for editing ingredients partially, you just have to key in the 1 new ingredient and the recipe manager knows that you have entered 1 ingredient. No need to type `done`. - -======= -* Type done when finished inputting all ingredients for the recipe. -* Example: -``` -chicken=100 and oil and sauce=200 and vegetables=300 -done -``` - ->>>>>>> 41947e5123afe06974a9d3a6735e1aafc5cd1967 +
### Adding recipes: `add` From e8319b2c29c922bb529dda227a1c9cbb881b8b02 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 15:30:56 +0800 Subject: [PATCH 222/252] Last Changes made to UG. --- docs/UserGuide.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index bae76132c0..4ee139b725 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -196,7 +196,7 @@ Example of usage:
-### Adding single recipe this week's plan: `weekly /add` +### Add single recipe to weekly plan: `weekly /add` Adds an existing recipe to this week's plan. @@ -215,7 +215,7 @@ Example of usage:
-### Adding multiple recipes to this week's plan: `weekly /multiadd` +### Add multiple recipes to weekly plan: `weekly /multiadd` Adds multiple existing recipe to this week's plan. @@ -237,7 +237,7 @@ Example of usage:
-### Deleting from this week's plan: `weekly /delete` +### Delete single recipe from weekly plan: `weekly /delete` Deletes an existing recipe from this week's plan. @@ -256,7 +256,7 @@ Example of usage:
-### Deleting multiple recipes from this week's plan: `weekly /multidelete` +### Delete multiple recipes from weekly plan: `weekly /multidelete` Deletes multiple existing recipe from this week's plan. @@ -281,7 +281,7 @@ Example of usage:
-### Clearing this week's plan: `weekly /clear` +### Clear weekly plan: `weekly /clear` Clears this week's plan by removing all recipes listed in weekly plan. @@ -289,7 +289,7 @@ Format: `weekly /clear`
-### Mark recipe in this week's plan as done: `weekly /done` +### Mark recipe in weekly plan as done: `weekly /done` Mark a recipe in the weekly plan as completed. A single count of the recipe and its corresponding ingredients will be removed from the weekly plan and the list of ingredients. @@ -307,7 +307,7 @@ Example of usage:
-### View this week's plan: `weeklyplan` +### View weekly plan: `weeklyplan` View this week's plan. @@ -315,7 +315,7 @@ Format: `weeklyplan`
-### View this week's ingredients: `weeklyingredients` +### View weekly plan ingredients: `weeklyingredients` View this week's ingredients. From b365518d6aa5293985d769b6a084f51992a2294d Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sun, 9 Apr 2023 15:51:12 +0800 Subject: [PATCH 223/252] update help function to include "available" function --- src/main/java/seedu/meal360/Meal360.java | 22 ++++++++++-------- src/main/java/seedu/meal360/Ui.java | 29 ++++++++++++------------ 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 9aa04b491a..f3730ff48b 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -79,14 +79,16 @@ public static void receiveInput(String input) { ui.printMessage(deletedRecipe); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = - "Please enter a valid recipe number or name in the correct format. You did not enter a recipe" + - " number or name. See 'help' for more details."; + String errorMessage = "Please enter a valid recipe number or name in the correct format. You did not " + + "enter a recipe" + + + " number or name. See 'help' for more details."; ui.printMessage(errorMessage); } catch (IndexOutOfBoundsException e) { String errorMessage = String.format( "Please enter a valid recipe number or name. You entered %s, " - + "which is in invalid.", command[1]); + + "which is in invalid.", + command[1]); ui.printMessage(errorMessage); } ui.printSeparator(); @@ -152,8 +154,8 @@ public static void receiveInput(String input) { ui.printSeparator(); String returnMessage = parser.parseTagRecipe(command, recipeList); ui.printTagMessage(returnMessage); - } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException | - RecipeNotFoundInTagException | TagNotFoundException | NoRecipeException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | NullPointerException + | RecipeNotFoundInTagException | TagNotFoundException | NoRecipeException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -198,8 +200,8 @@ public static void receiveInput(String input) { ui.printMessage("Please enter a valid command."); break; } - } catch (IllegalArgumentException | InvalidValueException | InvalidRecipeNameException | - ArrayIndexOutOfBoundsException | IngredientNotFoundException e) { + } catch (IllegalArgumentException | InvalidValueException | InvalidRecipeNameException + | ArrayIndexOutOfBoundsException | IngredientNotFoundException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); @@ -233,8 +235,8 @@ public static void receiveInput(String input) { Ingredient ingredientToDelete = parser.parseDeleteUserIngredients(command); userIngredients.deleteIngredient(ingredientToDelete); ui.printMessage("Ingredients successfully deleted!"); - } catch (IllegalArgumentException | IndexOutOfBoundsException | IngredientNotFoundException | - InvalidValueException e) { + } catch (IllegalArgumentException | IndexOutOfBoundsException | IngredientNotFoundException + | InvalidValueException e) { ui.printMessage(e.getMessage()); } ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 7ddada38c3..d49dff67da 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -88,8 +88,8 @@ public void listAvailableRecipes(RecipeList recipeListToPrint) { * @author notbingsu * @author junenita * @param recipeListToPrint list containing recipes to be printed - * @param emptyListMsg error message for empty list - * @param listHeaderMsg print list header message + * @param emptyListMsg error message for empty list + * @param listHeaderMsg print list header message */ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, String listHeaderMsg) { int numberOfRecipes = recipeListToPrint.size(); @@ -115,22 +115,23 @@ public void printHelp() { printMessage("4. Delete Recipe: delete {index number} or delete {starting index-ending index} or"); printMessage("delete /r {recipe name} or delete /r all"); printMessage("5. List All Recipes: list"); - printMessage("6. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); - printMessage("7. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); + printMessage("6. List Available Recipes: available"); + printMessage("7. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); + printMessage("8. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); printMessage(" /r {recipe2 name} /q {quantity2}"); - printMessage("8. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); - printMessage("9. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); + printMessage("9. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); + printMessage("10. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); printMessage(" /q {quantity1} /r {recipe2 name} /q {quantity2}"); - printMessage("10. View Weekly Plan: weeklyplan"); - printMessage("11. Marking recipe in weekly plan as done: weekly /done RECIPE_NAME"); - printMessage("12. Clearing weekly plan: weekly /clear"); - printMessage("13. View Weekly Ingredients: weeklyingredients"); - printMessage("14. Give a random recipe: random"); - printMessage("15. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && " + printMessage("11. View Weekly Plan: weeklyplan"); + printMessage("12. Marking recipe in weekly plan as done: weekly /done RECIPE_NAME"); + printMessage("13. Clearing weekly plan: weekly /clear"); + printMessage("14. View Weekly Ingredients: weeklyingredients"); + printMessage("15. Give a random recipe: random"); + printMessage("16. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && " + "...}"); - printMessage("16. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ." + printMessage("17. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ." + "..}"); - printMessage("17. Exit: bye"); + printMessage("18. Exit: bye"); printMessage("HOW TO ADD INGREDIENTS?"); printMessage("ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ..."); } From 7f970caed317f0e39629a32e76c8337862f19705 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 16:19:14 +0800 Subject: [PATCH 224/252] Added documentation and made changes to user guide. --- src/main/java/seedu/meal360/Meal360.java | 18 ++++++++++ src/main/java/seedu/meal360/Parser.java | 46 ++++++++++++++++++++++-- src/main/java/seedu/meal360/Ui.java | 13 +++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 9aa04b491a..6585e7b81b 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -26,6 +26,13 @@ public class Meal360 { private static IngredientList userIngredients = new IngredientList(); + + + /** + * This method is designed to execute when the application is started. + * It loads in the recipes, weekly plan and ingredients if they exist. + * + **/ public static void startApp() { ui.printSeparator(); ui.printWelcomeMessage(); @@ -66,6 +73,11 @@ public static void startApp() { ui.printSeparator(); } + /** + * This method is designed to receive the user input and perform the + * required tasks. + * + **/ public static void receiveInput(String input) { String[] command = parser.cleanUserInput(input); @@ -253,6 +265,12 @@ public static void receiveInput(String input) { } } + /** + * This method is designed to exit the application. + * + * It saves the recipes, weekly plan and ingredients if any entered by the user. + * + **/ public static void exitApp() { ui.printSeparator(); diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 6a8e888aa2..9e7ecbbaa5 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -23,6 +23,18 @@ public class Parser { String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly " + "[eg:chicken=100] and \"done\" when finished entering ingredients!"; + + /** + * This method is designed to combine multiple words into a single sentence + * after trimming the spaces. + * + * @author AbijithRam + * @param input the user input, + * @param startIndex index to start from + * @param length length of substring + * + * @return an array of strings representing the user input + */ public String combineWords(String[] input, int startIndex, int length) { StringBuilder word = new StringBuilder(input[startIndex].trim()); for (int i = startIndex + 1; i < length; i++) { @@ -94,6 +106,20 @@ public HashMap parseIngredientName(String[] commands) { return ingredients; } + + /** + * This method is designed to add in a recipe to the user's + * recipe list. + * + * The method will also check if a recipe already exists or not + * to prevent duplicate recipes. + * + * @author AbijithRam + * @param input the user input, + * @param recipeList the recipe list of the user containing all recipes + * + * @return Recipe the recipe that has been added + */ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); @@ -122,9 +148,10 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { String[] command = line.trim().split(" and "); ingredients = parseIngredientName(command); boolean ingredientsInCorrectFormat = true; - for (int i = 0; i < command.length; i++) { - if (!command[i].contains("=")) { + for (String s : command) { + if (!s.contains("=")) { ingredientsInCorrectFormat = false; + break; } } if (ingredients.size() == 0 || !ingredientsInCorrectFormat) { @@ -144,6 +171,21 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { return newRecipe; } + /** + * This method is designed to edit an already existing recipe + * to the user's recipe list. + * + * There are 3 types of editing operations: + * 1. Edit the ingredient list fully. + * 2. edit the ingredient list partially (1 recipe at a time). + * 3. Add new ingredients to the ingredient list. + * + * @author AbijithRam + * @param input the user input, + * @param recipeList the recipe list of the user containing all recipes + * + * @return Recipe the recipe that has been edited + */ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { int addedIngredient = 0; String recipeName = combineWords(input, 2, input.length); diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 7ddada38c3..f9a00e1f8f 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -31,6 +31,12 @@ public void printMessage(String message) { System.out.println(outputMessage); } + /** + * This method is designed to print the contents of a recipe. + * + * @param recipe recipe whose contents are to be printed. + * + **/ public void printRecipe(Recipe recipe) { System.out.println(formatMessage("Name of recipe: " + recipe.getName())); int index = 1; @@ -106,6 +112,13 @@ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, Stri } } + /** + * This method is designed to display all the commands used by the + * recipe manager to assist the user in executing the required + * operations. + * + * @author AbijithRam + */ public void printHelp() { printMessage("These are the operations you can do. Please follow the proper input" + " formats while typing."); From 70a1a7f1bf19a4e3737789baabc5f74d198eaf78 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 16:48:31 +0800 Subject: [PATCH 225/252] Updated DG, UG, PPP. --- docs/DeveloperGuide.md | 9 ++ .../Implementation/Add Recipe/AddRecipe.png | Bin 0 -> 15566 bytes .../Implementation/Edit Recipe/EditRecipe.png | Bin 0 -> 15494 bytes docs/UML/Parser/ParserClassDiagram.png | Bin 0 -> 47184 bytes docs/UserGuide.md | 81 ++++++++++-------- docs/team/topgun2001.md | 44 +++++++--- 6 files changed, 84 insertions(+), 50 deletions(-) create mode 100644 docs/UML/Implementation/Add Recipe/AddRecipe.png create mode 100644 docs/UML/Implementation/Edit Recipe/EditRecipe.png create mode 100644 docs/UML/Parser/ParserClassDiagram.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0c6e1e6306..9d77b5b6c8 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -135,6 +135,9 @@ API: `Parser.java` The `Parser` component: +![](./UML/Parser/ParserClassDiagram.png) + + - receives the user input from the `Meal360` component - checks and filters input string - catches `exceptions` and throws error messages via `UI` to @@ -374,6 +377,9 @@ It is implemented through the following steps: to `recipeList.addRecipe()` to store the new recipe data. +![](./UML/Implementation/Add Recipe/AddRecipe.png) + + ### Edit Recipes Feature The current implementation: @@ -395,6 +401,9 @@ It is implemented through the following steps: to `recipeList.editRecipe()` to update the new recipe data. +![](./UML/Implementation/Edit Recipe/EditRecipe.png) + + ### Random a Recipe Feature - randomly pick a recipe and display to the user diff --git a/docs/UML/Implementation/Add Recipe/AddRecipe.png b/docs/UML/Implementation/Add Recipe/AddRecipe.png new file mode 100644 index 0000000000000000000000000000000000000000..0ac286033ca5c809c96aa6079084f6cdcfefb300 GIT binary patch literal 15566 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

Rjy9uX=!EXiTOf9J-kiRuJEmHl|g!1?} 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 Wv9VtZh0u1=7@)OJu29B2;C}&oVcUBE literal 0 HcmV?d00001 diff --git a/docs/UML/Parser/ParserClassDiagram.png b/docs/UML/Parser/ParserClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..cdd0ad69e988bfcd003f88b91235922b749ea4e8 GIT binary patch literal 47184 zcmce;WmJ@5+cgX*iXak7DIwh{AuT1{-Q6iEjUdv3z<@}X)X?229n#GZk^>Aqz%a}= zp!ah>Ki;*zAMg6U)8&He0_Qrev-Yv~u}>pZl%%mSUt*%5pkT|&NUEWrJRm?pLH&vG z2zdu{spt~<1=USWS{$Wplynz)@z7dKQ49s8G8XH`6dif}#6?Ee4F%;{_uXIAKIcLU z6qNc+SxGUCk46V@MH>T1^7a#QY~eWU)}7!zanuVc{E_v{=*U46!e^b%-@bj!;z|)^ zKqDc|d1Sz5r}~puZn`77ORqoM=xnF_7f10(9{BMahNq%d$Wk!>M%sJGLS??!Kwkwc)UOJI9A>||-173emK{G;VWjE0OB z*@F15Ky!!(e=j-=-WC1*4u$2jSD>D*?)dY6*Bmh%kyL6-U0DCFiu}|L$KdD%6qKVFD!E_1 zw-9w0qDir~-CUVT+x-|JlD~p@H+7@EJr$^0yN!x`yUn;6vb)$i_##!Aez;%fD<4Q- z z02wU}SAin%X+`+z&6e|7^QQCdiIp<|vT^#QBz2ON5js7Ri5R;`JlZ__Ik0))UjqWP zH(s3vw)vcv5EbwtjM@>fR8e@Cd-XN@?ah|xj#nRO>1MNCr!_n9vf!dE%?laMrIif$ znGSL~208ygbrj`2l)1eG-EN;X2fEAT(wFayAyRou_x#(H%WoIkf1b{IM0PO;Y(saT z0qY3FSm1NWi`rVea?+b+&1(Xpvx|2Ay!J~k#P|xbpQRD8%-7(+X*z6l1R{2a{T6$? zH&Dv`7=&%R6YF*zdqaNB7buonew{@Le})VN#DX#P2pLD>(sE`%fq46Mkx~r8f4W(O z_NKH+3Vu;<{t|(+?S5-!Erm=e5QQ6>umFJ#8@j( zDkiW&ksYC$db@*Dd}cg|o%zf*f90DpKTr*d@RjmKgx%b~KJR~Dp9y{}3VVK?5Qs;L zNJEDQaulhAs~v>_5NWqcn^2pLOwZke_O_oO@9X%w%!OA!Rp6pzH-Tl z1n`l*XO4UU$pPnqhpPCRVpC+xI}|?#Bwk?pB3Ez_1d{=|%NH^o>ir0YF{1=G%K-u=|5MKB|`~Kt=;*#$Sg3wGTLx@UqUqY@H zK!*8`5Y8V-iiwfk7Vz+X<;8YvgC_KEK@{-oSR0L4MOBUmEBqUV(X#iyvaXiWsRNGT|cQeeFNnmGZxZU#5c!S_9q00&QAK?QDoo`!)sWFC_&pvu@*GK`sZ&wn#^NYAn3KZt}A42vo1 z_|Ln8gzi@LePiiak_&yLRz62frh=RSckR;jyM9q&ds}wuE8muk^^P+S1)>Xc-C}!1 z7-P^7$z1H;UkeKBENv3?5cy6J4UUDU06tCI#n>SFA9^v*P6;03l5yjP{2jlJ2kS|R zk(zcCnQCr<63e+ps!>fBa+2fEl$0-atTb{D`bI~J#TUWbliE^$KN`hra4_bQec&srpd0%Ms4KNie{K>()) z?B-$HkjG>%A3-SmcT~KpE!%aMir=5HJkL;WX9f!eMrz@7X~wUnbn~grra>QWyJ^2@ z`??!Eoin2xVODYNm)u0-2xtSXDnD2VaL{6|Ar(AS%V3}Vx}8nY{SjCOO0l+}-95q% z%+NXiJ7PEheZwMRAf(vR7ZQPy%1d3R(=5#rKa)Nbji)eB#!yHgB%dX;`1AHhWm0DK z(c$3$d;QY~#RvVq%aJmd>7f^Wi;^?q<&dYLr*E{V+m2e>YX%|~r)%jvL>ii6Z5lxN zy~-CQuY*0{!AhHrsmucTj>R^Dmxi}3yCKvBN2jByBBv#fjcI(ZzB$$lbq_{gY!hg* z3%X9k!ES>ILZz|o93v)hnNU3zHlT;Xy7?FE+dvcU#$gL|n-0tw0^>}UatWe^=IXp1^qzSDADnaRrA#j6rrV#4cO8^%STqVeH9z z&caL}T8mG_@WEfeM)FX9mIB5-XQwKWY5vKtK;E7I*`9fvNI(8j!YS48V{uq6(`;`J zn|8sO8f>zyTkQhQxn=m?RQ|fsMargiP}%Yu@Z(hG&pnR{dqBKE>%RZuGxPiCMPIrx z6Rgjyqo0#%1N3+ZS)XUuh%Z`85}6ZP>waXnOkOFDS67{|NU~1}FT&6wq$3Df^=&fB zUS+eGmM*;}DxL}ltLJE-r#Y(sI@fRQ2K8|h4k3~W&nXs9jgAKd$0VIp*Mlt@$c^We z`7PSoA1YtOi`=-%5ur1SryOX}5pbH`kTCyEenDJ!v9N7~4i5uDx!0+l3w4L-E$HeX zqj(kyl35*N^irKTp8!PJ0@chD3K5mk-SD^1I^9eRYi~>q%egt0)0!9dee3h~PqU*E zNRf}#DScl&M&k_`lSoXinXoa;=_1IM!ma20J8%cCC5OsSJnTrH+Q6)t(-u%{JhI0L zf@nH)A9zv|(Mr3<0@31{2niCK8S0GazI*~*oqDbcB*tQ#hg|S_a2*1aVifY%>wrXAUkChNsBE!gT0pT1kUTiD2~LtYC!ra@V>HUFTx20VAu zbN+ICkynfDK9)AxLz$vDKn$}$>k@|(A1{g?T0=}!Y{MjRa++N8`|WR0@s=g>?hc3Z z4MO?M%>wbpWu{a=gJWIg!itD$nXiX?1NfSaY$Y+a5j=da5}<>{-Gx8J##B@MZYAq& zdA6A$`tCU;Z~3SF^xO4X$Fu>EPvWWO@}LAQG1GdU#p3XhlFf$7`}H4`pD;sq=#Y=Lgg1jeT*~yhL;xp=VQ0w!?`h~gDy}ZB zE#Bp)_f3cx37lI0e_`Z*!MM`3dnXJ)Ap9>$K$)zt`;5;>u=bCGq4ZPzqcnF>{{M*L z|Bdkfm_rf6g2)O}=mFDB+OE~3e!wKyv%ZSB7dBVR*H(*QA5_n7VA(nG_J=3W zPMvN(?kbwe{pC-!?dTue_Vy;ri=;~g6WqTYtAi47)#FDNNRG@t&^|RQvHJoaMs#&M zmeyQd-+tMRI)j}z7lmCMr*{8IA8!~K3>O}Qk}92Dy^w2>?sYTIw28~d9XW3~>qaM= zuR76oD6{pG?VRHT_Ux16A`=~N!lV*Npw(6eq71@e9?FxLW^TyM#MCkar?O^d&|@^?2q|l1r=>mY zj+&Pn*I=mA#qU|jT8mr`9QkwEJod72N1?mTzfRcvD;1}jC+fJv!TA+IP1TA#2Uv`` zNmIw>nGCo=VCClbwiutM?m+G;U$F$4hD8!Q6?j{aI;(Vm0it+gvgSQo*XmuT=Cu&PNjXx(ZI_1YYQ9O*YO+r+SMRDzDCDbVUQGCAJ;Q<`vV3j9v1Q?B? zB}=Ha?he&^^Nqmk4+U^)!9$_Z&ZROVwuO+t9Yy|znZS;Ku!IF`_yOTH)2KMJ_+9~} z2O1wGL?q`>Vic`i?tlz$Fn$`gv?ZkD|JLf@)$;)AYEemLwjBsxgoRD1Huu~n$ zKyyJ|e-#X_vJaiSjv|FpeqgOas{|^%-IV%fuk@rEZs359vy#~htz=O3`9d=8BDxEi z-flM7Kp*fMdz$EPv^7W)8w39l#zd<1#G~ZNe96nC^J0?4r#Cm=6EfGb+kSRV_dMgq zWEiMHOgW+#KfP_lQo~o%Ck|+MV#)a-1HDV7!>LU3pukLSxn48BrFqKC5nbNHx3cm@ z&bu9Jt%o;qpQeso6=ritFS(>Tf8!9U%Ir($6EYG!fN_37A2X(*>%eRn)f{AEN$7|F zjNOcz&U69L(|rt#9BxzpW!;!aHY7yoFOn*7Fn_B~d*Et5fjy*lb}O@1{b$7cZV-Yf zBJ!I=OSSAT)Q5Yn3_dk~=g89Az_#jXD0~>^mV!6*h8edNCtcFzg?u9eUUp7ru@p~L z#x^6Gg4~D5C!Y;waCqI%DND1$DG(NZAx)AIRp#yNpUa;5kM#)Jk^tp3h|}6pyxqv} zp0z4%7LYIQd4LBBfNA2131GM+z0>yK89yD3%?#b#P+H&O!dkJETk_PA{is*>kXpv` zYdSdYiINgb%6g=oh`v*#xRh&7|WS5^_V$nGU0E&>3-Tjl+0z0O@$G zjyOs6R8*L@KK~gp7CsgI7uZjP0vrsZX*l$>9-Os2YX=)CV*^+az34$%E;x|Us>U{p^x}zLAIvk^ygV(0mX`v4d5HhT`v4&=r=G{s zA{8B$qQSnBT3%n26{82!sr7Rs&8z<~!}fb|l+lcaE^fS4bnXO`nXF zKP{@135eDg?{yBD{=UClcsFt=Z8#H6-LBe99bLombB-TqoVs<7t_qER?3#fX&XA775ZL+k8m61divd*fQe>(uHi4o&)`RKfM0gSq6 z7832ADTit)-+!h{xk>&yD*mApP1nbK!`#zX$xm+5>?}{2gywTo-GjSySGQ^Vy0hs# znYWC~DS}kjyVz)Oa=DMDA`w{la9dzlM4;cqKck zmKjDG7`4}^=pPs}l(sICm(tc4{d44m)GCs24~ZAVID2$sHmw=^wxZ)=aSo+fD-X1c zJo70UK&b{}^;#tH0K5T?GI*P3XDQalsVu^CTLyo+lyNuw(PiI%@6gIwt(M((Y{r;m zVe^A@MCYp}=OuUEs8-a=*x}amSw1EPdV|R$c+d|e8!JkWWc0l#&Zumrii;x0OvBQd z;m69!FYQ{5^Ly#A3f(H@4vhB&^UB&3%)dEj#MnBtaq$!{G$~Bv%_#pgWKxiJx1Fui z9a^HW(z`gtjS4J%d6v@fD1u8;*0^s5#*KdN$^0aT!C{xgO0pYHm)^$Fb-QZd`=xm0u$&gcUII1{^rHGbmwE#9JmW`!x7TOZpOJc<9td zJo)MMXb;4Q7~Z1z0Q@EYP*0WYhZSHANtQa@dQ0s|7JEHycFa&jTwVpQT4L)Z;q3VU z6g^69mpWhUvgaJ6|BmUu81dmbgf$kaZ@i9BZ4B^AEKUVx%!v$bQcnG4kxN8F*i(d3 z=66C+Z@$cfJVTQ*sRs$aSl=&yRahr4P&a;RA$bR zX;{wG3be!H-wgS7i@98%hrI}v?WiuBYA^(BNrLGtU9QRt3Hq4)$kZ~&Y||7v50#-t z|27t9;8Hj!*3U$2B;esGm3}U{cB}Xs_NuNoes=2`horU-z^L1v$pyZp@_0o)_f#pU znYvVv#Va3;1--Ig-JhgP$1?6CMtxI9m=o9@-6O&+`}A>+%8UQ>1@r&Vs$oezum6$n z{&zuX9j3yB=}FtUW7<*g`7?HeATuZWwFNE@H?~yPRQsFMJvz4 z?k33*Zl~NYE~I+Phjn5a+Ys>hhfh$5# z0!^j&th^}q7PfyZf7OV4@3(^F=qW*vty*iK%b6rw)>Cf)IMQ#&XGin?C(=7R^ z0Dyg`;sUj_+3xg33s^U*!CQLnqM~KVGXR-LfSY;C!)Q7;t{r&s^LJHKJ#`x(ejJw0 z`w3(9-wu`4DHsLI;a^&g8722BGibOJR(NpuPc>YaaeVT&KyOo0kDI-nC}^JGq02_j zEj!FRf6?vbe5LQ)daKgMR4&Bd-uWi*-D0fa;>L&Y#B3AN8en`o|7>r!vQ<6<`Mvhd z(siQEG+I~G?wLO`?nd~N7nsHAW1f&*v^hl+EMH}UQ&>m64J{l+lQ1)F&6ymcX0{;C zZsz4m(qxIS&uk84#_;!_DS&WYDTr%$u3qQrZ-bSJsqY2qqKe}Cv!xFjXUZ^}$Dv|BA zHT_Ml-rd&T*e(VbYkm$Ts8jz8Dk!6)d)0)IlYPXXm$%OK_Dh)$(Kx2sw(xj_%+%{mLIK&VYq>m&K14nE|^c_^)CffM$yXEhTzCZRg(# zx=2kA{h8%E;Nvqv*BxB+?P}+_MLcP(@+V@Rznf*>(^CML>^arb!^S)ml^LrV^doc4q+rOSMWct*$68(EI&Y25s zmY1*4`)`$4aJ+#($NW`WF8Q`z=)q&KZCHZao4%$`$iuyY5dL$=JU?zz^-C6%A5BV6 zc+pD=s$bt15kiqPrB&RI^ZTQn?1!9_{ojrcq?rLX8ZGA!Xp=%i@icqkXmZwB7yreo<) z=U^l3%odk!I~P#AICZ0%(OdYbElMvwao(&Q@rsZ_yISYs!CUCYL#xbkod{O|_Uf@2GD(XtPDZJ{d2%PNltE+|k5|_wsDrT-Us3M8l&ua-kSHDS~9QVnt?vbGEmX_$X=S2ijm$8lWx_=?4JDI!82slU_$K zOw&U`){J}QCrj6p_bBpOkD_tSfGtJ#DUOUj0Y(oSktKAFC3X+41X6gK; zV5%O?-%rMI{D42H&T-b|_V>QMB+3bVtn)<3larwOW@{L8wB-Ze{fe@&&i4NXG zmbHf|iCS$(6+7YTsRz-UDzWqsH}=mqWCKQmWfQhLBIb-fB1AF%xJ2coma^c?DP40` zKZBvTm-v@@Ol7aL3o}fQs$U;J+J14la|$OCt0>ngw~XG_%CI8N^2K;vBebbkIB+eoMJlztJmrVcY?nHQ9#2lce1V%u(yFGytO?t&)5 zpMh`>Sl17=@pm(^wK54^S?}`Aj^R9yu+4G}A&X%60neoyS<!)Ga^{-vM%W}vQG*2=`~ z^CpoKgt47B6--QxH zd+N_f5D#={l{d^}ad<+SW{(>wSZ3jTi|#2Ae}fuz_?E|~x)Z_4FCa-=R%7pe2>z&4 zTXpsLPIk;$tdK*&i z*05SEP6%BoZ~UBu`1mZcXOh!}`F8I95-jwXT znhdlLGXKzc*O4gI6*qv$YRA2D!=mZ)v``p!$&2Wf@2&f-JV_8YaiU5Yt;KJrz8cnI zGSG}!7){CHHv*HGBdu2?QDsT#_-A&{hrTAwUhUrxJe1yp%@F)*7?5*-VS zmhm*(g_hJ}5oRWj`9tkV%0R7=TP~&WBB@A4#5q6qx?W4+2 z-`{l_H%woQ5_+637Nq>u#z$eogn)Zb76&s@Ok9y;nb9TGVVapp!Jsi*s6|V}fGUC` zX@WK5&yzy?SYfKRYCLbus~cSB97Z$0unfP<7yDgBJ;ZD5MF>My6jd|7D9zmnSbdt- zg*Fb85%#c}?K)o=Eo?8;_+}M6mo%w&Oq4K;0lss3xJJlRb6B@DREY_#vYR;T62;2k zo7XMc@WLrX95+=M6qP@JOYlL^6|JhoIvc$$X>wL!E-=7PvfpuH7we5@$(Wb-i=>VR z;Mw_aUi5N34`Yj`STrw!>L}>p6;)MYM6Jx=Hh0BtsF0|k@4*ds3GtTREN#k$J$(4u z0!|(^cwgbTPiks|^}$vN=pN>r&-@zFYx!ezB3f59vJY&eUgNs|YHFK@qPgxTQL@q1 zJ@w#k%&OERm7G&}sL2Szi0?YT6i0{-@Wikm^a-^8zgihS`=`8kmN%ltT&E#m?>dEe)XdAEiJCn5CN0%N|6%&txNeEXLf3Fo^FqX?OCjnW9%$3hCYilzaIK<)@YiFJHtK15cLeaI%eua+#g3m-qv9T^*h?`*h=rrC+~!Jz*4PcOBb!HA^^!TPq7y5DxIfH1WA`I(Ge4-fZ4zCEhi6!$;6B zKNnxxqiM{~(>$+O9LsF7+>$I8L8l%v@M^l+0KIfQCn}C|HS;&E_VJD&A0BguEitsP z$2IV3k_51q^iXWkM-;f;qef99er6Zi=coZ+ISbpLZNymkB?Npp;PK$VOp03MVE&{l zr!)hpEd2W-{0)^4DYmVrTC+^DfexxOAApL4LK~6t}+pdw;G}+}; zH{V5U(GPnW+Y*ouJFSO$r(0)HY1~k0sO}%Kwr8ENW??q^!qk<5*(Sb%)}QS1V{V4# zqs~o!<$=a?Wrbv>jRWwu<+_#SkSrtW)?abjWoKe@<--KC{Ef-66{BUO{PdZV=4S2m z=lBlGe*Oxn`Dt`e!`X}0Ham^X!X0N(=>a@;FJ##{q^PCKUN7hEU(Cn7{ z;|k_sD+zarU4>%Y%>;d9&5%X(C)$$0I+cX(V%Q2MRbHxzk+8e`%|Do|L1poCeU5X@PE-Sq`fU`NFDj8Yckr$y+2(DxW8hq_5MP;B?q$1hvumFv6gTnqrT%y zm!=&NB@|eTUw`(aQM79HOT^Kck(c9pN{zjrW3@X6*1lgkla|}pn;ccbkm_VZhZ>9Q z*-mipp^vJ6mwj33C#mI@`t4HqhpzU9a{M8_OwqQiNg^jK?SZ(Z{P$VJQ^sj(NY6!g zIkmvl@^^unY>zjVbr~su;BMtkxzHJK+%vdfw+P0b8AR7clQPP^eXB0B5fCs!Uv&fH zrwJo**7csBqkmb$e9?w9Rv7;N=Ko&XDo5Z&?vv{-mbo=SLtoalV&w)kGm*vP%{CV} zL8-}$#D6$5WL)$XX?s}!=oyaT=w#KRP46g%*3G7C@(#abdHRo{ca8SuS6dj5@8%B$ zIefOT2Fz9sVMKdQjLWouBFPX z&8}1>kIThBjdIyQi;AH~%}~CUxL4-@z2nk2_W5kae$uk81_ta;_^(q&o%66g7GPbN zk3f|Cv`djACjQz(={nhO!MMA`E}71uBsIq4yz|F%lzV?H#EruXjj8b`$cK;%u0)?#X|$Q3MAG5*1oB{_OzYF)VAXRQB=LP zTH?ZAiwymFhr&LexZWGM1LMkrt<3;@gjXFoB_&U1PWGPBGek%Qf)kDQstvZ3WTn%y z{Cz(2zl_|Yo~^@Q6P=~qG?``MFk5y~+YXuXlI-?BluF)M8;~bBnT}*X&?$f9Bm#U} z7$h&Y7=^yM^&_%`q@fO3m8>qZ?pYA_6U{pO>cKkEv=jP^VQ)6)0;JVG`iTLn(dm6` zu}0LE6>9u8^-k2Cbz=rF#6Vou>bYX{Ra2J)X}EH$Hr);$4soz-nD@241^`BuLr~8} zjfj%|P70j6N~U*h(wNoiD+nuSbnpkAyS{GGZ%>P3CE(OLMPThbRNVScRkoJ5{+FhU z&uni{O8p(}!5Y}`ynL4@8O{c#ZW>!Ilh>jZnG_lTJO#k{G+L`7G|K878Tp9cg z@=~j03!^J#qc`~25vZVWFgw4HX*CnT8V0j+ID!!qE@Uvflm@G>hfb_wz~ z6Xwfl7c={SaJ`ovtZ&AO)|)kwvypDUs3;;%+5YFMf^5h%jaYS`uU{l70G;m>QGyzO2v{%`+>L@yTqcx^NfZ0ZJ$AT zO3~y>p?t`N{^@AWwNUYbiEV3MXLU+v(+m%b=g7UrZ0o`-#AGAa_$f8=`mn%nw;V)v zjPa0J6wA~gTcB@-$(Y0GG+}Sn_Mkl`fHh==Vyu3N08i^D`-#?m3V!Q*MMzX@bIT~?Jp4Z@mp)8BGfaeEA}@ZKfTMxOWDRbu^3tY*mTr3 zy(VdQoTrptW)Ep*zmsH=Z4I*iBJ#Yq8i4dZXzx-CO^MVcm^?G z`Ow}}{EoEuz!SCiVhX|6YhDgV-eUfeYifKnZmhdu-|3*8-)7uG*nG5CLV>r}OuHd{ zR-w}6!geZA_}O}(=S_cXgzaQa>Mk!zqO@c;nIDkhJoy7S5!Jxb{w_p<_K{Mxov;>> zbgd~nmN_M)@(Iz^+$mLqs_PCe>}rX|25|v`!f)D`l>)+<!%2&s&?$bJ4F&^W!k?)FN4YBV(e}ZC^Cu{{%KX@MVD{hPy2Abx1dsu5+ zn_0D;a&|8H?Awbq;qke|*O4Bw=Mv-1LsR$LgNasKE+A6F?9DP)b)H$J!-VXyyWrwg zy$4`*KUK9z|`SF5E0@aknX;LjP5=s+?8n{TBR=WJ{Y#l0y+Id*)>ERBK8_hKtb2 z+0bK5&))f7P-k{%5Xgcy*{eU~n5Sh_@a+A(xus{Hk9|m1_SLU!f*kk2ndW?;i9I%g zW%h%yWS7ZY?<)MTx{@2(QY&gCJiwehMu9B+Vl~r$vl4))QL8-NV^?xCYs4d~>f$`Q zVpT{fwYJJ%JxaJLv$Su0w)?yNjmCO#)12=hM(djo5crQ+#<9^zm$Er;W@h$Ruor*o z3nzzGkY*d}6YX9FtNouNA=yH9lZU9P+Ye&3iVaG`$OI9FAk)5MMV0zh|A9f3D9Av` zeZL0XO$_VBDdT3Y8Au3C_WV5%kCg(hga+TU>L<*2{<$Ha)T8`EpK_c%Bsuk z=hZ)7T~D%o8+ljSmBb7kV#LETeBPCfk>Nqu=J6{8#3~EQy9H($od1w~Y!Enr^Ucec zJoAfc61b3kYT@wn2ix2~pDG*;>ScecJzelG-V{z+n3>eJ6asfIOCx8RN+17x6dL{_iiaX z_YEve(xpEmrtz(X7jn0n5L1`&^0EhG#zlB6>&*0V^BNbpAlYX~Pm?`s^KSG?{1fkr z&CkvW=u3>WlV zg(!)c`8il~(leCcF@XzXKb0X11K(`%h5AcAy7zND-)|2Ob!Mqbql|Q-!)D6eUW*5A zHKPv%8JQ`SbeR%RfQY2z9JwzzZ~3w#e~N8;6|>*3?a1%CMI30@%ot`P&-|8J(S4%` z9>F-N+(qv(w^0c=(!^9T5ADkJqEzi^avD-0O8nob=}rDK7oiMqcdxg;v9FG4l~Ks^b3dX5%NLC( zD?A=5i&CbOX#RsszTJ*y1$ z&_)|gQzmMGv~c<=HdS4@6H<-Y3a+~hAZY%s=_m)M%ENIxi}>! z72KpPC7$dNgP#p$iRk8V(n0TBz)!6l>&kjW|0=u0Z6DY}^*vu(?6NFVZ^}JjGx}kz zm2T3|ign>XK-QlX;ORnfZ4S$1_5j44k6x*LC-AvI^``iHnfGbu>T`BUE7 z9tu`~h)595dA+h0m&Lh6z2Y?Z)fE5R%o^UPoIIy@Kci#dZ0Y*HWJ{OVyV<%7I{i}$ zDFUc4W{h8X5tMG5R|n@Fn(w;$BYtr=LcTf(vMp6B1T-QABPtEBuXr-42-ATc{&&_k z_@13sR*j-qpDNm1{teEwD<{Dn>_V5z07ZNb=uyboacfN3#r%h@CbtD zSbwTl8yrOj^fC(l{PWj4rhDKmx2C0(ae?NKsg#;{>i0v(h^#v+fAKR}>j_Asm=`#0 zkkhWOfr@fyUF6nE2C>9MV>7$W3t}#F<*@7=%IEwUU>e8MZ0({4g-umpj_iz3j)O^) ztMx4o0}Nk&5EUY|0PCtALaOgiIvo8*`f-rN1_kH&z@pdyZ&7_r6EVO1wfQ{e+vq^f z8UF-T-w=TdAjS-fmMBN|wG;83SyTu&lxnaC#fejbPO$M!#@3pyKbNPk0i`WSd#gbo zRKifWP=?SV8K~SB3Y!Di_Q?*;__XpXT=Uq;SJ-t!N!c2T<3g>RMP4O9=9>>^4Y~+E zeLVbu6rOcBi9gGtQPkQd10E!w3wsf4g1={i|Dw7M=Ohrc>pIe`FBEWc*sUzq>P|Yc z#N(0b6>z^8S$h9duC@f0KbEcA7=Kj_YONg3P)~-qbtV5{Ej;MI5-zUJ$|H$A7a6ed zvp}b%cHjq>B?&9O{Zl1we|vT3d*wZE41h+~4YXN@6}tT_aBKL9^tAHK7H^d>@cpP< zoKfYH7TlCxxoWcnvm-e%7y7Z1uR^oySh6~mm$F!+X`N;EZH;~6mn<9_`v!gChIp3# zDyG%=2(v@%8K9)X2g26z?m4x=oRPV=#H3B@9u zdf^Q|b9uH%0s0H=jG_5FHp`N3xV_Tr@0zn|313z5n*_Bw0#4%5xms6ur%D0Zv2Rho z<9*hj`Yqr_=B3loPFmt3di^{5C(*6$I}I__c1dnucE#47rjbD<#D<4yV-=Tb$s@Gl zx)IF&vW!qUE!KiqlKS=ILNQhl4)x1JKBSFyw-sq+U4qHKdqD{*XMVq19XaZM2Hx*) zPT=S1%w^&!NMg0rnJw=tV~^DS)FLkU38wgcn!Ee#>fY8}p@8K1Q!kxZJ4aaSb8vN3 z(x;KKb5twGfVhtZKlVeT%Bnm66KQj7xW{Z#HX9WYHydt`WCP~1))cLbsij5a=1iYP z;q+U)GT~3+wQ7(fFI5+$(b~3LnNkf`+=@v%kxgG&WQtvM3@ww7P2p$9wa0L)FV^LE z%u3*6xu6XtSS=~nHtnlMk)gh-rSKbP*{`ZG1krxUZA+e(U%~$q<~{h%OnDiYtOZ!7 z7FsXmq`ga#rgAVuLN6`eIvQ;+>HLhH^dGdYu%?HMyMTB!^4eWV)lAHu`cf6^VFk@{K{o2@u`2pEZMi7^CG(3r2wu+ZfHBXJ$f}{ zR!Lj6z=vm_&89k;_@`=^qy2tINa{dVdoP2m4_{9q>FxlM?wYbarK|f(cU6!g^8!+2 zmfR7Lzk$cR(rPqu><(YK24HS5P4L$pild+7X=P?s;7?^!Gh^7f9JfWCug23>EH#lw zL;)Vjr!v3XNwb{4fFdnR2%v0frdB~xD#oxH;;c*-XhZ52Sg!r1*MfX+D%?!vYZ8Te zHl{w;Gw67^<@cuzY)Elg%4d*R#^0|c?AMvISmPVc#hd%XfjWuELZpL7#MhYA@J9yr zq@l;=6gAAfp?@SoMsdVTT!S%>l1HcWkS9l;H@`GR(_wc2O5`gd51P*{06(Ct99YW4 zsG1GTLK{AQ#+ham*)F@)!hI1cx2&mP$a~Q&!uHP4vIkoh)QBv2lnft;HiOOGVjpEL z5+vuiO5vW1*Lo}O&~2@Y7%UCi)h6vDJ+bGr+f%iixaEbKOh3)k7+HE_zB$eM;=qeP zm#Mnuy?D0!c)o1bK)LRmr-a`rnJ$E3V!6QTDIEYWYHC|P>RKeDt2e1(Iw9KC+OqE7 zWF}_jTc4z)(7CL*tLZifl}%`FVfH?Fzb;IUv|8rRrQ7j`gVjQN1*^AT;!=9tY05A9 z=c;;`gPj2cVT0StG)G3)&PXF|pTA_7bNGdy%B>-1U^`n(Aq6?Em%#ntA5kMu;wK@G zV#H*zam>h(>ef-bTf6m~rJpNxQGqRxj>M@5UlyW(n!A)NEv}Li9{zM+y zXU31|>h+LGBJmxE$QE0|H-W1I-AM=rOtyUUm;3j&p@pqlQma%Q@9nkBMgfIb3Qm2j z$LFt=ws2UJHA4g*c-*)?QGN_f;Mn1wovbtnhh0-dvZPiD!Oe+)YlW?)eTXv^A zFZ))eCnNu(g3zJM+M3grDZ)BA0mk)0`E)6?g-m1}nDtgq>NjL$jxx#1D1tryX~B+yX5ev9-zWWN5YDT>NMk zg&*Q*ice*h&l(9^;SOWEH?WLW#i~!+SrJoRz_m65Z;`{;-;v~c86(#A^MT1Vj8!j) z5>pkG5KIG19fPS7xBI}Io8e>h^fnj$Zn;NiY&>YcvToNC7Z(fGwAm!Qyj`!J55x4v z6kg$o&R>M1l$-{EHo(vI4nlkud!VO{*2*TbXcR}Q@;L}$it!I*<1 zlq7+4q~?N|mZJ{)30v-*(CJ-ENY~i*jnHelkdJQF-xwr-pAYX2q#W7g4^I2cRi1** z$vjEDGcKFZA@W=9|HF|3xRJB&L!BbLmf3vMYAv7}lPs5ymp@fcbu4#(j%829QF;`j znvP!Dv*06Dkj(bH3ePT`z;H&dO2DFcDwzY58{4VuHFRcQy#p zr12|pxcmNuW3ifMn@wZYba813%_}!?!us5kHp@lIfywo!gJ1uGHBni0b3x$}Y2>xn znN^5@=dVq>1FC^&R^5U-$~;~8k205i?f1;1yD~|D9LX+x@4PNc608*e(Ca+Txq0mz zn$l?e!G8bp&;{m9J$YI{Sx+^fM0OriX4Y^qkQRS~t)^Vflq-ArkCxMsWT}&%46#0F zUyQ8;3X%L0OSq||`n_*>1qk6d&NhHviBTyKIx2FI3=`;nii1@Tk{!(ry|pM+ac3*B zil#Bm8+t!_dIF$JPZWThT>bI7^JWB5q#}J}&P6XuJmMnWR!-dM+l+Rbb!9S24V)D! z+eDsLeGY=YdRGi9+d;p(bF;nlqEJK>p-Yt`X_0Ilm zx^f8@yfKsJ=gET`yh;|70P%B_5OZ1kiKdDSyQ2!s)tb|nJW{N^AxaW_Om(*1L?Qd- zz@=yMjUz|=Ls<>lSrIvlr zFP^Rg_>~Dqdc{H|Axt^p1j|X;Wp5**qA-pl&|Yu8LN!F5F5N-UbFxu~-l2K}64j|+ z*nkZl6Wq!r+81fM^)wB;V)cWKwMbp{Gbh;tqBn`BbvnPh^SJ$)5p^SXdF5noN%cL< zEJiso=(CdWVQLg7vvcDq6`k>iLAH9*s*~>Ga`hFt#s)wq!s6uIk!B&tK_3Ubf6T}!yRQ*?vp@D>Qo}DqvGN|k5Kt~?Sjj3 zo(#y?Kc#3}o3;ONQ_Rk*ug9mdRX2Gb%6tB3)FPE0I;Z`Hwc(|yqB z@`Aw;&vk4y0+=TN8vD z5_B?uz9rE#Pe*B35tM~gjLR8XB#j`^KU=y~ns~Rad4zY5CoaD(WkWAcH+@$|2i_(% z+|GWu03L~)AeakNnXUK>Jivc}N5*VSoVQ&S{l2bAOPobneoTjQwt@U=ONIG%UGP`Zvqz>D&OYs#c0H!} zbYv+z>5}oq3_UxAkHelJosXXYb_z0h#!rS~evDhITDoQh(QvThm73K!xb5{yotdg* zFO$_KATrteSx>5!yEIlJm*68s6Irf5Vf zo5RXh(L_YtVTy%8pa8QBoe6 z-Ea7V`RrDz&)!faPSAEpwrWy(-KH_ULOznNID$=A-wyTj-9Yv}&Mw$^ zdt%MRj#qV_Jy#pr$X#u&^qrE0A|K}*o+)Wr(=G+Q<5b;q{(TZ;*cK}mP^-JmqE=x~ zG`MF&QPka)cF{n`=Lv}5EGN$$8Z>ZjKlC-_2qHKGmtETRQoP%JXJ+x^Cy3{OlK>PI zK=^>yo^(kG?W*G;xM)JG67yGk|Z z5%s96*`N}oKOP^otGegpkL5~*8rYU^J#!K!b5fh!Q&Hw}K6>hGaaGeF$ZGwxu4Tk=DU`H5hYLsEwt@33;%(q4E*9N(aPu16s z_=hhNDn!^8Z)a=v%u(;KCFR1xqT8lQCz-wZ@AsMWCZObYmSM&G^@sqCVX`tFjUN!h ziKMFuCtZo+XD1(;<|{e&c`7IBM1+vSH;-WXc!>o&)u^Uyp z{EInU76Bq6)L|(QSpjG%yhE(o z{(;AjFw2mj>5yZHk@SX$ZGQ=@AjCnI#4Q?;!U*_NB#WC{~Jk1-R&Q(9P! zAmbJ_*AT7!jA_i}E|Q-O*afUaCCVMnoqh)vEjVz&(XRvCPWV(pXKP zC(1_ZbLY%gTcrBGv_-2_1N{bDFaHxQ(zT74>NGDb=E?V0Jd92>J7<-f?lD&%4|*MG zk{muJiEWEkw>%rv26Kirw4yMZSK$uz0jfPX2V#NeV6|K6PH^1juSQGB^a2gl5By&t z8|T9ckTg(S(!|E=Z9D_`8-{TNpgD3Q-Zk$nHGOAYJF)O-1@bKE2ZfEKro9X@{w{_%@iQBp2 z0g#8g;cQaJ!{^aSK9_ZF+@%y;9audY`Hs!WX*d4n)kri!V7wp92Q4E^vL`LVE%3KJ z(mws)6QWz5?#D%uVnSzFL3WiAnrJ+^V&C+M~R?!ueu@`RiY`Q<|pYu=}eRw`@ z=vn;v`$nl&=-raZ+>NgPI3%c?L2x>#as0J|jB*_h`solO1RHLi5`7o6Lk+$6IJv(B zpp2KV`=Ze5>B@D_I>!=j;s}> zb8ysbmJxdTQ;AEH^Ks7&S29n_;d$-Tn8OF2EQ&(>)Y&#-M7_3z_X_%($a}Wsp(ow= zNw0d@>*C)<aezBBhZ`k##F$t$gx)UJo_woAu97 z2*7*MpJV!(6Y)**JH$5qOFMABFZDN+5AlotW?ObAlNR51N-=Ue4Xj)EL-g~b#08To z$5Y)qza!)q*-WjZGwbPLdKV~7=WiEIE@lmCxhDiKI8^<2A>zLYZhJ`cDrL!r^c~ze zx--R~VmAzDah5W!#qf$Ba#F$JStMxyn29fo(iFOX*Cp1QbPFP^WKHHD(x({OjGt%* z40c8dG^#uJr?KXPeU-6-C1nQ2)wvZP;o7 z$mT_P{~SEIBF_(QF~KdW7kxJFr=FdIUE5-|<6Lk4JS^kFa<yl5SjgF2xDP6a{ z_R4PTrWeo;Ff-aSQy9FR%B6zMFKaO^UCYKj)4|+{4>6cOD6NOfdS4I^Ir0geyNcss zGRMc=6Ics4|Izjt4Ea3i1(*``*s4*~>54${nwhZVg)Cl7P$IJILDZ_A)Hg%i?PN!t zK4uz_274dAMVZ=6XOLEe%n~5vgC!2|YANG1(7F)sauK}MHA1uXaY`$6mA5PjyOdOw zD1J&vOZQ9}hP(7e0g0MoKD4@xdduR7WQp|dUMA39=`l$$+PWb)jln?-&9th#sSzEA z!M+GG{v})@*M|wds?=fE9K=z(%1Pq4op|(xP4P_3lttE}I?Nc%#JF*?WwZc{3!dq$ zPlLu7Xk+?@nD#u$3cu5kr%YwwCiC6Jg;^A+(IsQ5XVSk++pr{Y?Rr0`HwBxKnXfG< zo_aj$;qvtqCQa0_OMU^M!aGJ|2r$(?2>cO)Mh;R& zO^EB{>Ok8y6Wgq7Z^bwbbevaPe-wNsi@auxTP+j*dFVRRwWp>;?0g8H9mi>}$;!zX zUph2m+Qa-xvdRLde>k-f4k!`Ry9->(I z@&sshfYZ)eI;)8~NS!h3t3>hw;dBhuBN z8tA>9QmUTD(mf2@b=3-I**(!eLUE5uXWFI0eQ?}+VnE@q_MOZ`t(<9)Qc!r^xgxSU zJ0_4iR|G7AMDqie;qwW$7a_`CVpklXnX{XXQMcyF)*Yf({MM^^8jPmT@E*@E68PJ~ zP0I`PunW|*oGzMf$^%HZVVovvRiuQc-1^YHQsVj--23Vyd2_)5^b?#8Xn=4ee*qdG zAYFv^p!7R-`e235#&=EYhd}u%POl_lw_Tx8GW{|L-LLVt$(ZOj2i7w6Ey*~>BJpR^ zioE*<6r+q%eP2+xB}FXtV(nsaM}@e=^wc3@||$K+2(woC;9a+uIkLxdMmvgvh?&Zr>PrL97?JZGyyniR6r*gbr-Z$!- zK&bpU46gbxN`PoOta%)(BnjeQsX5317qY*4&xN2f($zh&^D3^!|Fh$3p~0i9esWAV zu~6HRi~YXM&i19Tjv+mdI5F5@LEFw zN3nVw3#KJALpHWrOJ*h@0(HgZEQ{n7e8b4+x~J%)5lzQVDZxX?UFiA@ww^>MY^eM@fi><^IT`OOu_7 zLMdM3d)RlSw_=NBE^!%Hu_eb>D#*@+2do7l&-GT!EQcK%TL7;fS$I?`VQUIS0<>w_ zE=IXurWiR`B<0Tv2BFJ-Z_EV8?k(c`eb5Kwj&T9GW5m0FNWX**5b65~?AznE9h>f% zf7A8`jn);1%*mt|(_uCi#h_K`w+LnyE-=Zo;uPrNCypeEW=>^PLNt3~3-O5$;7X<6 z*d?L6PgCG$?%fCXjy#C01_XdwDD@;AIB5h@v2R{(v#%CUJ)5+xVlZSkmr2Fx4p3{U zf8@7JL2fHjZ2FH>|AE?nAtnF}kNBv-tDbWoNsRch{ON+9QpW8aQPXh!an)XLRQR;u zn*grzZV_8-8Yfu>pK&I$tZ81(0s}SAt~VK^=$<;@$~ylU-CP^?9rA}mA8S)X*CXM& zc4t|1?>os*_`+f`#QvJo_Pq~83i5^aP#efzNnxW&8NNBTmT}2`wh-FrsX5#b0fdam z_P=?EIa4-Yw<$JDCsH--Ju&gS5Ta=3rVdMQUY(03)%RKhPG@W5X<@U;#S3MT)*{l8 z(?KNZw&K6q|9Tn(z}8Q$jnwEf8`3lqT^dnqYl#62aIqVIuWv_DnezFaQWPVLH(S&f zaYtr7CXM5t9`fiE1nlS`w@3Tw%-}}r){nA%hw&DcasYtP8ZPruJZ@>h1$s zJB52{OGi8L76y?&csRLzPs5`rnz$O8U*+~sa#Ur0&Y!ZHuGR5xQ=>k3vV9Z+nEIoa z9{y2f&REmk_~JI-EDzRsqox?+&S)(N==n$eJ}~Doa?q$UBYzkrG-@AASP*e$D$eq( zUFq^z+7Dc}Q2eX5mHG6K>W>3_bo?leRSx+FhE*A#j8*&xwHM_IAcRBSJCgQb^on{b zt}mn?Dc9P{ytrAT_F1W9rQ&0Ce4FFtSGWfkF9I}4 zpPFR2!Ws>%K3Tg}3%5-kuOQ)aXIuE&171Lje<{AdBse2qym+zJ8x*3L`dlhH4|Xjg z+$iUE4WECe9=K?yzV-IRh4wsUr%7Xf6+_&g`C9FWn}r{7jT=<|+%SRFdK}!Spr%@! zVD4wF&Pjl>Ehu^R{f$|AIPj=xqj#!SaT{)b<+Xuh3NK4cJ^Q#|&-BYmW>>$`^8#i& zX*XyxD$&$G4lp%rguYKc6(vSEBH=CWr>1HP6y}QMHzk^p_2e{2afTJOWHGsf>;__J zwe2?LN93l{Ut?6Y)0w+<&|dDF&?5!PL}w;cJ}%^!{I=M3l_4l}tCgiq5PL;-F*`*O z9KvK?f0|2cvKx%N+`veG+ywqrM--=`$iM)RCDdWX55bJW&5m*!7jsn;o%gvhLZ}x}#h72<&x94v2Civbca*)k z(s>#>7xqtu?vRCBm&jqj*6Im)j;?2hr#Cw;s!I3A1-Dj>yk+$b|1#L!cqG{Gw9Rz_ z%~NF9xI*K#h?R)(g;H3Hj#%p#A%lix8=D<^14qSA1!XG7$m^f9_~8;&#j^a>w+!Mb zr>)ibcfSOopuX1df_f!!OFJ4SH_yIab)uv0ibcr1BBmS}Avh@ac5OSnZz%{m|3Xu7 z`CEmTQG-t%h7Uf(uc?EDI(Yk}g-xZ>-f4NYvnNleYUQi_y5!8oRHRfZ$kz@lILnAq zYyLQ{`!X&`?Kg}*tYU_o z{ygdZClz>OKpJXAJspa@W>3OGWf1tAm>FK2z?CB1^*;~x-gd5?z&Awwa13wi-Q&<` zuGot|V5V+$S=1(tDLQQ_Nx*mh68yr!e3=q;4~v=4_ACImQ}5lZ&}`oBcHpz!LJP5* z6~XTs(2MyK!4sC_UcBvU?(HMKg&Ei9(Ja!^!`vEoAk6xOP6mgi1SRYI9w{M|3Y4Hz zNNVtOalEI~Z+vkB9@wMJGWN|I+jsW2K>>jc2@N(EXZDo)8l_~x>veQ$PWW=ep-(E8 zWs0v-ZAk#-?nf`~`;8I&@2j0Afk8aLs7+MtmiZ^h*ma?kv)BU|(FH%*3>s7y` za5<9Fnm>0}I*IQ00QaUf?-7N}_lj{{nZr7!y9#vy+fvOV{)#WV%V=V-7sVTKIr&h} z?#H+racQMqi}GZ{tDZcgwMkZb+H*m@Rl1suTsk(|1WaZ#} zZ)iXxsGOye*Pc@8>vq5*x=d^oCb^{WRkwDDYl^|MNhjf1W<70_kRKa2L-|m7W=4}; z#Sa_rQcPgEhgpfJ3w<@K5d1N1vLv>p)5-VN&3Sj$_bVnaT6=#@vHA$}6;Lz>>Cnp@bhph(%!8< zWH(wR;xsl*iMYe5g&ssEIUgPC}-mgC$K~lR6fB)O|-E@d}w6 za~{lQkJ->Sp4p z=UTAxip>Hl*|ke>Vqz)-iT>kbocuZts!tlr7Iy!wtRXz3m~JzP3@!}kT0@!{qQaAE z@~=S^<^?vk>ad&d_>G(@`HJfc3+vuW#yzxNmg+A% zO)RFnC8O$Vd?H2FOhRe}tOr{(XJSPx7i(dj^SLu&1B$;L`)ewuqnQ#7KU_)l{#ul0 zzDS|3I_WR|@oL*qv$kYPkCgz%=hMi);s)oy%!Fb7++B288SpK7Z*3WATe-K`>M$g+ zqN-s1Mi|N(b^Ni^|E4!jO&zW+&#q25n1OETbUxJjdN;ZHK=x+8{W6|cF3e!)Ow}AE zC;hLjv=ZphEn6mCT69T!dPW$^k+u{JpEg#>rdiPHz5a}gY4De{pT5#%N97CN1472U z)ySuk(Yg|gjNB+BE2W<~3Q{jGZHoFQw!}SSe4r@c5F_jhqUvaPvM^;p&{x;PfHB3{ z8shf{O-09CxyFUKvM-MD{UNocm$pDaH0savxx8({2LCHlFRG`8$GtK5L|Odw;l$&k zA=4S@Eb6tLc1#48>H-lHzSMOc_ZGNnOUPz>IE@$In;Q>6Xm1rol0_ouWxTHw{g17^ zZ~>z$X(Pa};f?)jviY8BMY`oyb$2!6nL7{7(b@BXEIh-(pLYu6G)WC9e3@EOrB6}_6M6V#q_&4oO*pzn%oYCe1y!*Enn0!wP&}3zTfQ2j z3FQxjTtFTOcN?#^mZDUiYj&a(#0&#fzvgUFAf;+g#2@vJc`V$AT|BdmzZK~Y8w)7Y+3(9-tXc4w zNZqKWo%!6Nz5P`qVulDN0MjwuU)4_uLw14{`6FFvS2zL*bzVzeDqN|uA=ylogqUjo zY2Pg$UA_7qj%<@PkDs9kQsNVTm_TNX*1LL5wg#!yIq*mR<{mXuR-g@}=`fIdW` zea*EG6^=m~2wJg2U>7f81uYj#50 zZ($h(yV0{U?@G2c<0xMc;+%~{f@ve;gBVq0X;ot@yEMUJyKD5Tbw!^@KV*IO91IUH zh*(fbM|Ku5s-0gtU{~!66Q6twa6Etg>!J7lbv%|sosTvqNj;BoUQ)2*l+_=4l$^zM z^rm7*hJnT_FDWKX!5AVkm&mjcZ|Q$FiW5%U*IZ#L=Gve3uv7HDy;K_Ury0loy ze2y8*vlcutGp{JNDIs+Gst}W=51;I!8Z+22kb&tfVWf_c1}eZ`5)kHmD)#IDt&_9e z*dmCsF-UvNq9lf~G2&pivBB;#NkzrDp8)1KTbhy^9xy}CX+E1+x!f)5KrUpI%^ED?c-sLzG*aO|>r5?&ag9K~+41&x3ay2P2{@ zg2`O-#hd5aLF@0j0byItF3v)QW1Y0B-W1aXeO`e9tzdUl+w1KxnAvg;zqLs>ONL{8|H0e-Ijo2!DC+VeN{ z@=PikVzzHH3spZM9C(vC>z8vBSY9)IPhI0ecdHQyL15jyeuxcy&^2JF+9sgzR z`(H+VpVXFQW|t)bWc8-K87*qkwqmmESIA6cQ=9FFpF4P@t;zGgBz?AC}Q@-udYp<=mSkfujaXP11emdrc3V1z~yTP0!HoJ{FC95H+pLQ>1-rUX zmwLN_th1j77{~YW>|rU&$Ns`K(mq01`1@}m0{i9^&RCncr&Z{x^` zIAD4d2TQHmkib2C)IC9!lT>F%dMKRzu*u`4k$4*&cH-Oc?)qt&qpzl;qDdZ_r3DMLK%-o_(JT- z^T}s(zV)#(8Tk|FCy}*j+P`L3B7`m&jg$)QZQsR|84$cknV2`^aS9Q_QDgNm)AA*) zF;k8HjuV(Z<=}mh#SpiDX$VxdcI;pLHnRt9y9}txYb~uGU)=%$G0@18X{e7y1tcm) zO5Jy(JnYf7S2Ht6b!P23n>=q{HIU#e&`W2-Y+nsy6-0>gjBf>upRj9tU^`jO8BL^{ zT~(yRd7c_kObrBd=MxO%Ad&w1FAE)yv|uV2_%Sta!t4Z|<o<`}3unzsa z+U#R^Pp-@>^0gJX04cBKT7|;luKh~Ztb_V%_jAxru(YEiIS*VQqafiz{C)1Vzqxw=-gz7Y!vwGEgW z`2WU-JhqoWNL|x}k#1M!fNxHUX{(c!gO&N?3d+!Jx_ zJ*SpM?FEWmbZkMHWpbd}^&GCkfVSP>q8x+=%)^3UY<1m~jL#58^V>23UJPx=b-$}W zVsI}@S%1`r2Tk#Kz#xj#+MvkRg|3GIMG?rn6740O_vtPiE9+b(@a2gwynANJ0akoo zHuvKy`0$*>C3h%Gbxk~oza7Bvc1wbjtEp^V7yyFV)r()qPE}0pqNPVuk8$~7$i18Q zhtFaco_lhd;@P*_M(#PL(IeBHKkL0ZqZW2@VLr!6$B!D#PS3aF#*%0qZ3g$OxUV}3 z+){B`x-$TW??BQR%hJVS(^}!w>XqfR(L$M3Pbs9X`wVp|`w4`pAg{m+VhGLcJv*pL z%VB2Q;GQdQE}vHvGJ*=xFHEkG=R=F4fJ~QhZquw&yl#p?p&7_5;*IkOQ!~$iJCsaAnR9w|0jHe41sPx)Na}W(7TkZ4tz0`*NIj|D5bxh-#G$ ze=*5q-S_hXYnDT%(EZXet|zj+yZup;X9Jre|QS>1`1C zMH+3$YJ-em9!l1R#(0nPALqyL?Y|!h(gw6#)ab{++Ui(~_5wD3*eL1-dnc1}KwwLI z?R{X2zCUafP|7pWH{Djhq$X&}U2@Bu45NNxFEt^XYn+zMocD^t9a4&~sw$x0XFId~ zvg}oMg0k-u9uLDIvQ{=mR#)U3_Dh!}b3Uh+x>BoM-YwK0?282#jFxmF@uYcPUYh|) zs5!T}@JS9SYPwkGD^lDSHR0G7DN-JI!tD7Q9If2~Rpg1QOuap+LUObh84c@~JVcLX z!yvHZ5j8;7@L`yxfAujbrfI4J%e^-e~k~m-b$oOZN zjquzaMha;HBXfv{;H$E=e(mFAFR#O^;Uky*OV^EwdjaYK=%3baVnt*c8Bly+K(n~< zXLKO3TMo554>3FKJj1s^FRZjuM`P-O8fDw5c-{Nkt7;O>r{&&`^iRpXSi4J`$nV|I z&?Mxn9l}1dGT!&L6QesixV4iWFO|jUqpX)=4oecOdDLf{tN#q`l#SNjp@dkMWuGc@ zFsC`LEVNNf@MmT8M9#OWOrc1p;Lk5H!hqRE8>guOo!Vd=LoSMfJD{vx;4uq481^HR zxi#jH(1p5*&l+Bt`47dx)K=L^=~qIOfQ(G8=QNp$_X ze_u7>nRN{af-m0PH!udIg!J-rO?LppB;0O2Hnr&Uo9Hl4Ftuq$U4Nsgi1=wmxRE9a zqIbIz*{gPEYiHT-5f*4hV5JZpa#({BT@v>1`&|R<2m{=A5d4YS+kCYhgMSyhpm%DF z#b_$rWhuwFm|>cyS^D%9(-yeLREHLvlYp|-L&--Ip?>Xsr*gkJFl4 z)pq?hQp+Q(#ahan>Fj%utPqBjh@hllLH=l|sAKZlb?irg3N3eAJ@FzDV0c8yrUr=``u(W+QkqW4#IkGiw?SJOfy@>0sd0kawn zj@#|!s8*dCk^Bf%?2&Zs3P-JsP>);E^Cn1#x7(+fIP{K2%hJFv5;~h)9iCe};GK5C z-g0cr(KlCYB7Xc=f}};kuAb>O#tqV}%%r$>d)?x{+3-~ho?pG9 zo={eQ@4#_e1Y~GWjaoX^+}|z7OdC$;j-k3-p`4pVP6eOBQ!5C&{JxZ#RCY zqr=*+{PYInIaW@3a`l6l;#Y??DQ{|Y1HPp0`P&rtwb1WVx%5v;km3sNNr=O%My**U zX$q?swR%=DdY6H53U7bTf$Wn*k@7vafHakF*JM>AfyjRS)T@S43m^720b53?c88KTW)5+_)B&X>JeBhq(a4_&# z+>=NDtDr7~nHu4mA96U!hYn(56L8}ZaD3dSTBBQ#U<=#{64rkLOrpy5a5a5UR%O~J zEm|%!@@n&i6nXh%l?HpRi0|DpWSdz9#0gdME4hAaba~E!sDL*rkhz;q(w@-XnxyxNi`u|uLNI6Szszgg0HVD z!@zJo@tyORigf$-`}c24)2D`ix1JA3i~p5Y6N~XbjWg`1D^fQ7Z1$9OH+(nwQDYu- zj+AqH-rg?hW7V0Ll1@FA>F?U~v4q=ZnDncS__yP(vZ;(|niRAvB+~O2Pq)g-%l4Lz z-fYJAYnCAs`DCY!9z5wwdj<7n-=n8=DMRO#hw@QiXq|OmYo0Q&cRh2VHGbDkS%huW zJuSd^7H84daa{`?f!QCQeVDf~y|me}US|f*wZp8V&@yGttv@pH!fyvDlO=9WJ{aGk z;~F#W5vN>LQj>{yVlui6G2uip@%DeP6=+Rg2S@Re;n_+I8qwl6Q!N*-sPeerto!;k zsUqf`-GIE)VWLa(5X2ZorS=7e8ZUJR8Fdcmspnj-;E-RbK#~+g(n$<;!mRo`dS@V* zzOIsFulR;?dQfwmWrW~^^!aq2-fG3Gu`e6U7h--PshaP-TQ2G+8W52&*FQj|%4)&p zLz)(%Ux(DhTU3VCbxLX~bEf)lzSnT~t67$$L>a~X(75O{zdo%J=zdYOu4_AI*f&P4 zHw`%MX^Le~m#N*V>b_|dt?MalD6mR_`83?+c^_3#?Y}&8zcJ(PA@Bf#Q^ZP0V6psv ztm0f7v(3eCo}HQjVCjmk_Ela<>+fFSL@Du}2#(X!>!p|6Z`_e@05L0omB8`F52IBI zsk1nu&z6R1eX3pSi*GL$jfY2-2A_%)Y*Tuph^TgmKXZ5j6jA7iTvi$wq zx<3CjKKk9`C1)m+{ltyyE1w1b*dcp}J_5OaAxmB>zE|lFs6`Fo@K)>jb&Mn-I_;SI z4aRUs@4!`#e+>Q)GN$WVP7Zr+amhw9)`eMP#hIFR$!u}oZiB`*s{q!((2rvIK=F#O zLNJ(XW>x*^*VI#PN@3wjZWGNAK8K~*{)MnTj_Y~V#4WY?roOeD1&e@7;|_hhISgib zVz~T&2Ui~KaGM!W-^C4;$oGRWmOQb&-t2OacM>&YbKtX7BZfC$Kao+LP!y`H>~tCo z-8j-8a9QQu7&aqfZ{IRrQkm5axGkl{ge>Ws5eB>Qd$#|Bs)k6*b|7V@NtQx;hZh|7 zXPH`FyJMgFjCz<8yX`(iKAy1vHJhxxya!W`;}s6maKdvBG(i3WbO?Bsz<@D#*P$8C z-;(<~r~e}$LOa~}c5neHv(HK2znqN$9oFhZwg{BO_X&i5Nb@yl329)w!7EiuwZEzJ zlA9M=G=Zyeemo`yp8UC@dgRr|IH!^bMXxq5(~=q`-|(cV!Tlkm$=I9xw{34j(YV0z z7o3KQthnqoyTg|j&q`=29;)hEk#%f9giu{|B$rM&^-elQ&Ujk>qv1~(yB*; znK8cW8b=PYlgO1fux7-FHieGq6;XM@7xDa^g*Kr#BCv zFyY$wzj{UILUw^3#n+<2So@*R5?{Hv-uWI*KNZ$jQd229RmQYx_f_GDlk)31$ve*- z+sJ6NrVdi|Y19f=OgE)Nxrri3kBoWLT053|iita1b#oZ%*udTCK^;EbHBZ%^catCB z2G+=^VphyS*$|;sRUq*9qUt8vH|AMUc1oo!l3fNH3Srpa3chN9Hn~(BR|66UIuUl` z%pZP1-xQS3lo#FV?Z`1SuP&G;nqR8*>)Xe$p&Sz)lR!37rffI`O3OBytfmz>bR zF_KsJY|`8xRs4N>mSd=r>bDM)X=M3W^!G-YCh9!`>#q3vS|Q6MZoBp)z3b%zf{$yW)-1#YpX z1rt7tKA#e~Z9%QTPBj|TE>%3WL5vW8K+&hjP}?Zh-KFyGkdMP&u{tNteN@EU8?|7gl+*FK&S>qC2b;s;yi~dE2jlHSuDaJ4q1^HYjP;bU=JY@L zslcxdSvtMTlVl|{Z0dIP@cs7s0oI}w%+c=qsI*oNY6^Vc_QkFEl@O2a>pxRj2+FTJU{6gJ&CWik^GGfiERO%-X23Y1OH(0F(Muqc7yIL22;Y! ztGMlz?&i)@$mfgQ4OszAK>~{ZSe|m!skC5?*K~!dR%4LAkb%PTnHpZcn&Q0H()P9( zsQc2Bsi)^)|)WhvGQQ(8YEm-aAY+dwNW|CmJ$M?bJ-Bh7HV&; z_P2oi%0-E&kaWV4hH`*}NYmo~!oR=-NdW!@H62R)-j^Svn-@0YU2+ej=Nl}&wexDI zl^vhHMSVRqu)ytd!`=ejH@?TOtjvW;5H2ymxAB3e5ZeQZyq zX=vVJ2)%W-P=Vzqd*&Id5B8qeN_0pa_fOUxV;<0})w`Xvioc$@qePQdD3OVL9oWTe zniYL$g2%>OOBIhaCjqzWW3)P*Wa7B2-nueNo?)oXIJoiZ=b`|Rm;))OF@v&KOmOzG_qQLd zSTQ#kAg}(AW|;Q$pyaqMGrpPoZm0|6>rQ(tHM#43>hBS2(K#U)z|?J4WYcUHVXTD9 zz8V5}=D14_F3`H{{~W)WaN3m<0ez{I#y1j}eDyFrN5?gG$NYi0mw&|iGX}CiS-~%gEX9O3m*F^{*48)Yr$&w)TY*X7e@q5 z@vg%Td_RK7xOiaWF-TIA!tPHOZTQEcC6{Pn)!LonzmZN~GNho*j%+YVrgoPB4YHcu zO0QLM@`9@2tf5qe6ZRDRvwOHF7hJ;&f3J+^g@XP|5Uap`IQ`p=26oi1B3MpZo~j&Y zRQa>_7k4IHg+~pD$);9G{#VRZww_nwbVnXt2boSrN@@gcAM66)9an&F<-Y+tnZ#`Q z9ooR3-cMFC(=TNE!n5a`X2EyG)XmRin$+O0yG_bliw=^jI{*#HknpW>mHL0kG8QU> zH}*Fb@;*#)izS~@k6tLx*X_awWjK3I%)`x8_eUxm&Ooepe*Ft7PSD=u&qYQJMRdG6 z)~PyU=Su4ZFzkattcBwPjSXqxxsy72sV7z~)EA#jC7-UQcIV2sSLk%XC)muU&g-_e zyX;we`UU*RuogZ8S;%&|=&JxCYXH0NevsKLmh_0RWuSQ}m#R->*ddYN;4)nG_k$ z!>=cd(-^kwVz901*-3+CzE?$KAfl9qC+dB96uEKm?b=m*j3_X~KH@(p$oi-TOx#&1 zW9}VxoxsQt@w|Gx7qmBvKl5wj;49Qk0#yIFEl9>!EpC7d_pk@E<=Zb7fo^l{x3xr* zdcrftLhthm2TPpNu1^0k`(=iH6srviovi@m%D4jF3HpRyeb3-;wS{srqB#riUkj@ zt~3rFsirb*v@V4qSy+5Q+p?!3klr3UoQvT7=p$!Bs3mTeF(m3ZC;7Yx)lr@GB}&jY zrQzHEE1&kJ_J8Kn4s90yH$IJh;~KJhTe{vkI5zJumx;D@;OF%?Ba`C!gaH0IY3Zwg z_DRpyq#cIZU+^_jY=8-@-)1UDzZVxq(=-Ut5ZKzD^}ri8$7azjYDIl$sg_1dvGa>W zm&Yu<8T*in*n#;8$iVyrX#+Ta?QF)5bjaBbm^++EZ>iB~TE4+Lzz-t(bBODJJ#xVl z0B6gn<6a&#Kk-URIZ1eXD-~p>uVz77A3i2ZE3nq$j_xZwoZ!uN+8C*ft>KOSZ_v!! zrI3&I;>80FId$(AsKh_WEL!s$d_jdk|49J2=jdP1j2#+>N$iQ{d+ptr^u>nI9lN=H|EK1-B;;MoWemw7J+GB)A)>+-C}GyRmW(H~k?4H>x@9)2)WoT3KAb!|?D zcadZu(y=T?I3ErXPRciq((;C07jx({T+1J)1ec zXWh;q(-vKI`J30q=pdUq-u2)i?TmlQp&?ind(b-kV58%L5_zYP+!gX zEKdB7o|Xo9Q}{j|FOrY%WUu}VKhQB586-=q+=NHI`&42wsP=)p-Rn1>V;n>3qcUYZ zMj^Qb!CP5`4a5c1Hc)!=aUGiEvoDFhegQ3ld14v(A31rk$DgNtjn*4NJIUjpJ!>#z z0pM#&OeKKjyqaEK&Gr8xQ@xX-vAl<6TTK*Ph8$n%a__f8Riz!(&fU@1yB{;*RZC7U zdNI&YabDmihvyUTxjR0V1a)DLz&!d1=M*K8zT^ySo%TTpSW8|Go-~OP-&R8&dr;lp z6#v=(-@(`eXJ9OCBs}d0x8MJRiR+h+`~Lv22N8YC|At&-82>*aPJkZ&cWjC=&J}t3 zBq=7%cBFOz?P+V;LoBouxJH$8(?FBx_R>}Nn5Szm1fgM(%t?-D%I48P z#XaZr4=KtUpiq2ot1Im#4z)>ry_M~s5dY-1u4Q6Bb1&(}1=c&Cc`J8ntyj1~H@)0B^qiBgkVK-5K3DZyJ+ zu=F%q8IK-sxg{}>npE+_58Rq**MK_bgKf2{p%N-S$lvGhR#!uC>g~DZfd%@KGfx(m zg7*A9tB{9YCo0Uh|3tR(^tVRZj^y>vf2!Zl$6KH-B`GpWBqXF8 zlpY)12uKT)78L1jkd$tQbcb|z52U0KgaKplKZn=vx~}^;{txa)_a4Hr!Fg``e!lT} zzh0b0!6C=r>zK$iW!Q5|bjQfK)A&!MGy2I^-@lnFr}3uA;_g;tew!?v+*cx3Wlok} z*)-e5{$laa!!4{yKxy4KSyAC7tmbNWIsu{QHfZhuEw@- z#;X#vAu4%$3B{JsCw)cGk+AB_0X62K*`pTx61}oL{5%5o%01citycew60b`rI>iC8 zU0E}fQ>{F>ah1$Fbu@ZabWtC&Vno}|lRLT#zdGsGsqBBWp+S~(bHS{Quvcr;X*%3Q z?7(h*`HuS_{ZLJl!jR7?k`VJ5s;E(G_2$yItkNyF+C8Kdy8L9JYV-pt+x!*&1iCCr zWbFAcxC&B(AEo8__>guvX<*p;vx!BhD7iS|$|uG;YPes2MRXi0K=ikTXIMd7qa=fF zrUDtxeYF&}sPWbvt(!LCI7C9{^MjWxUHM%ty^eFd2JRA+dfe%5K7 z-%wFmQ;hi{#-d`K{inFcYJOE{@b>l^rq6ewaOOc+1;I#I!+y{krj^4XnfJqW5!7AO zwlj&Tsfoa$C_V8z&Gh>(tSLPji+p1|_$3lezfE2qc(Tl-B(qXb%J9sGlNK4*T=9OY z-n=RVSmeLwN7$yL$`cVA?4|U=&}EC$nEh(dy(CvXtOmoy?jtvJ4^8}x>CMP4)r$TX z^DsfJ7ho0~w(0%46Kp5TKb@vZQ-URW2X86=yyCzAc-CzV|94Ir&uusRa7bLXK6ID* zfGYa;AY52+5|)A=6*xPv=IecjIntqb5Nv?+4XfwtI*eLtlRhDQ#7<31NYcnvj5h`G zBkrQ-B=&;8Pwm7tQOI`h3-~f|LqojYJVhPa4a}6D2~-$fhBBb$Y_RNlFHwe^+?(FO z+jv9x9T}LlpZ2RB%6}9xeh(ANkt_N($-Pw+{osJMA?QKas*2IjWuyi+12I`B)1vm^ z>MWSvbc3TccPr1kKe+d}8$Hu^^@inzMt+@{C~M%bhTa3ZmZmG!SWPCyd?bDm)k`07 zF!N-gj~LLj7~Ezu<$VU0&8P)erj6FrQP7PWc9z$h_$@u1%9?MDo_;ad0pl_9HYo( zu~^!=#E?w8WNyGf>KKn!j70yb^+GCvQ`aKP6Pb*Y=5k%8&w=ZZkgL~)64u>Uuoe<@ z6S<=P)3^)s{p?-P(SDHld630#b)nnuO9-MS-dw(3Kk*a;qs%k@90`Y`=kF)Fz9Ic? zT_W%!NOd7}BFN##;nm;(?v=Z9YxcgNpZsO$nDW?_$m*34FbP`_G;D+e@1*G1)H<9QReOUwza%YJeejPrDChg7Ui-ZL6PW$7KOpD zpa;b8Hb-UbZS|IjF~VQiJtGezkXwlA$_he57GGj44!od(3BR(Q_k$MDn*LL z^Lpo?g(AWdXVFxpNikhDj--*e9qaswxCLuo(Y4LtQEcZ8MqdOphfB`ZHK^1bjiZ;yj|>%YL1Fl?fcp3v%Ga{_fj=X`+yL1mHA<9W?2=k8 z8X-Ft1G(h4Sn%qX(hYg%JcG&9J?8N#&Zw*(=gCys%vng+Z1Cp(HKNU+&hcRMYTS$TF5T3A7)zimG-mwe;Mic< z&}}KAi6wPZBU_H=-5kOy3z({<2!yP3KY!7LicJb!@%_V)4+E3%M zcFmm&UW&9lF?+8@NsxfBN<4|9yF&Q9Gu3>y!yrmH&QwN0T!wDGFZ@OJlK&AhR!82W z%%|x=Nk|)dFkk6??DO~Kj=xnp{ql)4{9S3^95dH2NQ25YM67CFXble|Q7Qg;C)b`W<)OKK3cL*A3eEShK2FDd4fOW*RJ z#8zMaj4o03sgI?}Kg)4Kw$-O;0@ZEvzCB#jpp!@*u+*uJ=WB&yluPJP9<$0wq zY{G!Dn!_{vKG7iFpMiyZmiSXdk#ril1gx>F!JjL)Edg({Yqq;2ed}dC;wLC`z_KFp zDn*!2d|GXCWH#Sh>k@%cj3MYj{P1-)+EZE=l*3Ka%_d-NVL0{m&c};Z5p8#fvo>xZ zC(+dz%ASAc6qo0<&c5#p z$d2n}B-A0uj5&KwP#hNoz0W1U>3hQp%mrkwJ?W&^(u(p*uu_OA3y~$q`br~^#pIjtAW|4o$N~*?M*-AJX=8uke z5jMucOS7H=7**Dkx+yV35O5mAg`p75@EuQu9P2;OfQrL_%{+UxzDjwQSjJbBWn~diHv<-`)Fa+_v(hXQ}_C9KA?%W&H=L;6xD`J~}d__!zT! zAML*`LutM-CCllpakB;?TLFONvqUi^Y|U$(B4(I9U^F+3yU{J9i!8GqaOJ?qF<)? zbzQG>ZwOOh$msO8#htIoH+^4j&SeFs_OtM%I|^t(JHD{Ci@pbY#w)_BxDYbkyyJdYM5FQ=oYz*9WW;ud*VO^a;aq8wPHM;K?E$Me4iKA zDw&B)2we9fQ9rCo(XLIf?@1z7jqyl>r+a@5iD%)tOIyYx~8mNvG zrgaOK+;^Tz;?FgJ4_fGwA1>}A;^#T1+T5ufn}py7F-OTI^~&J~DGs$gsC%`$QzA;| zy9HC<&0uzK)|^ymYu9_nQNGr6s_yg4d-qXHRGiEngHxUgqE=UIJT&sj3&^}n0h{Yy zq#H2*ZZkU2A+1RMnr<@^7y{uO{aM)SMhoC9FG(*lWWr1C{><~f z`Ri-D(UO9JhtsP6esz@h`f0MKo3qv)e`eP2kBQ$hb;{~?-^yZAEh>MtS1ss@`G4!4 zVT9m+e3XjV|IXgfHND7|@J-ZWK9bEE-hG=^Yoj39e`MP?I+7d$=dsjj1y{Y`uJzkn zAU^r@-8r&Y+rrYnq0dg4lBsotfhxYOiO)ncp|ydi;#G0O(ZP@|^-ew9F=F+AAq-Re zZ-^!BE9OUd+}YOK+9Ql-{&U4LZh$y_a-bu9s5xBQ)54+9zG72=-LpG5Rh=J|e~=Bt z)j7qPk+p9}H_16xrfjwlU)85lW7#%0bonEOYXcOOVCUT)rlsF}aJCZ6cr(@fVDDcZtbEtW+~uij6;?Wd%`Zsq zoMn^s!unRVaTX0Z$EN;rkbH|It>|1>`w}vHiuvzl8S?!*u4CeSjp%*`@GuoMOd>_X z;U*7)!~Vs?wCCec-c;DfG>kKT`;MD9SWs*xt1uAo1tlX!>J#C?_g3a}z95L|eCMtv zXLSGg&y(`jp_D#USmAqBK1m)Y^q%H;jy9^8SoqkJP1w8KCf%k0t8Mn9_H2_<-yzgr z4&|FR_jveZXkEaQJU$BzmmHU$Z~~4|j*0p_$EPrPDR2$@FaL=74ZouES2N!V^`n1% zOmo%a{1s1kT)TTe-a!{0RX9o%!lx;gM?%;W2J{*TZ^C~(SYUG5k}nn?OdVfJya#8L@q+{D&9 zy~vJN48)KEjRhdn$gG)?{)mo)gWmA4OIec4pQNy={B3x2EOxEeFqf|Z3lW|%F+%X~ zk;w|R-rEaTv4KTJly0&MbU2BS%(r;S6N0txawC<|(jw{XoIOpmpu~Tdqfe5y86c2yGpKkc9bb=}Ejs{w64=_O#Lt67 zLR+4L@O;)jTq~?3^f@q!CV1j~l2t2k^6>lj}oBrk*+@4%Pt6 z^oX$gtES;AWk&$)igF;x;_N^!HoRENAz{%4?9DpqH`ee0pW4;$3U#)fN-O#Td_Zkg zy}KR!+gV&xDeAZ(iofZmD>@44C7Qd6L2GxzconM0URX4ql`P5X_%ST7C%)ohcfck!z6{C<`dm4Vkw2T3O=PM{MDXbWE@|(~g>oisD1j zQC`hOZm&CH^At5Q**H3j&@MV2?km@YjSC-;>io3040hfK_%%Gtdb7@LNjFNuG(Lx_ zZ+CSvZjx8w^S~2=_8Ox{!7e+trmh;dzADZms@^vi#6lI> zs8dmaC_o2W%IsD+LzYiI2R7&!P4eZ6di<%7i;p zWoh;)+p_*K9iG;~R~%mpR>QRsugH&fu2cS2%L>ZqW6e?j@BzF?2W8MN|Bn|NN6+yn zMBDLEl1lknV8h5xK9w#$43uPAUOP+~jebIbt zT4{F5V-lZlcEBEf{bDzOc|I@(-n7Mb&LHWls1%u!LF9?Cf+S%Hkdhh%PF)g!aiIS?{ay(9TWN6qJNuL6eCOXg_hh&JQ|YG<}*YeQ4J|N>I!HLF?h^&X!4}^#l21HtDGx zC!kKRdltjI*F=+HeU%r_IfT4zKiR+Gn7l;UTz^byIIhjh!DZ`#kjy89%#p%0Ft{fd z{tm_!oeT>!ED}(ehs<3tnYqM7DItQ*Cx$i{x( z-g(t2_T>W+l%iT6vbL*#3XqQrTpt0~))2kmOM9;=YaXHPqJwrn6gC zLf3(u8bq(cg}Lg10JjFF2e8jkT}dOb(gK*{MyL4|DvA zC#2pIaqc+;h=nseGc%t=$nhIO2DXlxN@#f8wHE1Vt6mHUqrsp11ypVSIE@svJVIs; zx~7Wi1RlBrWqNcp5pll{I%bTD7 z*}tA6wqVjX>@~(_=0DP-svO}FHP+bq=lEogk^WW=E)r=O3KJObvKsFT;%Q((S1#Ws zav$2isn*WSI0hf;{4d|54f`DV3WVt|fhzd1Hn|t_O=isJn8wn3^jMUwP8jL(tEa-E zuK8{2)A+8HUq!f2t6o{!b3Xc>dS|fBAUB?#=u45-zzaXL2^a@ZStX9R_4r3@qLZ(S zWhCJFlPt+MW+ihHy21kvwNs+|C+ws#NXBtpd#4!|d7QCuY0m}S!dYePBfv(su>t7L z*0wLc8qRuHt8G6Wvo830z1DgN&^3&(1i?fdz5Twy+8SpEGyc^OqcU2C4!13=mRLL+ zS+Z#{Lo(}M<_Hj|92HR0JIy`ryiQN#%M6H@riyP9!!847!p3o7HaO*Ba#va~`%d6TtL{BoTdiL0R9V$4^9fGo zQiH?AA>>@G1^7E3TrV`?y^!SkW_5OiK-v=LeaV>^C4#A6H@?Yuf- z-V2(&<@PI%0Ugt^MWHko1ZFhP@Mt!B67=4uUh}!x`K&6JK_&tZ^rs7|%GH-rJ>=C#d2VqT@U(IQO5hI168GHSo)5db&B<|9Ayc8 z*~e8~i`C(Dgej9GSQMZ#^o`;;6AV5rhG(*Dg1`UA3fXKsmF$c9qphOc$blx(72VYP zz+cjfB1@Te10Y@eG@g6q(3#)1W=HA!^g2Uyn)t@IgU)5Uqr zwcTl)7dj&?*7@ETvjvf8kMI%uIW^|GZ$QAd9UI~zWrjwggW>N?dL(km(_3##R1uOg zu@g5nQ)lg!LZIv}uzKn?FO%A2(QsH41-&ZO7v)`8`3XRbVza(fbPY$1&8uCCX?nsjviAQ+X ztq?RK|C?IeM3~)n)}p*4XHvz-KJUio-;m<&A@lp7d)mciQ*PMyAhjEr8g367&eZb{ zDtRsI8#jQ`RT4j62t_#j?)t~LDxbW{QT`_K{mAuje&=X9 z;x_@)zDEG+es)-%@_O+U{xy5{}+TjYZ{tmqw6&e^mriHQ;om z!dyD^%nQs~l{7w2+v%+#dOx3GV|OY$QlTwZCx5ZPxV24=2#d`(-d25k%donPoy_(g zoO(O6bvA0XI-gyEi3^e;*eebAQ_Rzj#4x}iv!#p%+PpLN$l@fcj78dY; zGO74&Uq1k}XNqfx0>GnpN4>8DEDQ?;mpHw4C}Feqo2vJCUW!_}Z+h#Pg0>r^QhC-?|_p^#++K$}nAy3v^Hlp&KwV9_$(N8xl&y+vv!TWcMj*nEP_YC!? z-IYX>k4pBI1=MA%gvX=odc826lu;*m0z(@U;X_)Czx4te?v1#6=&f?Cq|w9^^|U|# zAi6qx7dVO>s&JJhIbc$NoBG4fIPtviEY}}>R&BI!-19q*I?vfoY7aDomB#X1*lb+-ITW<-d=g1Fr08j*4 zhxoXj@l6)s=3>gmxVaYpS)SXw>U}S1ZB9O4n1s$HBi-@AsUL)+G#>)D+weIs7j12G z_TKG<%=q?q0gG|#Hzq!ccb6}6;eXK?-b4>T4G^j5{?0?$3Fz-=|u%b7=$v>N<@5MAH6I!U0}%Wfnrag@w}0SPZ9#NFV>wG7&BJtcs`lhC+@-lMb&!B zHxB%vs?yqlQl8rMai{p9p$JvM@Oc*uXmWRP`8zqMCw| z+vvQWMI@sdA~c(yy1!=%-0yHKk*DfwSt$)9&t@x!8w?ZUheB6=j@+Am^LG8;xn{oT zntronXwxrPI(lhwU^jx%&2m`}>rD@n(*rxr9q5CodTmeM-cPD( zre^eew8Sc!&mZ8|RSPn=&0#&*RXEt!@aasKnD^0nlt0$@h+APJ8nL$*=KR|A(2@Sr zd#8bbs5cSEy|IfzToTog57lorv)K*c)yitu+Xz1*%X`(;-+2C5?YR~Kto}&>`zfU`*az`N6vD>+cp9?(J6D(%%9FaN4;7@#_~>a z-`(J)Ey$}8Bu5K9nesrLX@@ClS0G2nRlO~4k9A3}4JsY%gUP}R#_x6gXb<{?ixNq$ zr;-NUb-l91gC5PW4e;5&Vb)9^#EF`iy3%$o%S z@UOG1duV0L3GA*nDGUQhhvMiI?g#G&s&or06xACqC}XL~?p$V;u;1JSS}&h#o)I?S zQTtKEGfL}G+=6_}1AM6ZS6p@HhTAzM+-cHTMysnv zrRfP7s0z#I!E)~4#AQNPZTlA>AvP*0Pu|S-yWVyTF^`!{9hkxPwxRFma_DRs9cTmX zL2WPrc$$IW7Tma3OT6MOX%D@_?LV%0wz7e~3+a1n2{JyJ84u9}YT|>-y*@>_l?HMu z-c=D+^Ny$0>c7rohKia?H!-nk7i=hi4kHTwBKc*x;`-g) z?)&t~#Eq|^Y8Avt+8~eivAi^He8w%WZ{9URTe787UW){}YKL43;u|jy?jtAP+zq61McsPOC}7K6o7mRMrJe{fRxq`GB22 zH9osjdVRo5bj^iva{c*z(WwTVHzWH`X!sN3LD3+lt;6X4AzV!Un)H+9QRO|wBz|4Q z1Mr&*s%Pggv4`g^6Do6Q8N+AO#12P-6`lT3S52#tDBw%+0Hlng$)=7I0%$xgO66OF zI+Qw^Z>sZQZUq%k6Urx;1o=2_Jg&)`bXh^{F1U;E@Vwu7w3o(0yqAy;vD+fsLtGSyuAF zPHuNHxZffa#LB;~NLJco7Xl&>SIcDDZ=O zjL+!QIj{vRjzzMG|v!4ptDa19z@3m?j2TzNDsv@4(oy=c_^&z!!{7BPk z_|61Bv0#O_kXgb$k_qp<>b#g*$=$lt4D=-;En)9`dOUJN%w`qLkb_343GbZ&Bf8aB z;pBN*+Xf=EdDdmd_SZ?tTL?W=NUH?Qd-RUEEUcj7Ij9ukDy0NWA3vIv0}Z0bK!a%a zbokMVOWZR$sZUTMgJZ3tqJj0Wa;nt@dd9%fHpiFVH2aLtdFUVBPn+F0aDRVVF7AF* z_b@Ql;P%S?w-nfY{4v15s<6-MOdjyjTWUgR?`j+7&vRk9Pq1jY4m^FIDse?f>M7we zLhcNi1f2UMV@keC>i4~}i+`~W*w@zEkPhPE%2F;-$nZg4C5?x2r-dF(gW!nVUr z3I=}#mvXS~=|!%c3T=! -### Adding recipes: `add` +### Add Recipes Add new recipes to your list. @@ -78,7 +83,7 @@ Example of usage:
-### Editing recipes: `edit` +### Edit Recipes Edit recipes in your list partially, fully or add new ingredients to already existing recipe. @@ -96,7 +101,7 @@ Example of usage:
-### Listing recipes: `list` +### List Recipes List all recipes or filtered list recipes by the name or ingredients. @@ -121,7 +126,7 @@ Example of usage:
-### Viewing recipes: `view` +### View Recipes Views the list of ingredients and their quantities for a recipe. @@ -137,7 +142,7 @@ Example of usage:
-### Deleting recipes: `delete` +### Delete Recipes Deletes one, a range, or all recipes currently in list. @@ -156,7 +161,7 @@ Example of usage:
-### Tagging/Categorising recipes: `tag` +### Tag/Categorize Recipes __Categorize recipes into a specific tag__ @@ -196,7 +201,7 @@ Example of usage:
-### Add single recipe to weekly plan: `weekly /add` +### Add single recipe to weekly plan Adds an existing recipe to this week's plan. @@ -215,7 +220,7 @@ Example of usage:
-### Add multiple recipes to weekly plan: `weekly /multiadd` +### Add multiple recipes to weekly plan Adds multiple existing recipe to this week's plan. @@ -237,7 +242,7 @@ Example of usage:
-### Delete single recipe from weekly plan: `weekly /delete` +### Delete single recipe from weekly plan Deletes an existing recipe from this week's plan. @@ -256,7 +261,7 @@ Example of usage:
-### Delete multiple recipes from weekly plan: `weekly /multidelete` +### Delete multiple recipes from weekly plan Deletes multiple existing recipe from this week's plan. @@ -281,7 +286,7 @@ Example of usage:
-### Clear weekly plan: `weekly /clear` +### Clear weekly plan Clears this week's plan by removing all recipes listed in weekly plan. @@ -289,7 +294,7 @@ Format: `weekly /clear`
-### Mark recipe in weekly plan as done: `weekly /done` +### Mark recipe in weekly plan as done Mark a recipe in the weekly plan as completed. A single count of the recipe and its corresponding ingredients will be removed from the weekly plan and the list of ingredients. @@ -307,7 +312,7 @@ Example of usage:
-### View weekly plan: `weeklyplan` +### View weekly plan View this week's plan. @@ -315,7 +320,7 @@ Format: `weeklyplan`
-### View weekly plan ingredients: `weeklyingredients` +### View weekly plan ingredients View this week's ingredients. @@ -323,7 +328,7 @@ Format: `weeklyingredients`
-### Random a recipe: `random` +### Random a recipe Random a recipe from all the recipes that user have, and show the list of ingredients and their quantities for a recipe. @@ -332,7 +337,7 @@ Format: `random`
-### Exit the program: `bye` +### Exit the program Exits the program. @@ -340,7 +345,7 @@ Format: `bye`
-### Add user ingredient: `add_i` +### Add user ingredient Add user's ingredients into the ingredient list. Format : `add_i /n INGREDIENT_NAME /c QUANTITY /d DATE` @@ -357,7 +362,7 @@ Example of usage:
-### Delete user ingredient: `del_i` +### Delete user ingredient Delete user's ingredients from the ingredient list. Format : `del_i /n INGREDIENT_NAME /c QUANTITY` @@ -374,7 +379,7 @@ Example of usage:
-### View user ingredients: `view_ingredients` +### View user ingredients View user's ingredients from the ingredient list. Format : `view_ingredients` diff --git a/docs/team/topgun2001.md b/docs/team/topgun2001.md index 3656aa6950..d466c3765a 100644 --- a/docs/team/topgun2001.md +++ b/docs/team/topgun2001.md @@ -23,22 +23,42 @@ Given below are my contributions to the project: ([#51](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/51)) * Implemented enhancement feature of accepting ingredients in a single line. ([#51](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/51)) - -* __Contributions to User Guide__ ([#69](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/69)): + +* __Contributions to User Guide__ ([#69](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/69), + [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139)): + * Added anchor links for quick jump to respective tabs. * Added documentation for the following: - * HOW TO ADD INGREDIENTS TO A RECIPE? - * `add` - * `edit` - * `help` - + * HOW TO ADD INGREDIENTS TO A RECIPE? + * `add` + * `edit` + * `help` + -* __Contribtions to Developer Guide__ ([#54](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/54)): +* __Contributions to Developer Guide__ ([#54](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/54),[#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139)): + * Added anchor links for quick jump to respective tabs. + * Added documentation for the following classes: + * `Parser` * Added documentation for the following: - * `Add Recipes` feature - * `Edit Recipes` feature - * `edit` - * `help` + * `Add Recipes` feature + * `Edit Recipes` feature + * `edit` + * `help` + + +* __Pull Requests reviewed for Team Project:__ + * Gave comments on code quality and code suggestions. + * ([#15](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/15)), + ([#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20)), + ([#23](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/23)), + ([#29](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/29)), + ([#30](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/30)), + ([#31](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/31)), + ([#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48)), + ([#47](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/47)), + ([#56](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/56)), + ([#127](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/127), + ([#129](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/129)) * __Community__: From 2fff64c90f810bc7ee48e4ea92563c8ac06dc6a1 Mon Sep 17 00:00:00 2001 From: Abijith Ram <88262428+TopGun2001@users.noreply.github.com> Date: Sun, 9 Apr 2023 16:49:51 +0800 Subject: [PATCH 226/252] Update topgun2001.md --- docs/team/topgun2001.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/team/topgun2001.md b/docs/team/topgun2001.md index d466c3765a..dd4e665c0c 100644 --- a/docs/team/topgun2001.md +++ b/docs/team/topgun2001.md @@ -57,7 +57,7 @@ Given below are my contributions to the project: ([#48](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/48)), ([#47](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/47)), ([#56](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/56)), - ([#127](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/127), + ([#127](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/127)), ([#129](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/129)) @@ -67,4 +67,4 @@ Given below are my contributions to the project: ([#3](https://github.com/TopGun2001/ped/issues/3)),([#5](https://github.com/TopGun2001/ped/issues/5)), ([#7](https://github.com/TopGun2001/ped/issues/7)) * Suggestions: ([#4](https://github.com/TopGun2001/ped/issues/4)),([#6](https://github.com/TopGun2001/ped/issues/6)), - ([#10](https://github.com/TopGun2001/ped/issues/10)) \ No newline at end of file + ([#10](https://github.com/TopGun2001/ped/issues/10)) From 7d640589c601d219955ac1b24c14677bb43c4d3b Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sun, 9 Apr 2023 16:50:01 +0800 Subject: [PATCH 227/252] Added availableSequenceDiagram.drawio --- .../Implementation/Untitled Diagram.drawio | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/UML/Implementation/Untitled Diagram.drawio diff --git a/docs/UML/Implementation/Untitled Diagram.drawio b/docs/UML/Implementation/Untitled Diagram.drawio new file mode 100644 index 0000000000..cced1eb988 --- /dev/null +++ b/docs/UML/Implementation/Untitled Diagram.drawio @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3061566ef4dfceb202139e628133461427e2a45c Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Sun, 9 Apr 2023 16:57:58 +0800 Subject: [PATCH 228/252] DG --- docs/DeveloperGuide.md | 4 ++-- .../{Add Recipe => addRecipe}/AddRecipe.png | Bin .../{Edit Recipe => editRecipe}/EditRecipe.png | Bin 3 files changed, 2 insertions(+), 2 deletions(-) rename docs/UML/Implementation/{Add Recipe => addRecipe}/AddRecipe.png (100%) rename docs/UML/Implementation/{Edit Recipe => editRecipe}/EditRecipe.png (100%) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 9d77b5b6c8..baaa0aaf2f 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -377,7 +377,7 @@ It is implemented through the following steps: to `recipeList.addRecipe()` to store the new recipe data. -![](./UML/Implementation/Add Recipe/AddRecipe.png) +![](UML/Implementation/addRecipe/AddRecipe.png) ### Edit Recipes Feature @@ -401,7 +401,7 @@ It is implemented through the following steps: to `recipeList.editRecipe()` to update the new recipe data. -![](./UML/Implementation/Edit Recipe/EditRecipe.png) +![](UML/Implementation/editRecipe/EditRecipe.png) ### Random a Recipe Feature diff --git a/docs/UML/Implementation/Add Recipe/AddRecipe.png b/docs/UML/Implementation/addRecipe/AddRecipe.png similarity index 100% rename from docs/UML/Implementation/Add Recipe/AddRecipe.png rename to docs/UML/Implementation/addRecipe/AddRecipe.png diff --git a/docs/UML/Implementation/Edit Recipe/EditRecipe.png b/docs/UML/Implementation/editRecipe/EditRecipe.png similarity index 100% rename from docs/UML/Implementation/Edit Recipe/EditRecipe.png rename to docs/UML/Implementation/editRecipe/EditRecipe.png From 26934bf60e5593471e2e21203376fe41dd60aa87 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:14:20 +0800 Subject: [PATCH 229/252] Added availableSequenceDiagram.drawio.png --- .../availableSequenceDiagram.drawio.png | Bin 0 -> 39231 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/UML/Implementation/availableSequenceDiagram.drawio.png diff --git a/docs/UML/Implementation/availableSequenceDiagram.drawio.png b/docs/UML/Implementation/availableSequenceDiagram.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..ff745e7c5c9e6265ed825296e74d385620d9d14f GIT binary patch literal 39231 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 literal 0 HcmV?d00001 From a0787b9935677203e3bc500009efbe2c18b72f88 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:16:12 +0800 Subject: [PATCH 230/252] Delete Untitled Diagram.drawio --- .../Implementation/Untitled Diagram.drawio | 62 ------------------- 1 file changed, 62 deletions(-) delete mode 100644 docs/UML/Implementation/Untitled Diagram.drawio diff --git a/docs/UML/Implementation/Untitled Diagram.drawio b/docs/UML/Implementation/Untitled Diagram.drawio deleted file mode 100644 index cced1eb988..0000000000 --- a/docs/UML/Implementation/Untitled Diagram.drawio +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 344301e980c34a9dea8d3910269517ea43b4862a Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:16:45 +0800 Subject: [PATCH 231/252] Added availableSequenceDiagram.drawio --- .../availableSequenceDiagram.drawio | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/UML/Implementation/availableSequenceDiagram.drawio diff --git a/docs/UML/Implementation/availableSequenceDiagram.drawio b/docs/UML/Implementation/availableSequenceDiagram.drawio new file mode 100644 index 0000000000..fd3a4d140d --- /dev/null +++ b/docs/UML/Implementation/availableSequenceDiagram.drawio @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 626c892d216b725f3038eb236c628e42c94adbc7 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:17:05 +0800 Subject: [PATCH 232/252] Update availableSequenceDiagram.drawio --- docs/UML/Implementation/availableSequenceDiagram.drawio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/UML/Implementation/availableSequenceDiagram.drawio b/docs/UML/Implementation/availableSequenceDiagram.drawio index fd3a4d140d..ab8bfaaada 100644 --- a/docs/UML/Implementation/availableSequenceDiagram.drawio +++ b/docs/UML/Implementation/availableSequenceDiagram.drawio @@ -1,4 +1,4 @@ - + From 13907cbb5980928a15c5b0350c7b69a107991c59 Mon Sep 17 00:00:00 2001 From: Lu Bingyuan <101538126+notbingsu@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:19:25 +0800 Subject: [PATCH 233/252] Update availableSequenceDiagram.drawio --- .../Implementation/availableSequenceDiagram.drawio | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/UML/Implementation/availableSequenceDiagram.drawio b/docs/UML/Implementation/availableSequenceDiagram.drawio index ab8bfaaada..55d31d32c2 100644 --- a/docs/UML/Implementation/availableSequenceDiagram.drawio +++ b/docs/UML/Implementation/availableSequenceDiagram.drawio @@ -1,6 +1,6 @@ - + - + @@ -25,6 +25,11 @@ + + + + + @@ -80,6 +85,11 @@ + + + + + From a5bf36ba708abe4b173048a84eac1f71494957d1 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sun, 9 Apr 2023 19:20:22 +0800 Subject: [PATCH 234/252] update Implementation in DG with available function --- docs/DeveloperGuide.md | 23 +++++++++++++++++- .../availableSequenceDiagram.drawio | 0 .../availableSequenceDiagram.drawio.png | Bin 3 files changed, 22 insertions(+), 1 deletion(-) rename docs/UML/Implementation/{ => ListAvailableFunction}/availableSequenceDiagram.drawio (100%) rename docs/UML/Implementation/{ => ListAvailableFunction}/availableSequenceDiagram.drawio.png (100%) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0c6e1e6306..049ebb1745 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -195,7 +195,7 @@ How the `WeeklyPlan` component works: 3. `Parser` component then returns a `WeeklyPlan` object to indicate the recipe(s) to be added or deleted from the weekly plan. 4. `WeeklyPlan` component then uses either `addPlans` or `deletePlans` method to add or delete - the recipe(s) from the weekly plan, `clearPlan` to clear the entire plan for the week, and `checkValidity` to + the recipe(s) from the weekly plan, `clearPlan` to clear the entire plan for the week, and `checkValidity` to check the validness of the weekly plan (i.e. make sure all recipes are valid). The sequence diagram below shows how the `WeeklyPlan` component works when the user @@ -332,6 +332,27 @@ The sequence diagram below shows how this feature works: ![](./UML/Implementation/ListFunction/ListFunction.png) +### List Available Recipes Feature + +- list all recipes that have sufficient ingredients + +It is implemented through the following steps: + +1. When the user enters and input `available`, an instance of `RecipeList` availableRecipes is created +2. This instance of recipe calls the `availableRecipes()` method in `RecipeList` on the current recipeList which + returns a `RecipeList` object containing all available `Recipes` +3. `availableRecipes()` method iterates through `recipeList` and calls the `isAvailable()` method on each `Recipe`, + appending the available recipes to `availableRecipes` +4. `isAvailable()` method + - iterates through the `ingredients` Hashmap of each `Recipe` + - compares the quantity required for each recipe to the amount of the same `Ingredient` in the `ingredientList`, + - returns `true` if the quantity in the `ingredientList` is more than or equal to the quantity required +5. The `listAvailableRecipes()` method is then called in `Ui` to print `availableRecipes` + +The sequence diagram below shows how this feature works: + +![](./UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio.png) + ### Delete Recipes Feature The current implementation: diff --git a/docs/UML/Implementation/availableSequenceDiagram.drawio b/docs/UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio similarity index 100% rename from docs/UML/Implementation/availableSequenceDiagram.drawio rename to docs/UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio diff --git a/docs/UML/Implementation/availableSequenceDiagram.drawio.png b/docs/UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio.png similarity index 100% rename from docs/UML/Implementation/availableSequenceDiagram.drawio.png rename to docs/UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio.png From 153c9aede5c4ccae60ee1e0283179d0d08bd9c3b Mon Sep 17 00:00:00 2001 From: jaredoong Date: Sun, 9 Apr 2023 21:04:54 +0800 Subject: [PATCH 235/252] Update DG Update recipe related subsystem diagram to reflect available recipes function --- .../Architecture/.$RecipeRelated.drawio.bkp | 2 +- docs/UML/Architecture/RecipeRelated.drawio | 2 +- docs/UML/Architecture/RecipeRelated.png | Bin 64045 -> 67481 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/UML/Architecture/.$RecipeRelated.drawio.bkp b/docs/UML/Architecture/.$RecipeRelated.drawio.bkp index 03c36b4237..73784a7c4a 100644 --- a/docs/UML/Architecture/.$RecipeRelated.drawio.bkp +++ b/docs/UML/Architecture/.$RecipeRelated.drawio.bkp @@ -1 +1 @@ -7Vptb+I4EP41SLsngeKYBPhYoLu3EnvqHrvavfvmJQasOjFyTAv762+cOK9O2tCDdqW2Qmo8GY/teR6PxwM9PAsPHyXZbT+LgPKe6wSHHp73XBc5ngP/tOSYSnx3kgo2kgWpyCkES/aLZj2NdM8CGhtZKlJCcMV2VeFKRBFdqYqMSCnuq2prwYOKYEc21BIsV4Tb0u8sUFsjRf6kePEnZZutGXrsjtIXIcmUzUriLQnEfUmEr3t4JoVQ6VN4mFGunVf1y4eWt/nEJI1Ulw5f5iPpLmZLhr/eftn8+z0eUb/vjlMzd4TvzYrNbNUxc8FWhRyeUA9P14zzmeBCQjuga7LnMPQ0VlLc0kweiQg6To1dKhU9tM4Y5X4AAlERUiWPoGI6jIznDHU84/L7AoeRY1S2JQjwMMPfYL/JLRfugQfjoRO8hSxn3RAZU2m5LL5nISeJH9YiUkvzRruQcLaJ4HkFToCeeKpdxIBwV+aFEjuQrraMBwtyFHu9qliR1W3Wmm6FZL/ALMlggddSmb3j+hWNpe4JYgekksagc5P5H9VEn8mhorggsTKCleCc7GL2M19GSOSGRVOhlAiN0hkQdz2/AvnItSAfjpENOco22dkhdy3I+3vWw1cg+8Ys3GHlrRuivHeMKOMCp2vVyoR4R1Ys2iwSnfmwkPxt1q9FAvqueRJetiwIaKRRFIookkKm8dkJFqnEP94UPuCxmTPweh5MfAZtVLTho9WlmokI1kJYgh4FPtxTzYluULdvIRt/g7frd8M70zs73PjxcMhZgl2KcXYm1INjN4BDgIrTAtGvGvB5H1moYxt13IAwJz8pvxExU0xo+zLVrSH/GLhV9rJoSyW7JOhex00+vhDmwwbMpzsd2K+C4BuE90/RRtKAwRrjdysRhiQK0giwVBIQMU6FTQQD5aoLpp2ptT5VZO9T4Z2AOWkaY5TGznTEOeVU0RMH3VfVHx31LWidlb++042//qXOKDR5PGrRKLjS6XCBYymtk2IfBTQwLgdfyOMP3RjASjLBP0Y3acwPZd35sdy6gXAB69K5TSktoIGVZ9eSAkjsIaegD+EwbMah5HivIR/MZJJyothddRpNYJgRbjT1itwE+8NKbuJm7cxELPZyRU2vciJuGfKqhlBtLqkfLEMJN/Jl/4+Uxk5jz0KXvjNwHLfMF9iZY/8pnKEHprRJBBaRaacGsYNNu7CnG8dS4+kMTCF8wHeTjkxF3otSdewPRjWSjYYD74l8HeHBaIgn+V/VsOM+L3vtjPyPtiOtxNlHr115LpZcflpPIH3IkL0ScXrbQiccnJ3On4fvR543rjgfO/bZ4+JnzJddO2FGrwaNeiBH47GNhvecaDSlsr9NIpAFdZ2vlUL6g+H8jKEbvWj24Hu1sOnVTHSNxmAIDsW2aIwmbj3MXzoee684Avg+bI1qyQqCQIbAS4UB30Kkehm04HmV5coyI+Aa/iH5Ow8tUJYT5VcF+5jG4wZKIHQpTnSo878Vtk4uDPjNNGivZjaifqnCVlNZYEqCoIgG74p6Vb1q1FqnCpIS1QM2TIGqVg+bQWqRD6LohsrWEdYsKs0x6Vga5C8S0vJA7ytG246et+rWE0mMhx1J7F6IxchOagtyvB1lZ/rmzcsqlnl+ii3cUfbtXBn3iXcp3O3Est8eBUoRpN8YdJL0t9Chhx2DCwtRxspCABGSZklJd4uvtSY1xfepEJyS6C3KnF5Db7l+tZ+VjXTLfndxAt2gWfzKIr32FL9Vwdf/AQ== \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/UML/Architecture/RecipeRelated.drawio b/docs/UML/Architecture/RecipeRelated.drawio index 73784a7c4a..a2c4d0b03c 100644 --- a/docs/UML/Architecture/RecipeRelated.drawio +++ b/docs/UML/Architecture/RecipeRelated.drawio @@ -1 +1 @@ -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 \ No newline at end of file +7Vttb+I4EP41SN2TivJO+Fig3e2p3evr7d19ObmJSXybxMgxBfrrz06cN2wgqEm1e4eKVDyxPfE8M+MZjxmY03j9mYBFeIt9GA0MzV8PzNnAMHTNdNg/TtnkFEe3ckJAkJ+TtIrwiN5gMVJQl8iHqaDlJIpxRNGiSfRwkkCPNmiAELxqdpvjyG8QFiCAEuHRA5FM/YZ8Ggqq7oyrB18gCkLB2jVG+YMYFJ3FStIQ+HhVI5mXA3NKMKb5t3g9hREXXlMuVzueli9GYELbDHh+uUdf38Jv99btl9nX58V1HHrnuptP8wqipVixeFu6KUTwCglFTCI34AVGdzhFFOGEPXrBlOJ4YE6KDhcRCvgDiheMGtI4Yg2dfWVLX/DJ4nXAtWT4AlLkDUmG12SOomiKI0yYRGYJTiAfQAn+Xgo8myLXDLZGc4ISP1+zXR/O2j6cg2VEywkKuphVlpgQIl8AXNdIQoKfIY4hJRvWRTwdC+0V2myLCVaVarhjM6eFNa1wCiUAQh2DcuYKMfZFgKYG8H42IsbN9BGZT9/vg7++pSPonOsSfneApJBIKKYrFEcgk8McJ/RRPOGyBQI3j8mFjdwFqBeiyL8BG7zkq0op8L4XrUmICXpj04IScgoIFeZsOI0ej3wkI3MoCeTA3hWQ6FukW7BudLwBKRUED0cRWKTopVxGDEiAkonQyqxTB4gbttOAfGRIkFuFzdchNwpL6hxyQ4L8nDWXaGBesP/PSIKerXSnTdTNR5AKdYjgnO5UhnQBPJQEN1mfmVVRHoQIOAmzsfMoc3oh8pnRciAxBRTkqHGIFhglNBORPWEfZidTbWgPbPbiU9bWqzb78O6ETnHC1gJQhilkKrGCXC0UaO81mcMqICA3nJaQOz0hbh520hHa4TiPBzhmUEWwQvSJAz471yXUTRl1U4FwtLVvkLzvFvKHwG1qL0pCSFCfoNst7dztCXNLgfkkX2kKL3z/AXpoAc9QsuAOmFv+IyUMCSFMZjyGRrI+NygVPR7K9qc6YcAV19Rzh1nyuPQR7Z3JDEaQwk7YiCFKNk8gqPNIe2FSgsK4nXk4jkHiN0e9m8UDjJlP7ZsL79aNuCqCmtPvCK4EJ9VSJFbiTcgxKvbAZsWx4NKYpv66pz2zW/fpaO3cp+70FibJobGEMkz8C54kVkDWshaClyzR8IXM4RrRP/iToaYZov0nfzZ0TUu0Z+ta59mm1rhjuxVbFo+u9wemKV4ST7xdeH11fR3e/WrR1dWzvbnVCJ6fF4kx9BuJqwxETfK2Jgu+oBEYAYpem+muCgzB4Y7rXhUe29poaLp2I0S2bGfoWlvBUL4wMbqepm5POB41JzOs5kQssQgglSbKdKRc/jvURg6vf9nlHWrKcjCHKqOqLJPZaczcXsGSYpHv6kf4oA6SHUdr5reWNpLM2FDkt11EvsrzCVUUtG3DzBCKbJY5uhAHOAHRZUXdMuSqzw3OIlsu438gpRuRrnLxN8GV3QSjXCG+lHdas1hOrtN75GC0NPrW1twWlX1vXUOl2IBPhw6d2OG2EzQdW7JD07ZU2+m4J8zlHJSfOiQghnsDSkYj0EcwyaPIqTG40L6ANLwFC9Y3O6urx63XTBkCfnrlBFV0cgrLDhnie44ylHpkjXpSoxYO/XSU0THoI7Md6B0cZShf2FZgPhEJmexAprLXMI5wGZ+aLohtq18Zi7M9aS/rcl3xK3oe46S2GS7j3+aKKbOItd4XpRevAEVcwYo+LxhHECSNficf2Kk5uHLRRm0OfdmD3iaqPSIzTdhL8dRUGxqWXhB4bspzVbcgVMlp1trUW63T03qguu/Y8gfJTk173IyjRnZzitZZqWU2J3K3JuouK1WqzHhHxJ0frZ2i7k6ibt3Zjrpd2VOYCm01dLMvV6Epw24Kglbh9NajIktTb2KniLvFbjNurVR7Im6VDpkdHKGoVajFOegp5O4Y9eJU+xDqvYUY8hFNno/PUeJPNllIvB16768MgbLkmNdQ6iUUMfIVs3faHufXK3z5UBYflwHx/gJOyfQJ83IXc3u7Sl1tX4fUKmhXBMcdTRuVJbP0jNkM21t3Fs1Q+lTwE8H+4WIZn76sYe7hcGAmUGQbxUSHOZN69WwLrNNO0anPGMklM6XP0K0Ooo19p8w1p1FlsRLctXykg9hrpDcjdduVKw+6vidT6FwYLW5GBiwRW7RffHlLVejloH4RVCkU12gKxbQkoTiKcozZl0zkk5yUYhav7/IF9TugR7qFw4W0VYgofGTugPNcEbCQMmMZmr1It1ZW+TzNUUV0faHgHNbMvu7sAm9J4d9sxwFJkIGQ3fTmnrMJJt9EPP5XuOKc/bnu9oKLsI/xUC6TFJFQw4N2UBhTX6ducVOvb6dhOs0Lq6aucBruB6qrIgEhbGKIXn92x1HC3dpzyAcKH+o5lGnBf9F1HIHMD+M75FPh/8/Fk1Fx3baIdBRHbx968URXFa0+2JPbRlMo5lhW0Q8N/3Q58mBLSrO8UcPzn9yZ2ztw231eLB/yfKw3H/3s3txH/EdgOSnhF7P6hEsbNq8pjmV/ryv8vXE0eqxZ/awvrwBVP440L/8F \ No newline at end of file diff --git a/docs/UML/Architecture/RecipeRelated.png b/docs/UML/Architecture/RecipeRelated.png index 8a7148051bcbec8b6704937bea64647e92317cc9..9da002142529d9a6717f3a535e01b48dbdde93c9 100644 GIT binary patch literal 67481 zcmd?Qc{r5s`#-GZU1_(JR!X5%%rLfWS!Tu@mg|jA0mK9qolmWsT5VAxlIg zS*BzuLWN|HLiU}(;JK#v=kxu3e&4^I=lC7Z@f^qRIgT>-T=#vS*LE(i>vf(JW{O4b z+J0!ekdV+Wl#wA`NN5vBNN6K{+ZND5JCYg$J~sH^k@`ZpjYo!sgm(J+!b!e#e;1ku zMMy^3;GZiQC5S7-$5%$#P)11!?m;2@G8vxW613A9&NLSq#rdCmN)RRGa}d}$hz0?w zETgOkfeHR7DQKvuTL1IBBbDO$FF`5_5Fp@`CC$^B!S(@{SOWM1g@9&deQ*VCsDk$e zm;S1-)8IqT%gcjeNpV8cd}WjnD#~gK%BrCG6xxV@F_BR+0M{NgcMAAGQpoNM!7I*8 zN45fu0UlR^D5xty1zj4rG8uI66aorSRe&g{D8V!opc)$B&VSDhp#)V>R!{+L=8i6o zOxl0+Czv+H*OB_ql$imn0Cl1%1?ftrpChUnyE#}P|Cy>Eh3P{B>-1;U{;PMv+r9x_ zlz*C?DSk9E7>bgNG8`bOyD*u75LGf(iB0u})1ed?1#Mv%;BV>zSI2-?G1hMWbSsFmn+DxVA3;I+ zY9RF>m_Q44(?G1J9>$1(b;eS`0ug*Y-4Sq#GTGf&&)pcjNbp55*)*&Q6=Pv+=AlkA z@^&=zFh+U#eUVd%?NOdy=%|H*%GQ#VrAVB8`D{FNm z)!SQ*5x~@ks#6WzP4t!AEWi@$TVbpa#>xnDUlf?TzLBd1N`+3+Q^uk(XeSk4WvYfN z9!?^8U|1G`EQ$wB18D^}aWXV=1rM``&MwO8#(o+aPQD%*o+K4@3#gG1)05@pYpTxn zrg>S={3!^QDw;@O8&EwE1Ot>ZOwR)89O#Nb;E-@r5>wv;XAHA~tD+5E$#?@lsv*sl zfaArLlbKx8HO@9g@VRF5*~=bDY>bVsY({`0Jb}t<>hMO;YBq=d8q4= zu+Atm2HFK>1#>mV`&r@%Y-eBv`Vb2xAj-hP(ZZ4G>V{FJAh3>5wgHW(XXdJ8NM>1~ zF)r2!D%uLEZUj?8`8Z)U^pVyCU;+p~su~ag{&|_3GCXlU<}RKTJuhQ@6dG;CM8L^Z zcXbRIY%T(iH^m_X^vzJpZt8S|n=>2Xtxur^n5gR`)dJnUAq+2d6Bvm}q@xT-UTzRD zBQlkNLQt%Ia3~1HO_}YEQpPY0CbSArE*12#I%0N%q)7a4r7YK26a#aED)W{J=pqc6i zy3&boOSYMxxv^d#Obr@9A`8^RsU*zRgpGy?=0>#k1qHpQYSN(ghR z4;rYlJIu}9h=zqwH0bI?LpNg&Q#ETJ6EzJ-EX%;#fbMJRXMl#mjWsOHjS)^X0-5TM z_H)v+_ObMbVbNAzeyXZofl7gvV5}})jyPqq7Z{Nm1VM8$W;h|?823PR0~MINg}b4p zkE^4BM?fH69Yw;x@Jzg5J81-lqm?zo58~+(Xbm9{Sr8CZ^nD#wH0X3F&~ui*g%bj} zdVQ7#n?grhz|0A1{>~I5DAWb7Eb#Z1Ogz-tGSJV-)55@5)dc}__t(&88GEz+;RF}7 zk};J9US{aSt@NzCD8LKr(^&@8Kz*2%8k6Koq$p{4F&s_2lu!_JB`2f{!_vb~pJ)PO zW1PGxUUU^xoIVU{9EkH#aX0hvF{4sF%$?BAXgnG8?B++rQ&s(3G(0_wESYGsn}HG9 z8|Q6eY-;UD4kVL&kmgoiMt-X9E-;3ks<{!-nW@60SYo|QFu;qr`$C~`KObhGfd!H1 zi&QoY)Hgso8C$8aT=k4_dPaC_BFP!UGWQN-E8|ceJ}j8BI@Jr$!ZSTh{ITjt3uQBN zHgV4}F9MgiK|c7`l4WC@@%nhmn`N8_CO@;co@v6M|$;gb<7v zC^d|;sy>8lZSLx#gs`TXy26d=6n{N0rU?myQeh(nTkdGWaP{?us$0|4FdB~L;B6+^ zL)jm#%%H$j&6SYmYHrGc$Ixge9Lm=jM)JZ_{Pf@!WVV$+Jxu&vjo=36SQi@EMG5V$ z!ZI?!hFg0k>Yc5yUfxscGxfht6OD;E#8kw18k zYK#kTF*8E>Agb!2@g*^yt zxVjOzfLWrfJ=IiwtSD-(WTYOQh%|HZCz>1Ktg)&ZmTVIy7K?*8dYU3J?j9Ibk|_iY z!7&(64KH;z)C-F6@WGpqeMtfCAc`}+49RZJ&MXTw8wghQ1O8VP!L~B7R6**~*mz4d zyo-yGhlvHn&4XbC!&?}*6QN2}w7-*?JA*(&lNo{59*{tHca;F5m8+v42yX}!LW97f z;?=wnY?vj)!ivgpL4pQTEE(=(V1}V%tm#ZB$`@)4T$Mf{5KAOlK)@vbt^|^*GmC72^K(*lcE$NXOuSVcS!8`COJCKSiK4CI@*ZTnOH^Izw#3wf8%A!wSURpH zYUBOOX>Z-_jtxhTU5;MM?;z-*HV8|rJup9h@bt?g=x4MzNaaigvzBdoxl!*wE?$?9T{{^2 zW{5eGztTa99M-G|T?$et4n5be`9-Q^&Aa&U`Zb}=$AmU)+Zpv%ZVk&DmvotR-S?;E zg3!jjmjpL2e-ZQF+o!gyBP6u#zZy4eyKwQx=DnOvY)He^e?G(0|LQjMVvGyZJwRs9lMJArn3+XDVisCg*DGcV7RqY11OSF{-Xj@JeT|q{Dj} zbn`LD=8fC9$Njyx(Ro#JI%dKA=~@HV?eu^4__FB5oI}sZwEdfF^uPw})@5^JcBXeP zitN`H?4Ra_nymaqp^iP5?ZKkYcZ6(GN`B{iq4DWy!S-!2zLf9w_->lj-UC~~MyvC? zRxOm`{d$q4ZD3C>j%_}WUDLD4Rd;hBMyRjNeR0#U`c(Efy%JH~B`SQiUz=HNXUfug!Wy3Xxyl%B)KM$I0{biD{Q6T#+iHWhO8o-)n&%ti)x z)i0k?AKU*upM0h+V7#a;+&#A>o!B0HaN}NAt%6e@U5rg}mfvkgJtF>lS!ftB9_ zRzAS=>FtHh2TVGZpI&p^d#e)nJaBcsE#l5$wf+0&gLr*6BkW53Vs=%mEsx4wG1YA= z8g0u{Ob(v;II~>j-j;jo*z$+Jul@S=+@_vc!5>hRSXrD@Y}A}AlP2!|QsX$MX#M4` z5SggS2|m1WFNp{`Bv#`F#5V3s_uaCMf9|quUxs@!XL%U^H0eAmOPrPCbyf|YgiQb^O=dq4~6E?V8_TnQY8_Z<Q_bLL_-7`N!NWm;@YEER% zcw5fNwGH-ZnwC10cbvuP2Lv* zK7T`j#YQHnooWUaJAgg3Nno+}1Qt7NapV&gpAK* zU<;C(4AXSw_}z6$uq|MGZ;uH>EOvc;4%@zweEibX;fRdV9_*Ip+@NhMeG01)}rhNZ5qvOty@i#YL{1d?rWDBCSC{MNloZtH@mk%K4UaE|DP^8#Nro8tv%Alf~CF(ym8!}@EsDy7mKzu%l28y z9g^67t@5}acs};oY~h|Wa%9`iD?*!>jey=E^LBk1wA#}AUk-2ddGY=>TOZ7HPtfE( zc9%Eu;NQ))(j1mqscavzigBy_j;cTz;_tjYOK$a0nLa0&h>zT*sYFfu_D5lF&t9eF zPLVT*OceUif3|+_woghH8$`hVTtI@QJ>P%pOCq%XV))eIkm3zsyh4}LMB^zr)>)Sc zz?d#PP7tb$?D?{5Bk^ixtkXnCQ8sMm@0*g=-rIIm<{hqhzg^JZzqXeqw|NT+D5_EM z!V9yPJJZd0!!UvKe5vmB;{xi~5TS{h67otNc!2GCOUt8q5~7cmj|TArzdwY4U~uW} z6~WNXeGm^91Xsv8U@e7JuQ|}oE(c98JiEZ*v^1|M)6P;hW12tPMBSkqRyN*Q9M@aI zpQ(=^xp-RNsy6+b@JBy>i(a;>$x>*KJO{)+16z$4U)!z1`Sy-b=}{kht~#Gw8=e<3 z?q1F2u5@Q&=fyXMaY2m0y7FYwwsCi}L`?)*_@ZvJ%h7C$c8{!^;M*|)I?_|y28s83 zzlXE|tc}pdR$ykokN!VUr-LT{zp%_ll4pfw@V|)lR zs|K#m!PciirK*v@`7*b~#6G%&l+$&lEiHFaV7J2`Tn zghTN3S$K5s{g7o_Rx8oxv?ApL?A3^M(@4F;8Z$q1eXYN2w(-nJ-NW>|(RXIrYVI74 z7|r8W_)optx}!DdqfA_MaK{v#X<}2Fxcs9Tr>or;R{$T^^zJt#>$b3LiaoV6ZnfD5 zjX$dBZE;yCk5_BAw2b}U9WazseR(I`8{T{Jf||#PYB3!(t&@_eef6d0Ra-H{6`&ufZB=sjQ-j zAD?Lgt7WM*^WnsfeH{A3;&Ej2Hm;>Z2u{A7gSq}IP8 zj+{t2a`?3iOL#6M$J#EiWjDahO2AFZYhD^zzk8wiVh8NwgQ*Sxl&2py1*iK1#8z+A zuH2-hEOK#w67irYQx?9mPG!gF4 z+Q_*3Q9BgNUVJZQPyRZTc-t~&^vMzXN10l1(fNRhk|E=1_xrezp({HSPB}-cky@0( zHO24=M|%A_=>tUttL)H4cD-wuN96sM=zA|dmXF*&P|Q4Oac(4aEqy(7b<{y|Jojbq z%H&`oL!r~Z_9#0#bmh0Xxl~bwoFt=s-r{3z@GBEt)$-sMswkMv$yR=*QDN$%&9D>r3K8okPDTca`>5ES67V;wL+c72ER&SYkGRy?1fU)0Uxx*OH5MV% zR}5<*5YUfl5PAZk(-4;`zg>%shBaU~`W3C1RQ7IB z?CtB#pOB9UDYEQ@ANJnW`_drg^WSXhxh%V+sR%K@-rb2$&&G-)9gzSZ=I!NVa?*4hh@Qdwc{d-l<_F9U?qk&kbt-OcxN}Jj&Tr|>PF7s2 zP!C!dt9m72@Bg=Lf?H+YaC=;!C-f`^_n4NGP+?dh2%Hyb0PUg;FmPpI?t#pg`oX^S z+`isITJy;|%c89{xThzpJOa{E?TCzV@?2%y-^=@~@X^L1r*%=PdTwH_>+7e2@zOFA z(=YvOG%^<~#>*r0Yl}NM8K=TI_QYI=K`YDTp#yT|r;p1oyxgWcx<^O4|H+;EnV}o* zk=FrME7vy+S}zje$QD?>j}%pH-mV)ui+$OmJTX065vHg#^4)s1BJx?@A>=CEj}A^n z@Rfe;w!&J)?c8Yf!n7`o;?uFxOl{77RN>HFiI4e7ndLVZf|dK?-cX65#F7ZxEbU)? zyZh9fC%>w0+nEfIQ#`E5q?sCr*sQ7`=OpK+%VeN?m^xg>M)J07)O zdWz4lVu@5Xv1k2_?!xy~w;&IU`v1Ch3+%6d&JC$2knpijk>LuNlgk5@EJbAh6WNNh zVTwY0rt`X8dDpEgX~w*?<(MLzUoCSU{}jc`Y{;af2kKPCp)gG{iu{o(PU|dO(Yin4 zfJ1sDuf1MoeXN=Lgtu_zrQCaij87hivd>e_{y8L(0QN&h{@!vq{aqpL%DxkFYwOmM zgV#-O^N2~JzZXv&)ebD2Ir+XtDVL|piM{3U=<%}5lbHmE#^G`j3u0_{t-k632DWyFwtw;YnDUZV0a#`Ekhsr_+UgO4tZ#PvN)>R~Kf9qucBcFRGWLo74j*|7{|N2Ww> zTM8OXi?grOX>CR(=GfbG99di;3V)W@bgF8aFc8+|n!tJvYg9IcW=zN+nte{o@aJCo zpE7G+drOn%thHynVa5*lk;Q-C+=n3(b*(SQ0N7|GfQ=)(MwQa>i*8XzRX$;T3WbxU zwPpE@y6b#Aq@A_);ua6Vb&E`q_L8j}JN6(x`CY^TOf-Gt*dnjpUfm|O)g>|oPK9OO zMK67d?PPGv{pY?Q=aFzSHw7qUGz%YYrnX zcDF0qc;rzJ_em^j1+IVmX0?YMc3*x}s(yytjK>w(q_*vLw5pNRRlL!nR(3(zEW`B` zG;Rt#pZz^$v~GTnevp+|oUvk1WJ+koZ>zx+sc*W!q{d6;M7S+4ak>#lR@c5Z?%J#k zc{WaJy(;S@4FI<-I4<=qzj8R|t{I;&)qGj{)zju!+VX&J2l;995!Q^eTbPqAXApPL zBxx?g0G}00M3|8?0!L0ZCQnO zMbgMHuJ3lnDlsNI#b%=5QQCuq$0M3j!BcwEGxdroJ{?)-yrUe%Gw;9n>f9##+Kt_v znXD7&v~qkEuR5ENJDcGjZkM}SvEJp=q+Pu-$#sx?WG=_=FZde$cIvcl>~L+COzg;L z1xA)RuiVr!an%YtKew2S36V8&1HPTIcg+?@_=Kgr$s z=FS8a5x=rS8tev3 zT!Z`<&LvFM&2-)+))&Qg2vBa$F#u`}e6L>Ud>8$($(Q4C;sAbSWW>#3TzJ{nxv~6w z@`v9(7u-s6QXRu(<&}H|2ncO5|3$Q1F=QA`&(2%r9M)B6c_AZS(Xm>GsOs*?xZ z#BnH$UH1Mty6m0)-#tY4484O*Y*4P{ ziESUJ>fB7Yn}bU`^tmWjy;D;oxlDt;HNH0aROsXCpOL!ul5&%{j7Q(nTjp6y-Tm{^ z*XsOJsYD&MnC2Tdbya3EGm_wLgY@dvp zXHZ9m)_%3qmOhacZRCg2$3C>58TJ`pn%j>VHYu{-8sjszu+^)J2@`8`Wgv58pP z4>TMc;kX+#UbbO|XD?c-Jj@YQ$voo5(Wh574Q;tCJYrejUa$UH+LBlOa|+W!+O50F z#qx?A<3*3xUu>>%S@DdSsy`ics82#Htxe``Q)ZB4n~6_e&9c*jdE3wofAs6LuWvs+ zxf7jF+8834y&rw!>v6yd0oXYI7WD*@4`9Lh^WC!j#^Jd}(abl*fz4v3p-N9u_fi`l zomTbuZaUWfGUI!R5A|UAmyFYS@iHN8MWSw*k&(MkyRiZBIb$8c%UtVS8}C)Pdqe}D zyf?FqwHzvcnja=6Cp*vM+d>chezNo1jrhmQBiVTh6K_UyD`( z-ndpa%*O0BpQtPkTFm{hb?Ag;&F}O?Px)vZhTo9;1R1%%qPs>trmVZFx_q%G2&*B# z_`JABJ~?!4>1&?6xdM8Th$K=u6(p=I@7tF)1;M%)KDLT3XhQwiWlcMa8H&}Hu0@7sPmazFJhv&%eRN6Qu|Vcjo){;=BUvZpjfsh8 zR4`^NAvW+E90c6+9Y5nPpB8xoFF&hSbnUL}D*@3<;|~2ToRc3uPy^d-&&$-3QL}_8 zx7sV}+#wqCP)2qD+gaT|ubYWEmlzS{&WIEC6XOsUf+T0+I^_OtL-3Z?URiU3=UXl7 z*G}!WH%j!^2B|s{wnQ}{!2F50|4D^s=~VE<%?45vfPi!Ej^lwEoFNbHln_$ zC~kMs%qw5$*e9YOhOH<&U%|{vu?3(7^4%GGUbt92r+#tx7H>#5Zi8SIkEt$cce4(gNyj^bj93i$5_`Zy3NP8hCj3xjCQ+yewYv4#y$9MS_O~? zI{+fJo7$)<4hI@?csc?->CrzHcPEVP_Awf++b^mdaly4DW&OLJv?zqrKaiK1*rFn= zoA@FvwjoV6s$l5z-v$HMzT<)$l3&AS^J^u~6rMe|olDSs-X-o}BTpNE_YKMAM(pL7 z#m8@Z9v=JM5k}Nv%C^$4r3~eJ=w|7_XA`caEW<~1;#rXnUCsOBjwS4wXP(%;f5k58 zSa@Yq?6YO&XzDD~*z@L@rT14lw&^x$hBx_NxZj==XS4h?c;CviP`$m^9fB`MpZ5)i zo=UmUOp0+3wGsCtS##T7LOlV3(SMi?D2~K9zzESC$ z(2b8y@b`;MM^q{ng?iuTd}{wWw3xXhv8mvUTED~|_B5JK#L8y@c${_3p)6y5y=BMt zP#icgj7YoZE5=9iweJVMhWAXHroMT9I}1CR6QtotkG^Ez(uW{R)_@}x^yS~~aLEe3)^zUsu0N@_Oz#7{=Rv8z>`%5!Z4+qo^L z?`y0)NzV@z0U3tPEjvy&Ip61ag!ABLoZgVdeUVx-MkQ=Ni$2TZ+NR}9>AF|AmWk6r z(COAZPLY3qn4HDf^h-*4g~QUCtz~X#VZyzy+BvSdM@cUa1@Xrq660(_%lU;p?dS4o zt42*y?Zb;d(ieD3%<&7U_jfA#&|N^_&aE*$APCdLfTK_PUK+TFzu5xh*?cczK=*OWcF{1*#eap(II!hf9Y zjLaNJo2ef!?zPui{{3Vi#BudYtnhM3R1I#`x5HeU{Hvp(si6GdwE(@Em<+QTbM5S9 z;@EmcS4(+TZ_x1poYnl|jU}37M&R;LjG?vda))n%msacS)jc|=>^VyVK3L`4Gi&Wk7jqYG_VD1 zec{PVQ|`j|@|wZ`QWNiso4loZ&(4azQq?FEAXV}Er^|&o&x2%1oD8E?V%c+;?^~P?HB(7IPGZa zVSv;AU!pfxwBjw2#7Qwd?=%&td3d{IMF$I_v}@>t!Lvy&l0molJr`2sFYXV@s)(vb z^+x9Khwoqp3j6wSR=0yTNrY5!4wqKv$gevzu61;+-il@Z5M*_`#&Cm=UN!yt-bNTK zTv`tf&>0#m4BGTlIA^V}>5Xl&MpI0>>g)>avQ8wCCl2!5+Q1$CF1>&hnhSv3iK_G` z1Rd>vBy1hEH-E-FV4RPN_S?Dc_B!~W+%atZM`q2#XJ0O#jom>v3(GT?c0TAa*f%TR z7iYczt5lTb;O0jkogWIo0BDwZVtb)&Xl;uGbUG+$sy;u$-Q~pRp?tSj`)5H`Jsd3mSvyM;Kzk5X5!4cmCn2065eKw?*R~tU7B_76y%j;FLTEV>gx=9 z2Nx4P-(;F5>nt^lW!0@qgggnn)BT@-%x8P}M*#ckmh;|>WGQ`N*Kx$60QGrpyad3$ za25A&EraXX5xi>78$hU54kg;$kn)k{#JV^2>L#i&6hhJ-T^g*-dd8?zb2|7WMyGCK z(ya8`(9G?n^{izgKUYyruAe>9k|`i_2VT}LKNjs_biK|Gjx|YKS0rXEU07Y6OVEtIo(r3G2cqM?^DL>__5k zI(7)HuN=^r^LzMNt+lxN486Og^LSx&eZh9FEVy(osN6Z9+83NW z_Wn#7E$5JZ1Wn{Wk2INwOvsWd?#{vWDb`;}MHwG);V1dNN${wwSX{L$@)7CbDd-B{ znWQ_*;!zm2ky45$`LN7Z!_TtCX6gx3$|7d0B)CN|b!z2FLWkph*m{W6^z6ot9Vg*! zWv6Zhi{GEpue}zfnAfP7{4jDq(Yp@yNOC3i4`y3?-rqMKI-C|KyV0n(h|`JydS_i5 zB*Gyiri*YY_F!JNG^e_(t@v@ep5hngd-IRo?^hQ&;k)1NPSAC-!)^2vmTp#x zW%-AX0p3dApgCZ-&q#EDBAK}>Aiha>9=d!VBS`Bi_w}FH1c+G&5$|lV1ClIpRn?DK ziMQJ)%YJ`V`f^HP{QOI}h!*^+V770{j+#Xq2K~eX%xKtsc`s4qYu2_n2Dz1UzFp!8 z;KoiPoT@)=z7)v|xSUklqRc9AvO9T_`4M0s5$-Ae$nsB^2-jA3aBO;ZMLdK{)Qx9l zW;nQIGyC!F(Qjw{S^$D@NV7NP1)V|imIm@zUwT`#MN&=^>-DnhlHk1RmFu@0dMkoB7Yme{U65=5JdH2;XJ!$HCvr(V@yI}yWY4Y(p5%wQqE$ss+ z%=ob0W{aX)MPhD8Ovlfm>I>q(!XH>ywHCL(EZ&6mwacACAHC9Cn8ED0)hoTgt2T;> z{N^tkF(+WyM$gR5D=qM>bc@8Sf0iFdIINCXM#v@mJ5@_^3EY|0l3d&MsjNV6@_ggz)ftRx-8)n>HOy$R0+sku#S21J9 zPS}KxEn*Jo#wd?xCPSIyapaYta|(aW%l+(-O0$9KO^tW`eSn$_8y$X8~+0_LnOb*@+2)J(&-Y z;7nJUMzrv5wV30yiDgTJiIfSw2$R!+Pd`NWDylM?UQPcjqg(j}WOwJ`SI}_{Z$~1& ze2I_qDHcGOW=V}5<^re**hX@z(NWyXMT7@ILVSd@X5+c_d8mWLywn~P>&s3^_J zUHKN%`^s~4$N4X2a{807C$;es54C|$1QbX+3y+EGovoEKWY8;_juS@5&dwSjgP)xQ+0?G-l+!~knP;~GYTurxD=fbY=3~%p zS--Q4zUvb9q_OVO;!lc0C-6Gk`#L9{9Mq|NIumRU3srht;q&e<3Guq&bX}cDD|zqI z2i5=VNi9}XRJEjSkv-X?ecHiHdAX$%Z=4zuRIX1z zb;h^B?hwa~hdKo+z26vQI8DpMlQDlXoQ9pwBfmaI4O~Ntef@Wl5AEuzjZ+=&f{J$+ zs2k82e$`8JN)vvN*BnO`Zc*u*5jzdigoZBc|=i5tx}hl3Jv}n9|9Lm2jkFz*E}-021nE z!wT+1j0I0uOQ2s>G%T}?c~&b=j9Q!K@4H4pa_YUQ(t}Cto`<{^wmzdYSpN7E)o@GC zQm6I&g<_BdZ~Mnj0pJ|Uy{J+itnS-Vt! ztTW=?zcQg~7VM@f>eb0J7PW&7iIy$n)poZ(4IpYT(Zq9ochN>6>o0mAPQ9ew42@m# zYcH4Ey^T9|JaeWpJwGdCS2VEk3l|;1fnFxx8|-K{?3iVo;F|=u&Hv0QkD;%gaa4XjH5=k{sE;b5v{JE%x&5uiZz)K2 zyLtH$Qz_NE%bjB#ujrlO3)Mlg6|VUO+1DJ5k924^&t0htE%t<85a(3bfdWwN(G(~$ zQu5r`U$NB7Q;BXQWBc1v?oIbZf$Jom060!%j!<^xPxZpz#xh=!QF1otGs4Z$)h4#Q zfxE9x!dMWv+ry_RkKte3qHHmBeEW=3!F)p)_Qp@=FUO1z$S?Q7NikEiV!u!EJ;Jg> zEJecH^UD3Mn?6sx7bLRx`eI=vF7>ldq?7LA{+XSt1(xfRgpxI0U4((~OudAMqV zLdgK&&>Kr#Pi|4&m5ve1Qum%&kGygU!N=d7+PXh3K7F?XN_ZuD4_`@ZrJS0VVzu;g z8y61er%q+h7=&YN)(1gm+sra_Px;(e^qEw2NoCUr(MBeB1p7N@IcYuMHqRc#U8 zv4qmvrsB+r0gxiCOFqLHE{w4wdWy$sR7T$F?cdS}CgH7Ot|XwPz5(5RE`on+3m6g; z%z+Q_uPw1+!4c7qK%!s(uMOC^-6Fj|EXSvtC6yIxf}ffWbgW(A24kbnA59lsEG_E( zIfUEPVqZqekd7$s{<~Gz*% zamU^8Mu3B>_-1-YFxgB22Ul5Lz2n3m4sHnd`XwcSv-BwTE-kMEq$AZt^rufEY#P&R zmbJX(V$pV9PSs;eorD$7)wf z|HIN2^Nk-CGX!<={-Dep%^fjkWl?V{EFV6N@SQ7_*99((Sbwv1F(lFC7b5*zT&qL6 zc58EQvD0Yh(BgU~HguhsG-B1-+b?Quqk3c|d?Y`x$oA{z5(nnkC$+io`M+xrz+DSw zFrz{M?Mu)bhTP|ajU%pj>!hWlGi|VzmW&D7b<7o)`*fQ-1tHgY={2>XqyUVJ8bm&j>WEz z5`}*OO#+NA!_7Gu{7fYQ)X#jlhj|^d7nHS0>B=!|wFVkfs-6|||7ZU6e%<}Jx)UxR zJI{5$li>2I`_DKm89zMnS$0h4W;`}fD`3X?A+Da;Z{>{hBW-kp^YLM6WLPz_k8cy0 zlGq^4gr=l08}0o2u2YXODLfId+R-O}hSk-gH6U@RP3S9);e?PYUg1ePz~( zdWBHkQ^il4dL?j=F-!H!&t!BK*QUQrWv!f+>(5vbBxBD^m`}et^5|R2{Mi?_!4>5? zyKY7{4)r+5wlpXPCdXrRGJX~=T4JkkihqqgbX@yZ{#=YQpZ_e4%N?;l`E&#(bxQH) zknZ{ts-$jUc;zN1FZkw&+{(iEnP5qHuO)xhNOyfYGW1cI;(n#qpGrQ1z|h!gc0}MS z0|3j{5G6}#!2ZMXi4qeE{rgU4m))8XLu1@lXH3@pI@^Zp0aW`4aDny5XJS93l#@dV#DrE})Jf6Af6 zH%2sL-awDTT5^HJfh_Y%9f>{p$^2ou~JkZW65XLy!z}LDWhN89#P| z+z~mD-GaP2_p(K_G^-rJDM%I0k1Qjca}SR)bGR{Ld96m4#8KM6xXN2czviLb+zO-? zc~+&P9q#w{OR=KwR0Ioe>GfPm!q}_PJ78A1hcr~r&Chv6mo`rBnF%)EsIe~z1$S(b z6mCD&Qg#5+7caV&IoeH=zIgdsYSBm(aPwJ!=9vfs+1It zYW=DT0G@Q5b}2J1X!-Yxx;bgcc3lCunzIXYoIF$hW9B}icTd)WeiO^uEwS` zbpWX!f^bm(6l2#a@D^RSQZT;seu|hmm+%?qagr~N!4s-t>C5hPl&cp10);0N?JY{< zHnYMJ?O(CF$FmZS7{91aOZL{6lygH^)W0Y^az^2ViLh?(1VEOV*@|tciKqK4t1bKA z%3fVAMaBES%N#Y|sJ8DN!B-C9UJkO?r6cDt`aUZt4`h;QWBFux0Kwyeruwe+gA8 zE)KtC2~KQ-f}agZ+!p_u@V4w)3dXSfA_=7aw;vZjp<%|eBKI2>jX0OKI5(tTfS!k7 zsuTfCL?b9qB7ggDCBU^uq~WU5MZ)D0pTCrt@v2d?N+&oPSFj61wsMz=`xc`Y;Dz&TMfGbHkeU4Rmn zC4uv|UB%|CQf^ji21}8}oXk4{%;K3dxx3tj{x#yUe7-}`k;1Glt7}ps+;8ts{PhP` zNC3{E%m|Ow+=!{n%k)k39X^lg;!8^F{tYVfX3_7Q+p2}jQ$AUYPrv+dPc|%JuX|Vq zeC`ugH=vbS+hTvFGlJ?wWHr61ZAujq_3-;}z1{g$7iVR>`bnftU}MjV7Re(o+v42i zV!jD;KeVm<4bsI_m-(z+*551vi-`Q(Ak9x$MzziqcWHAnwOzdP9v9K~_fdmRQQLn? zoFK0KbuD!1$4b#+8z`g2D{Lsz=Dh07cbm-Mrua@SGs{0rSJsV~rr6da4!Ox^$v_nQGCmsHt_{S&-K1i$@D|})e(E<;elIrKa>#YComzi-?DV36oSv@(Cp;Y?( zj_&%bu0v2(hI)-HbIqAZ&Kdo`*n97&sFrSfR1ptgLNY2!&QT-?2#rb*Ns=>-k|YaA zkkBnAGN=ehkX8_oEIHGN1PPLZWN9);Xkr5$UTr*{@4I8%dw*}dci&&{{&gIu>D_zR zu3EKft~uwz^QQntF+oAFR28!fgae|=Y7zCg3s+PgX7AT3_vsQhXkb)t06Xc^wZJPW zEX%uV`;+N$206%mfIeDry$e`c)9ccl)c_Y|n)KQ=GIx9@JK!02ASfbfIO@DtCZCDt z&q+zbChzEL56~nW*oTT5_1q-YbeJshPtBup{5k`7t0!mmwdcs8RS~BRaEySt{F9>PIU8%2-K}cdCaX#~rC0RlK@p zRszHHt}72ouR%1v&9dMP2;$X%6urlVL@d~X%APu`W<5XYe4`-Da`EnHizH5X)U%{gXhkD*O{`a442CJ^{py=~fxEAb?&50W^H- zc2*zl!lqTCY-mCIfib2veJ;nhXud?DqZMvsV0Ue*7e24Oo7|Mae({oC?6inSs6rI) z3saAS{wWbq#7JZiEaOP?2r1Vs9N z%&?rHpAYWL_`?NQb0H;XjZ%yZ1daj*T}JIB^bE`_;I4m~kM#Yu{YXr6cB1Xw`+^tM z_hkPXektqjDe0{DZu8zy`Z1BYCh_3NJ)_`q<5gu;hGJPi75dTeNR!9XGk8>OB_=1l z>sfN0-tN8T`40LP2p`E(Svo_x;ou?^TGMqr>l&(VjDIluwMhZ3}EAz;kqLN4*`V}-f|qar`2@KPCWyv75QR6D}tmGB-# z)NVU-6W#?8~UZ9Wm^TD-%9+Bl^c0-AhPHlB&yqDgbnppJ-oTQyt zMnpa$f+b4`oU99+e^9=kvsykD0vBlcIrTMIeR9Oyz?nW}eJYIp(qEfFtGwfBhWXDvw(a#qBlLHg+ya-) zY~ceZPXz{8Dj`XG2TKrIS}+iPnl5qk(mhaBel(=|=x~bzs!3_pxAX%LfCQ+0S}E5| zR3aok^mA?22OUc{*l`oq+@NFAL*G$|Fb!24ZXUx}8^1Yv5p3Xkgrh^Tjfe3)1=Yku$T%AtLX?~>C$>;~C0#s`L zR#=Oud^cj(!>QS;A?7?>lwN^tzR)h^KS3)q7jB&Ig}Qoudu2U!;I(hg8S7MWt}y-R z=vxc^3T?B>+0K#X-wPabnD_>H++v9D{NMf38?L*!5$t^DwbynGGfn7@$%PyaVFbso z;~%k_g<@ZF#W|A%sym_wQT^qB?N{2wyR9|OR0m&7kxUvafWy?-M5cBz;i7T7`D=Z3 z@WzAhyXXpyo~4)F*g$3CP)k6Xg6pgPY*ov?D<4)B?pL8TaFX)N7(y&3UOyw$gw!#x z$*VHw!Lc;hH3{TW45G*gvnAzNc_V_ZwguXKx_RSy2$I+|AC64nz?+`>7Qg@&C#2iI zBR^X1ZE&dN@NNo(8?=7Wi;;j8_9|VEkro9QOR`-fn_BWCa+E+ctH+dAliwv83AzSTB&2 zZH@b$$UUZOh{g z%?p5V7m|3#3E94jCJ|b78?ujG1NH!*nCkVai|>;jojuiGu*#j(n{@jEQHF6$*82%O zPYrY)E34u?$lvXn#4472Q_8;R1%Sk<++}r3mc9F#h)bMxF3%@(Y0v^e7t-QoXh!%H zgg3H5tTW|1Q|XTnK=+f@~LlY4M<_?HxBD zRJNWk$o8{>)^6;yA?Ak z_+R9A%o^fkZTooi%520_I2;Z*a)81EqZp%uR+3Dq_(YZNo)4&vT3Hd3d4kemcB5VQ zR|XZ70ySQmnB2>@h0|_;0{On5r}lPo{JP%c`u2f$zi?K>%8)}c4EKe)O@SrNm8ca( zxaxHR1NcHZmn!ZCZ)gv<1*DDN2|74Yj{Tkk3uWJYGBs?biz4qTbv8uHDar(g}Z zQv(#}^U06RywK@!qx*fD-zO3LcGu47sq+uaZ?{?;fA2JXdX$p%P zi~@p^-mkIB;xS&PT~c$*;}v2F;aePMu`89c%_YyFT|1&2!!|$V)+93M{F~As{r2ky;FbD!#+kcD}*3VIAFZ3hc+e(Ou6!ei_6?tU- z;-Ym9=jz><`d55}-uSwbJM@(YD~yhf0`wEl?ZiYN3GOU->VFFReQfZkVxX{U=NWCntI`J<5=CeWsx0jQKow9N6MAs|tGQm-on zCdX0Ajz|Edj@{8c3zYW(V0Fx1$!w+vZZP}D4?lkR4mhv;cCb)94TzHCY5ymp;cN- ztbmb)MV-pP%7NWhO9>IkNoIH8v)=S_vq4)Zfx9%vZwkOZwqakHhhqd z8P`rCwda-aZ*moOZVs$?sxPH%?}paVc`^=Ct>Ah&=YDSWD6-0z&fn>9^MyD7s!=Tb zB-|%QNIQ(ykE#bYHB5!to!8E8{R{^>Lh8iFq2Pe#3yy8g%LlHdHUH2aJs{pNpXJr{@vj+%WK3si9)aSpI;b6 zMH@%)|dE>3a4PE#k7S z{osE2&c2DGn$3VsqxO65J9yfh?EAXOxqIRgJ>ojk4*Rwb5Eyf>NX^u(xCtcw!hwJs zhJ2uIEuPJhc7b=&k`e-n*JDUO6i_F-PIAF5FB)|@ukd?bs*LP>@Xm+L!Rey|vLmb03na%^su# z3Ak9N&5xOvX=Y+gl5!DHu2LXYiUEAHEHi~cMrWe`5-i+fc~;MyYLMfoakmFJ@Q8rRQI6?i(uztS(#Rww)Y#S_@{@Cs3DEnO!|2T?S@WB*?7z zB){~DOB{TRyEUvNAQE4~_f*)vNZh$K;aLRJ*`0$562F1#_$74zMo$07Lf3@*$zyx7 z_By!q5ub(b4{D9waj53>=Thv^4PDxIG8qsEG9mU~)D8(57yMrs^t|SyOzr-bpbt0` zDSENU@6?v{%)tW48JyAfV!BeyddyG9CA4OPXdT!34PlY%C1s20!IrW(C%xTx;cbcQ z^v_Ykg*&r@%FEUd2hLb*5I#q)Z`P#YA}Ht+zSFk;yM(3iqsO%RQvscLQ@f?KSxU4+ zik3OZmH$0%Zqg#8F7MEg3qReUYmp7YM26GZvo40xr2!am5<9zO@1-s;=}`PtO`-ahixe-D_l|jQi z%!N-p`-2=l)FkgTg0hdfA@{K%e>0e)QF;idR5T=he3Z1$vZt2==T|uP8)x(ze;WJo zX(Rh!&6&FWfdWQt03(J0ypdOQHE@IG9Gav_XC9al8ZmqcHtIB=cD~LT`Hl&3SvDRd zfnK+5I*FegMoL5E5tqeH=PAN>?nk3mC;|_KF}=9j&^}x_KPJ8p2_``ge8SQR#ewst z)EztNd$3Z@1iXpvvj^pepg;wF-^`%0OjL5ax0yU{Nnc{MD-i0H8i&Uda7UifXIf8%jJoSpmP6R&a$F?eLI5t#w3zN(0!Yj=T?JNc_j86CR6AT`p!L?xapr65gqFm zoC?k)TORds)@?k5z4fouPSidLQm;*BDZ=?oNIMh>AGJ8YZ@W1@%EHe+H*h7r+tKf0 z?%8QqBTN{g8$T}r^$d~mkPAti*uK$*Dq2cNMCH~3o5q zP02IfYq*2PT?VA~XxH?_GW!{OkSei@f6xT;!ws4r)7e26M!dz|8KrKpTSxhy$#ih) z{J>CGlboK=*FV|hMDV~sK#SD7uMjcv2AP=1-FNoYBRHQF?_3oViv_p73C?hgM22mA z_&sAIR{$wWI%jA>p%keKB>P4{vS0R;zoB3_+U42xzA4$l9TAPjq)-i{^0mwTsqzZ1 zHvmDB!L4r3E+MAdgI^#!_frNe)O~+s8Qs&2-Yl~np3U<{wwr|22=P#&n_h!FQg~4I zHe{M~M;-hC#o`}xI4I47ETya&YLER7IhWO)$uQU}&|Rb#I=Y`5rT$KFK|3!weeBUM zibQYHq>#7BrW~<5F5_80RzeBcdv`pgy3Ajfu$Ycqr$F8bm=%Qci&W0M-e~NpDmmdI zQ&w8-LMTR{U0?-mUT?pCou7pYm4*Jhs~AwHbGo*WDe$U#&AM;nTcOX0c#C%+yd}GE zFLVbaSZcr@N>)Xha?49BkCw`Su1TsSP~@7RJ}AjAsII4WsT1>j z`kgS;PlV-8R`S~!|N9vKl-xNT!=wYDeSr+stRm6ac=2+#&b04uUh#Af6`nvs86002 z*_5jE-v$f!oai`apXe1WLSUppWkLVF_O#4C+(Yr{ge&%8r!Pp+10N24@6|Drly9H3 z^@u|4%X4&ALl-yKw4awq?n;WlIGT-K9(}@yD+&e?N5BxnCQZ&l4>mm$QWPH;`ucuo(wm_rsliAz<=C0BcC)QNp%@sGWf5%zzQxV$5sE zLYbkf>fqaaQx3*i!yqb!4wJ_cecQ0$;M$y^b6=O<9@#)9;6q-f{_q-|Gr9B#vxkf4 zHdq1K_T`ttOS?NPx5kaax8Tw$5d+1k4!NfC?VlhgGDU!s!#O!bj87bTS%9IQiQ(1O z;&}m#RP5b<)(7>1)OX|4o?5cf(9X(ed+29ECyzm$mZn7BDdC}Bo6gt5Ewd?>5eZg3 zalJPP zs`qXqbjbToo^ooh3p}`e)QMm+1QoT@DY3f)>Y}y!Z^!G#?)&_LWd&esNy{a2 zx0MjgcQf&MWuFLj=98CDufK}Ed$Y1MeJ>|kcu~L7^5e3P%pxl|HKgo`J6BjQZS44ASCsS=IU?VJ1x$LI@+Cu-nEL79wWReL(McnpWCtS3`ik7TtvjKUMqb zGj}9 z#E6M(_xpIp`GZYC(*DxHxqu_X@key7iN+(Ublq!+-RhPKWP}sL&94C|3C!ty{E1`!~Gp<*8%E;gaj~9u6ChZpeKyJDb zH9zbVF`~p&fc7B7hG9(ce$Ctu40_u5p46@w&`637J`9W74E+NHXC7>C7>1|9awROZ?qcPrNR$^0EJzf4jk+%G?5MTlrN^R|1S2oyB( zMqlcMERz%O_YRP8)!2vRh88a!?`{==YV zNx-?0=#RC5Fd{a({i%XY@d!=YouX0JRoYz~F4TA668C^DW+B$dl0W`&v;4yp)KadX z5xP9Ith{9?%{Jc)B$ojtk>G)N{dZQ!%~rqU(1BxBX04MZqKIkQW9lj&tpIKS zyB_hi=&w5$mfiSu*rtBU7=S`M;=Ko?L1fTr07dc3MGH-}Og9l~b0vgptJoZYa&W)< z6}4&6Q&vET0@Kq20$=%&7|y8QHF z$VMI!kMAM{0C@`r6ED0(s)N6E+uF>wE!6bhn+>2%T|<))!*PIwZTX-%8Ie`{azeC> zMNg_F{TcBN%jh)kb?+W!rr1owX8+V|^EFoBvEzuc`$hN4ztbVLk}!7A7oTLRB0NeU zn#*A&QYf8Spa9!i{6)2Gc_-5^$VuCBe4413ZF}H$nNtyY8~Dy_XQqR?Eaj<}00Muk zwPG6s@I3?dBtI%^h6vZMq9VKI$2V1V(xb(iV>qUD7u*7-FWA!iylNfOdy=~xb-%A` zegL9PZUWRkSz+JpoO$BXeK|wP*se8*wI~E#Hs}Gr-w80$`b0DqGVZ(1i@1C(a3I;v zpC9FXius_#7_{@s;o_04*n)uc3c#6cyPv6W8@8S<8tCvrcqQ!t^czR}M2`-<#tz`O zdXPD-?GS?K_2Kjn@Cy-f;1^2r*NnfO(~z4x+W~=!M}j;dr(AyUkN*j$TnOIVz1w;j z`|(RzXOX;xLZ(rY__V_t!#LQ0`^d(8sXgC(2+4djptJdH=H>DThXVC?N3z86RE2$U z!(|t<`swU$4rIOFIq+=|3f|LLmd|IUg*3`HH;%c0+qDA{!z8K;@I<*F1?r3}iIWCY zDEs5(lvDGbo2~hehAyj{ReNBjgvv&JbnA8>kug2$wTm710>qR&9i01HZMw?{m<<5< za$fvm8UgZd8(?p2dl!@XobLX4jU=8VZ&Q?qgFF#84Y`q?K;7(|FW0jc+D}CZwt3BU zB;5P@;&e=n`DLc~y6N_iy_PM1l(D=DdTGf>;dok)g@bAxkqpQtB|D z)Dr7{-O`=j2c_I|k((MFu(m1tNWKnX-wrAta3E!p^Zv!Rxz$wTT@?Fl;v`Z+_j(H?9JzRf$rH->eIe)6o6?jL zr!y)Wv@zevpD35~-(Vfzp!1|UhB{?}hRhrJ;{x8%lC_&p|KS3#7&ZfvR9oxk*YB3A zGD0S^^fDcnCo9~o`IUr^mWb|x1g42dIB4gZ@qYK($Em?ZZPWm{BrDkU_EyB=$hVfL z*k~G9mzvAVpR&H|KO40MM1$-)T&or{Zcx>7+Ze?ElKe1p4%Do?0ebj5FFT<`rTW{(?@;^ACXkXYlx*U znd!^jW8Lxz42wme|2{AXnmj7w(TaUTgif<@rO(PPXba>r%LM@<->(2*)y~%K0Dx|- zYI~(-gVPz8b?t5iNNB@~zjb72Ch_QmWY?-A&~M0NL)kUw0J{t~Z8H)7;Z`qXRp~3J zl7<)cTq?g69x8}JYS6jU8S}iQt~UF%`k44~xngB7*r(6(_;bbbs#hFTf851P#{l4;Kz8x}kOgmy4O?u}9+i zbrq9-9g^)F#oaJk>gt+zK9a{E;?2;ZuK=>8$)OwOy|)8K=wYvRhvb)CvQJvLJ-++& zobI7%+qA;b5jU~`=q9J30dzF!C52=CKJ?e$_-fRWi(U8HTIj)mGk|bf8X(LUwTmRx zFt0ag_o$JuH-raRmsS&Tuh~?d8Kqq;l3rabk-{lp4k~NO6>(nE=Rz6A*}5eRy}sT) zG?0A>Y7uGHz<%qHJ|OgZ=J?yVgS`-~h>CO$mjN2GDIRhpUUv4@4!Wr!0Nl@wmB5 z=Z`m)@5OB>QUSA!zrvo|0Y7R2B-9H=y>PP~{n8JB9hE|YH;*j7NLhHQFNj|Ddfyp# z?2T5GA^(!XZX!H&es?|nj1N{P1;7}0n_5G>w*9A=w72`I65zN7CLUhP46X8ro{wYc zDT7~YD0?<;qdN*0={tOZG&Zjv^(4D0yKSJ0kd37?G`5?=LQm_7p%gAqV{R;VwiOZl@eAA2-(vz*Q?_ zaCrZ^!J8LUA3%kl;f3+nkqB!{=p84t)Z`QX(}Lp<~!*816n3qe=xJLw_s0xU4j z-}?R#+FcL-2%Lm*{veO?1ML4hnm>_*0+Inf2e}Pgc^?AeCiobf9of3wK-fSWP%pE8 zHYTG*pom+UCzXk~KOci!YzyS&1?Bl)A5aPffefAMWfs{#cOnFN)nX&Ej*=0$*TJ!w zBto1;9;I8gZ?RmCtIJnb4q3iJe9)rCuP44izkdHV9jt@tE(bblv`sdOM z(g2o26N0zT8VenzLc{lB;r#S_(@?{UKhJLlt~yb5<}3SWs1FafV#Z;Ag2S=-4AM|^ z)0K?BD7WJ4As=&dP~iLTo(*b^a^n?D;qcqPAH9|v>}z?;Vk~6pV23j!v&n`={r6|# zAkdp#vvz!}hy)M0zbyA}Lly;^D6E1%)2GA1Nb@9m5*|g`yg~Nze|Ff2;0#-Xn}ri? z&Mg1CVZgYZ#tgFi3pNKg|nP7qGHEUEY&4HgSw`(hj* z-Tpn?P-VggjBYj+9vBLV0DfcFe>WMl1DEukb0Gip4S+7<2Wk&PW(-7^{_D}ecP%_xxerZe@%`Ea zea>bSSkO%ng#lRA%S8?~pPT^569$qCUGo1`hyfhTP9hPw)>~d9Z1tu8xVBcaS%hvm z?3Q%+TCA+V^B(i$`yNzpPIarF(1+aDK1o&I51EfQ9ZJ^hkvsMmmI>i#TsVfB_>(&9 zdy=%YrJU%Lw3qUsW5(}!cPa)f*|&&vgR^g`q3%Pbh-qm=+Eu@;`|g0Dpl`SjTs;_# zEW8Y`El7Mzj1zrRHMrw;lGCGw;w}ZV8o*0ziW4>qgNg{i?muwvN}y}yY#ip>E6&-j zOTeDw9#HB>PU_iob0DP0AL?O&O^F5vQsId&ac}z7F(`ZtQn#|dFJjM!v^vRv#04Xbb4`lpSPt}?(S&kR z8Loh|jn2otQ^ucRxq2szKU5@CEL2>1IY3{FqhklRI2lF{?hS{XPWK%xw%0E7obSBX zm!a8oT6*k`3eFYSyko)y^Nrc1V8AA?b;p5!Z!dL5l!AqB+OI<-xq!f?xK8 zT>;@gfz9d}7#GfmvYIaxrGm_-GRa8LWNkw3iIQwzPh5u`w4?Fu7#Kd7bO%2V;#yZ0 zz(KP)oDF(l=xCtq$%GB`#f3wTzD*D{)59S%E`93Vqx(!?Rv2y| zuq)2bbX8HVk^9n54(eN!Z9JnspZL;Oj_J#Rdh<9U%=S+lmjDq-k^@5q_@$4vrr*4c zInuEg05up$^XI|SAIC?NurMBUV%vB726f=6Bd)zdy5gSs|$gUB|SEdvw`h z?}%`sJ^1)_XEtj7!Oufx%Hc0`Uk3Y3lnl8iTQ@&h-wD_`G_c{=5PN&5Z;6cgw~$|- z4dP#3)k!hnY{DZJzOL8!s~oXh9+sKn=jb7JJ2)xC;mo%E!k{Dm6mRa|?F&KRJ`KM2kOr#Z)(;okha&F5dc&vo#eryC+A$jDA|tj8nw;t!+H|M;%Vg(vpF_Enz~=l-iig|tf| zPGVBSMQ-4PgCzg82?ZSo&mw$QMEU0XT`+L9KJ2Ietjd4S!pru+OJo< zQc<+JPEK4ZAZ9}r&Hv-Ch!(+Q{^0rt^xmJ}1aKww29Fm)U7oCZ3+Z| zCpq~{z31!#uz`fHS=>7I&&+!arrQDq$RI%vLRN?%@b}Y#?pO_OXI($ioHafh1PvD4 zed5tP!~gW`V4K>7vV;HTMg0!5Uy(TK|MOF+-2Ul_Ixxq+TMMxNmg{0% z!d}+Worov(C%(s8o4Rmq)q78X2;Lnj%{EA>Fvej2SRl{{ZKmk{wBFBjztAGyG0$> zF>?n4!jn}8xopKp+m2N}*{f5`rLgPni8Xa z^PK?=@moWq^5ODQdH=NQF3?ex%Pmx}6jvU$ck88GPc}cllpD6L%E%)E)p0(H{e8Kb z@#`(KZ@)`I-;GmwJU`QW$KK!>tVqlqcorTBdQP+O)025BetPAMtVoMvDNtW2(JXF0-R?4Wo~NPjrqleCsg&q9VVH^*(l93n&kBrm zem|>k_0y>K%Sld$-;F%d)tdgHGn*1=13-5fI^VyWKfcpj0`4$|Q17BE13Lf$V}Q_W zbTu#`f*KDcWwF$e2iem7zQH~!+5hT!6R&_H2-G3TcW2l>JY2M{LP&nQSjI@*{pjgN15Fx?z!`yE`AaN^Yh(g)D7;wDXit!P-t z0WhV5IP*8Ktnu`hnz8h|4JOZv*<#Z}Q$XjZu z0>yr3<%d1-YwaxIu>12%w12-r?tgwvmqYY~$N>q|G;W6n(2J^^TJcf9*t>~AG-Awb zJX|C#Tp`uifLH?fwN_?(qP1JPdpriLX5MM(vH@&osn(N!fd%~gjTKQgz**dc>!WkQQ}TDI z&&ntKoc4Si>$lX6fdBvJdkO6z5%cWSP0-(y0fN~J`e=Qgk){iM+z+!;48MQ@iTe8c z=R*aRG!`6cdVOg*5h>~eYa>ed=7x9P-Z8%yOmhA|zj&v#rR%RszEdltk+1K&Kw*dX z!bELlRtQR%cl+s2$fFs5fF!N86KK!t2kwD0vGUF(7#*UBeO1sVYo1oN_el0nnPFjG zOtkBswa{QAwxRhW+kyUS{RU7WGB72908rGoZ0}7xdxEE=%Ook52A zhF7g@w1u1vz!Mi8ju?P(kE6q?mg6roI%R8Z_s1QTd*o@E>E~GE2Q|1_q24JnNR}D! z6spZT_%p>^{(0-!9DZ5lN#3~d1Op$B`CJ;<aAN;^9^L&N`M{)wbVVsIk^$M0qHE2q+k@F9Y**a~ zlmlMuJpu}P|6|sjTo-C;QjwH5_3SA3NTXoJpiM>2jH+}sRIZ) zBB#9!m2sRW>6id=e%AQ!Jx^w0_5HL*$J}9#tEZCHSilsG2*iG6C5kPZ9&SEI zg7)Ze{h0~|$)H~u@pzXdM}uhaMLOW=aHu6q0Q-UKBUa?Yc2;9ZTNeHIQgQw9e{ZXD z`TzModjA&D7i=A2X0Da#S3PEK4euOw<@>Ywb+4^fOh+9;AP{cG;H&`7wD*7&O%qUW zm_oa)$yfy?Na^ZpC?6h12Y1*1B<1M2gTI@qjnTwtvxe4Xq7YShGZav}91r`Q5QO}l z5WxSlgy1`dI{YQnCbS6@NZb7WKoFuN0@Q2tg0yRLKWW6NAoi66!TiQA5U_Vw2MSTT>!!$hGP?;NWue_%_aqqqCFMBrbb-A7vhQxEnDv- zy@fVOlTN^6Gy=eaUGJ*U&%=y{?d;oGnHsAQkowdY%jP?>wP$$_I_WVGYRd>R-{N)al>0WcODmyBPa2wp&Tl-#x&lHZ99sSOu>4)#-s7+7+-Bvs3LaWqz zAeaZxLN$2q6m{`DfXZDmN5jT*ab7G&v+HbN&5^#q4bW>wD?f&wU!=facBLlv zi}jd=gG$svB}2m<5C*#JU5xOSM)4%@L7&a97!=+H`|~Na7J1747pODJp-BZcBft`` z**)5*?e=T?)uhYoa>~NVW}^A^cz=rvW-oB#Ca9Rc&oA%b+(;{E2K25!+Q@mL=22on z)ar-{{_YJxoz+aoWsSn-;k~!m_75ha1Bp#jfaS+~Pp2!w!E#Gq`GQ_U*Ds)_IB5jm z1zgG!OcP7j|*VnzU(jXfgcXv^VLq(o6ZU0q=dK_JZYzn;$gv34T;D+ zYU)Hg7?-Fs7uMlQ-f5N{s0PUlP@ll+tNRJ4;l|?&%4e;;Vc4mz~uG zK6Zbxd)P5JeB(_C8>iKEF2QH#OcI)f#!YV{0$h=(wY5D3nfZzN2`H)Dtwk~2c)csX zn>-(o0?h1C2lzDZX4Cwi`x{`{6p&|6A6>F=&A!x3gP9k$9W;$UA5Fb_Ql#R2#ng)n zw~d(FTrC0s&$5U?kZE6LIkz}$4M{o>d?qG|tozVph6x7CP@KbQ!e*&T6rY z&WjY3`(PJzw|T%Xy>)c?!dMv8QB7+cnc65?&UjU|Le(TWXgDdg9Fv0zP{!~AY4ZFempz1Fho>|7iD3a5`R&?4)w5n z?YT3wkMP_rk?%Nq()crWxZG{>#Ng*!-La9(^X7fI+=ol{;6^Tu(D5DV05=Ov_Zpz% z+!kD+0IEKNlyy6ydyNhg<YKl|BzwlO7yTmT0MZWJVBBi9#C`x8*)-+t6GC})f68FB4)O?KM zGVRqxUBk41cwPrJgmy-kT+3K>0t4c7-lEf4 z&L8P3U6h=2Aq3TQ7T05OW;uzJagY~C6XTgsW&>`m+7?5#+5M&#(&8OWdpb zqn8!&RS!wnL4CmjSpTMUw6ef<1vhP0`Hu&ijX^KD)?TSz;-7!+8>gSRDIhI;=@yoe zWqR)31KrDriSy3XVLR``nU3zfza_-sHYM#kRZ`FBxdxL7zZ)+HW{U8D71IupyFlC ztgu_winy&y#xlEbT|m#XPUi5q+rGN9+(AsD_Q~!lkL2mXtXN+p3AEFF6td(Gzid6P z8>*&D=b9GHhn-Fq6R|$Z+1Q2tu_-#EyLqctqj>iQ6CYsxsW5@UU6TVDCLhxAb^SY(5xmA55hrbGuNiX1P(;5jLM@2Kg$_4>pEUFi58tC zWkm8KYBq+@L@#U(oRE#1BoQV(;Dio)g_sqI*}89pu(*e>g=)5bUb0n-D*c&JBhDwd z!_ZjT)28f3`7567dgVuxxU<9Lf)lZYCn}{Vq69E4g$dW`M3a8t2J$!a#J)d+2&Cgs5pqSriVdd1ZW!WBT%G?=Y6(w?Y-|KPtqLxWc%YO??w^#33uumCQpxTN%*v)%sZ7tp}jg{1# zj3=N6g5+QBGsA%1SHS(|YPkSL^Bxr@zKC&fyxk=f-X{5dGTOkYt8I4Pf}tgo8QmwD z$cb>K8qy9x?D`P79`W(BM&B}jk zVyDu;hgJAs&7kYOEvkBs7fh^j%2N+m8L{D?D)KNMjnr68DT|WQH$RwR#>&1{A{!Y2oJTJzPol!B;xtl2U9q4jqXtR^pl6c)kTxAM#+)+hbr?O*4G7`@>28XW1Ad<~qt<)3xY(x7>AxF-hvzs!tnOv@j> z>KpGZa<`M+>7Y=xqj+=ZmA*y`q$zprzP?U9^cm>n?78XEyz+vQBYKh~b27c=pN*b5 zlXtZr$4nc=1<9Lfk-QM2Bwxw48thN*9hr?ftL1D>8%d62X zg%QnyO~V_U;~H+Bh#@{V&1S8Rv%xwQ>Gm5^QXXah?0dKiCZ~fC@>zkwUYN)F*3_jh z1=*VY&%FlS?P@2gNk5NJ7_~U%SK1BcGa(3fT5lP2Xfxc01D|#E_zHzJRC0RYRNIQq zV}+eok$ZSuL-YD)zRTInXnJh>BU@wL;2&mn56}BWz@yuhZ&Dp)2b;pBAcd6h)7Jq| zb3{tJX-|pu6&C|dLQAjRx5k1t0tI^Nsq}_5Nr(=+9P{$PMn*?{`^S*F7V*()3`=oN zZVJDXr-fnH;pJy)E{aj-)0q;n@47a?5IE!^!?0$9)wecj$!=IBoL!i%{Bc&422E*o zOy69|xs-8t^tfYu zB<&{+L{B6}p`6yf^5#1E8-!5pJ1u|E;q@P{U}R0|&dY}rM9B9Qtp)>q&xixbg5t&Z z7>;{6ksxy1crQ)9|AY5B9=Mt2V>I3T^sqtH0q;TUZnwR11rS%#70x2@z>BHm)9s3Z z^fOhb9x-!bZw6q^Cie%6^#8IL3{qP<$bYbFlF(D2nf#n2`ouUC=aqhUyO@%^YAjgp zH5{ZaGe;PhXv|!mJqEv6%ii6h5X!Lvx_l#zh}Rv?2X0XIFMe&lkb${-7kgMlBwLx- zOxdM}WIg)zr3|(Y*RhiFIok0NUU=q&$OiCx|G~M-4fXEfs*I;?$)BEjMREBxX z^q6rkPeJue+dxYm3hRavz?Y4$Qr-}-VJqMEuN7ftyq>UPnw1l|tbS$qBfLIQ4U-$t zF{f#9lQm=CD*dPZt=jgWgK`r{yp6;{6L#3yU*3H0%4&H8NT+DJ zDLz$%{BYzX2P3#}`shkb?e&Z2KWVYjU?^U17e)u>;((ope$7UkpzWhe6;dNbJe5V# zLIc*+EoB{4XC@(BJM`EsihWy^`z7i$us6P6D3rcfMz6hmOEK)Fw^5k;lJ^zl!v^{U zm^!pZRQQcN8t&+P89r;a?iOXlEvn8H#Kj6)Daja~V+&1)Wn{XIW2nQi8^?hJ`9DqaWcWNe^~;9~{FCgn!M3t%-q0|MCl zs9&d-x)o&taUTtSb(kuxUks^-PRvBYJd!w{p1uMo4kE&NQtb3a7e>jpg_3Sy>`zXP zR;3usist(Bw4VQV^j0FT7~9PWQ`_0%ZJW`?lcwq)DJHB{#vU`w6g5)Mgs^J!J;rJh1Js4CS+*m2Fe)Z7#K+l{@%VZ1nA_Z~)i5aeJ4-!7tFc8CfiPQCHe3jQNGD zzND!m`CmA55M^>JjtYoyl#PIZ$42gVQ}MvY?N0Dt*?p@07}a~WRKfBc2geF|5mFZf zLRihIS14wvg58~JvpEo1%h#nmHcT)SMKyo7vxGI1jhOx3$ zwh&^1?A9sg2-do%z<1y?OW{4dxgI9oOmGuCb`ft~fKIG(@5KE$4LYVK-1D+jHR6sp#S~ZRxh#4|6 z!TT;y+=tpwF6!Q9QnZ9Q8ET`rX|02}UefPlIr39J<4hXJitZI~e)zwbd-HfG+y8Gk zQnXpiav?iqO|mnVtRaQLSj(P$-%XYZStBDUA{53t_MPl|ma&tOCHq(hL-#R#uj~2U z_w%~G|31(CZ?C-OoO90eINry5`&hOQ5!&kr$2NxaiwPDY<|-ye-_wg0Y(-w`_z=pf z6Wa$*-+EnjiZ+jZv5dYPkzQ^%c_HlqZ=(A?XXNKVNdA{T#|J@A;e<+Z`C?s|tP}G$ zztP)QXL{}L8Ijn`gf9bCuaWHQ|FMY$A9T%rBEMEf78K7kp7j^o)6uWGB<=D#cq5|b zFuoPhF_Yojv|b+PxbgjdP?-^N#yWm7O-?U733D_(td2O_n_hKK$`$&v z_IQw7tfJ__&^=!Gw_i-1h3(yl8Ud)>5hwh|D4cSc?7yvCL#kxlqF~FHC+ocyLbUk} ztn5w{kKCwAMpX!ZJ;+Er$rBJJbuWI8DpWn@&u-~)|4HykafG?j)W6+T&Y%}hbT|l? z*fdQ^{{zC0q5FRDfBz+lUH=kCxbyO4dK`}o>P&I_;Z5f#m`=6KIQ~Gdi@{Cj4xdsr zcGl4UA3&u{`{1IN9qTU+lElCM{KutN|M`y*75}zDsvVOxXQ_ZsAq%NyyVDe8*eaB{ z@o%d_0z~mn?i<1tJ#qf~RACno{5mS4K}Moq)dH-33orcy`b)OT**%d*Hii zQvByRd}A%~|JwuWP51hQQ1)p87TC5EKt*Cu>8Fm^UXg+8VDPvLc1gTZl3g)m4fOX5 z(E`+2`T937xbYWOVO|p|OAV_J5;O#FKM$Cinni4EeUUqT<~Ktaj}(ZZNjH2J4j+(Q z{s5hO`NDpJY{3c4uB=+gj50d7GuIQm05vczzuQUZ%DCaUJ=G)BXcBm~n=YqCwz2~H zdK|J0rY;peKmPS4G3bj;-7U%Gs0M!)K4R1LM9YsSl#2++tFJe@z~j*L_V1Su7HoQp zJlr#ofBtoJpI92s^!e$28{oYSK7ezXHBJ2OK%Eyag5q%n=8fg$O(Q7&<P?nyT@^mLZ-PuaVC)8M?+RQ&+Ap&px zf7Tj=^+$|6IS>?}pgMr(nHvg`A{01(CA<8}PYmGL`2W}o3FZ^GDW}S$%pX1p;?$ys z2ivl0Gy?E6-1o^=h=QKoV~!Nxlc_ngKP}jVxSg+O5s0PIit*k zV2b3LSDN}Tjix?|GRJ3**9Z8N00uIlSaFH;rtc>vTfm-Kr_UYr`*hDO-6mZQEvbKb zPx({G5y5Lpup{6)RUxIJSN0TXSJ`ANPoX9DI{8^PXoz>rj%!4FZC5IDPxnQ-$CQ`iFH_#Z zGjc|aInUNrk5_xxmOTCT%H1)Zl3KIVZbr$i54eOiVA!Y9-Pd$3VIsXb#aQohin_XS z5gpG{JU6TZ{(hm3i){6v0(O~KH7P*Ax>TvJkg7;^HA)Fln8pg%H*X?WIs(KUU&#f? z2a$b>Y8lD?f&t|ohH94)8zZujjl^L^ODrl0LR)lRov^-_QT=Cqhb2h1!FpmgI@(`g zPk1q^nHLhgH_FElFRrpUY?SEd=|!h=@uKZX?sioPPj!TxCw;(2TcDduFDDdNe%Ie! zy_${DlIp1z%CZ6ErSmPukte*9OVhV%5ubUQLtgx81K)pAvhQE!Q7#N;h2w&M zl*k!A#g@1Q=Te-YX5{6AKcm*z}z)gSu6G%8ZCnte_pf41Fr1{39i+gGSE6K5`CNH}uKG3(_ELns0G_M<)o8 z*Xfg5=R<0O-2b|D)fO?-;p)kzPFV4{|6ZpxN*=oHvcl8s{G!r%;D~#ntwB8PFd_G`kStU0}8 z-B%MOG0Te;1O_K3f(3(dag>p_ zr#~|eZJhGpm^{K$RBO(g&V0E&k-2tf(wR1peM}{BUHRA^MWK59F(U>X2I`1-3-#AC zrsd5BGsdv_7b+GmHUuh7;TmGwqzY=)K6d)`d^!t{X`(;uddeY{>glwnu+xIC7{=7!UE_C?xOM~y*-woWKg&b?XDX3V8eS-sLq$=Ek+}Q%O zJPFIB6*Nan_ncXso1#ev1?)dT0_cLAeQRcvoCypktP>Xy+IAtf7$3-_y1TD^|d+H$@`u&DQf-Kx$# zqFlYHPBb1(ZepvkZ#Y0@Oo1pj{tg){nqe$B3CcSw(0-(ne?{OP5Pk&i(?5B0zFArQ z=7>@GM3sm8PqGMsASDY`e$eN%RNBBNW3WOL_B-s{lTCWM@fLP(Ag>jTOj_$da}doG zzkEDV_Dr|Lrtdwpm0g*{cTiP-!(_%JmF<|Ibk`C+e))xB=hBa`{TJARjyL7@MyHP( zz$E%~gyb~DczwS~hKr@$GE>}lvUr*Xn=zYb=B>&Pul8C%*?QEC__s)qaW%`jE~VHO zc9%4rTw7acjikxH3qQGvLC&YvY9rIwNP8X}Wd(EI8DuNI&mc5ndU2DiHsnK5{ee+6 z`EQVP$u{}Y3z_vS(EBK=8+jq<)czIj5#&i1=L@Z^3$>(=%||$vPvU;#;{I&M{d8Ov zI_ZM_d0r>3DAW2xG(h6?{{|re$MP7cop8j@JG8Pl&i8%0IgNJ>X2;&w(rr(hIxk6H zt7)`!QcilO`#fdfsd3pZco(VRkS9#b}x`z`;9IoJ&hn0`MS&XdOxc~ z$TT8g71Hcq;@l>7{pDOE;D@+UcF~JWL>fsS?Q8VkQ#VeZItV1tvS_##G`uqiJq(@G z#lQdg9%ED@q$^`%S{Ge36@EX}uQEmn&+be9FGrO}4_RhQoBJI@h3dR2Spur|!tIP8 z|0q%dm(pZOCdb)~;>(9|9AoLezF2~BgRP$I_f`> z%EAVp5v>#qtp!)9j_7x_ORuL?j>W}IEpI`@i5rVrW-8R@FZtzamz8r;WS4K3HX990 zm?xf)NDSA!Gm7$V@Q%HWQKfS>cd7bi^y~p1v@2Me9dLySMOh2)IZV`K>khe+Q=yUm*)oPQQa?vy&_(%je|)S<|bh3J6B3BJNzJ~fd{V1-+rmo zyvh?JrGeL(D8|-$?JCN7Dqp~&TC+f?;pbN=yD!%*O3u%N4H%LV#RaEjF=y{gXd@%q zY2{5&o}!@?(uRJVz3vtcMS~x4zqm}FD*#0rwDr)0Zb-)#n{Omu);Ux#UP~?_oH`ml z%45Q-u;cw+jLsHV7yTzk$+2{)h7|A>O7qWe=I(!H(>z&?!HwqJ?SOE;BTjH~dWUl$_1)zJWhfF6#cLfgpD`6w^Sb z*Kq_`717+c74SN-u0KnO^CQtMjsW=bsp6WqhohYn7xqm zOsr~p>X%^YSl@lKm5Zl4Z0{52j1`?~^N`QZew@!2Mpd0oq@TjXYN0eLNdukBx}P@zscGWE#P2gfdwwRU{Tj$5KTK2U1_w#=nbx$#8EA zSkx>CXOs#xZGQK{Gzr(GC4)t?U+LI}R|3duf7mc*)_~0YtC3ayp`JS_=N-4hC)hmP zl_S$f8Pz09-EvkBk5OT9Z%|bVqy&R75wqcrRl4?pzl(60hee}=_V{{Se0X6p%4#2J zBpygRyjTo?l3IA9kIrrj{X0fT?t0-FBzID)?&NC`PuEpM?`q2H4W-|bI)H`MJV@N} zeb7dmVDqWD#6IU5<2i~MbuJoCCYtu~=CX$n|P zk=~ZgYNV6*aODn`sLRn-3)Q^1H?`MSF|aA7?Z>fs!8@?`jo?+++ZaZ{2B)9K9*hgb zJ~St^gAJz9(=`}q^Y4tyBDSF)$?9ST!mZ+RdXxt;d2dX4+N)R zoQzCig&tB(hEAnp6HoU2I*kw6iFQjE3r+8%lg_&oI!QCixXd-}T$|u8iF|XS=7eAj zA%grsFmAt}xb~O@#bj426%ph07`OXs|F0Go+z6LsSKkazt9nuvJ)g7X+W^Fg)$DG8 z5#Jo3EH2jt9$0hMAaYmDRxFT$=J&4sk*4_*!0SQ23eOm7YbL!h#drn=k#y~$Id8_# z)HE1oBG|K;hQIW2UrfWn%3!gtaj?clO>fu_(}IsJb!x0BWF{U`m7exY zB7E*AzP}IMZ>94wGF?p}el zCnjvv9oPtIAE1_Vfuh{PBeb9B3p1vZv3EULHbL<5&GEy=^DKme8h77{uMR1dg85~~ zNmlX@<&w7XcHD$Tdo-7IPJO3rhL~a#$DK9EZKYae`QsH@?R{o^G_R)vF zbCHe)628MpLpD!qmeT?rtj(m!23$@z?X~R+U9b2MCbzd-YCA8rcKLnJDj+c$P}|BH zZcc@BdivTfUcJ^D_Z!hZGRdPTuw3Q9WIs==EpZ7Q$5`zvNmD~tx(dUoGNUG4o(+CjLhDY;gUck{a5-;ZWE+OFMK%DrF3`zqI-9KvTkBXMjB z_{v39uscdbfVs3JUkQw*_nMf~(5!p0-zb*Rz1ZXOO2v-KjEpg#0o~;gNwz!XLGBOl zc%z-tkJYH;)*_qetb@4XcLp--jJ(&_LV8CaFEU+rCMPT&sRGWApCklwIRAqLkeBk; z2$0UWGUX)>OEmBfg;uP(GDV$R*zPi^ZS41%^li@0*Luo#;>5aBJj*f5$kVZ39ES;A z{?@D>oITCON^wQsE?4?+H-~Wc8$fv~jZ+!Wqj}V>Kf%eZQRql)$8*A@#UT1tx<0GS2qqWRZ zND~8dhS1E`CbdFZmNQDiloB$PDQ84IR@JgkBtuFJEIxif9EzBqdhee z@8!kN74T@lKDQ2puFc5FVo_Z^?q04zeG^O#rMQ=f^1m*HJZ5`TNg?#)E0rgJ-G z?il;M=Nu`Sur4r>!_QOnNLC&xp`WF~z51#sSNzkN#@54moWO5%QrMVW-?jx3HfH5Q zMmkCC@LtWBWfEkh>wjpM?(0tna`PO(Vwbl%Qc;3iOuMiD3gEng?A1uGDckLB{WMM> zp9BMX?AsOj2Vm>-AA4=giM2eH?UknMz1f`ABjz;Q>Mhx@5mf`S&Ia98)Cs>DBFsI_ z%+hYXI*Wm{f1B^G;a9ePB+d4O3S8Rt8Wh{03JZWs=41DkS1)10DKt1)kD_?s6@>zm zD*QmmE6PjbPxpe%Yg{(vcAwX1)HBtio@P?Fai>E#l(y;%!%+o5nIma`C7&AP+wVcJ zi~&q zb8O)HYtt|^hV+QV_eaRiGMFAvutM)q2AeOAWrwW|YQM($<-0k{V*F21i++q}7A%{-o8SeMpR!W@HlM;`PB(CtZbeG!SI4|h z`kYdZ^7aU4=F34d?M&j*g&Ffe=}r>9x2NM}qtKAk>S)JkzjNTbk7p8Xtc;=YD2kT1 ze0j`5(5SA3cVXW+Mq%J9IvFm;IHy7O&_6egV=;tt|fxr{{bI5pzeKQlfGqt80 zq&zLFD-1_d|C)j5uDx;jT^-ARvk9@=G53~6s^5D4GnCa`D6h{I5YgwItDfw$!We@L z`TkP+AbPPb{FzPo4|v4I+;@%2ofVomL1MX>+yC!(LMkdf?$>UsQ1ZvO&-H?w6< z4ZlL(?m7U!#Qa%Q6>tdJ^R;<+~7 zeXWl7_T!&tdZ|xY!J&cte)lgmwjfQ_vG=(Ew0u+gkIZV7J94`)mf&8qbO3;rgE`f%RKKo@v*y0*JSeE;Qvc{Fi;B9EVDAixE+bIiPDOJKN zb#@h@q4>+PdM|f^AYMTJ5icIoy+%2|g$lzF(ZZ6K5^d!5xp$r*Q@!@BrlEzViNJkX z-bcHojHElUaN=&q&3F!LExJ_GH|jOUCl{8aJ(+|{2$C7|iZJoRK(v#O5O(2KCW1%5 zx&I-J%MN<#zoU7mR?~J&uVH-l^l__;nK0a2wuRVf#!okk9Ie+bp;Kgt0?4e?h0g)IK9Q(L8YWk{rt(xh+;fhfRmssFJrpOHH2m%i1m z7hLOyASc>|OcOJ<=FR`YB`mf;-yUVvyjS?=q$Uz~>`-te<5VDNbhzfSB6+HHUpr?` zsnRj{1HPO%1NHsXyePHk6vMXe7u7!oB58OY=-lLjORm``<>zVNIj^H3W7D3cDii3SO$MESffnRi)Nh2&FY%ba`lsxG7poH5Y1`6zReJf;NSP3KUF!Xgrq_44VFD1`I%7_Ge{#O794jK8k zQnJYK=+60+zYmfiy2NcpOPy~L@xb72)^Q|tja{u@cV0tBlzjS$D$tNm$2cEC79voT zSc>Dg8r)SI$SmjoWRQl0EF+rAp=&7SW||5jon9DGaEN(@7V5rDidBTq2e4x(0 z=aEd=tV%q^=?5<~>`yny4MjVYoUssRS>Nch^89oug#uAewe1Ifn727i~juTO+VcG)djRz1k8a2*aH)qfh@^FP))!>!Dx z8@vfQx50tcb@)umP6$IsDrVCK$S4)%jPD>NKG*5cLC5LZ<-T?R_3|sbdlMz%D z(PUVZ+b@0bCU!20hJn6t!K1-7Ldt}{`eHB(GB`S>qssGSud7GL%P2#frN5HP7mb)QcPI>!<;EyJA`=c@;ndaCZNozBxJ9-TQ>*tXwE z#Fg~hLnS#Wg^UM8Z*XYkYvnoT7s)v+o>$PMl4Go0o{`CY7g77A=$CEMgQ%?2{^XDc z*6IgVL;c~cTf^yRp4dg9=YB7LvMEe~$eI4UT}R(&t}>(X7cU^Zg7Gp2X&pt<)bFoj zIl4OL#NvX>nN-j^x|j|(kMe}M{X(B4^va0Q`^DLk-F@*&o|cSM^O%ca{~%=H|B8^2 zqTl|5kCBX4u{fB8KJ>VaMh-EBjZ}~ji_9y32n92mX7sgv-CN@pW04wsNaXv&1<+#M}&evmB z59Tju5~v&h^w%g@SD>d!A%oASO*Kl>+99Z)(N6YC#UDqLXn}EZ}C(}%78>k7H+<#(;-}{Bp zpm)aQwL+`Pa2$-ff21HP!-h9MG2naSmpzm6r4!&(NE|NbH!V0ST(qAuPd~9TX87W1 z${3_%i4T<3uZwWB$L2?2QQ;06cldLk@ZT`qVi$&2+;mL3(N*Igdi71#B7jghd%-d|^SxU`#%Oy?6YXuT{P$ZyapArYO#OSQNqypQ{2ef$yL{W;rsp{OeJT|ADykSs+K}J2FQz*ZW`dI+jjeYTm}!n$qde z%0D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 literal 64045 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 From 7fe85091205152e21d9a478aa784b2c28cba5b02 Mon Sep 17 00:00:00 2001 From: notbingsu Date: Sun, 9 Apr 2023 22:01:41 +0800 Subject: [PATCH 236/252] updated notbingsu PPP and link in AboutUs.md --- docs/AboutUs.md | 14 +++++----- docs/team/img.png | Bin 0 -> 45254 bytes docs/team/notbingsu.md | 61 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 docs/team/img.png create mode 100644 docs/team/notbingsu.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index cfb1b6e628..c78823540c 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,9 +1,9 @@ # About us -| Display | Name | Github Profile | Portfolio | -|-----------------------------------------------------------|:------------------:|:--------------------------------------:|:---------------------------------:| -| ![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](team/topgun2001.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](team/gurmankalkat.md) | -| ![](https://avatars.githubusercontent.com/u/88151966?v=4) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) | -| ![](https://avatars.githubusercontent.com/u/88092096?v=4) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) | +| Display | Name | Github Profile | Portfolio | +|------------------------------------------------------------|:------------------:|:--------------------------------------:|:---------------------------------:| +| ![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](team/topgun2001.md) | +| ![](https://avatars.githubusercontent.com/u/101538126?v=4) | Lu Bingyuan | [Github](https://github.com/notbingsu) | [Portfolio](team/notbingsu.md) | +| ![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](team/gurmankalkat.md) | +| ![](https://avatars.githubusercontent.com/u/88151966?v=4) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) | +| ![](https://avatars.githubusercontent.com/u/88092096?v=4) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) | diff --git a/docs/team/img.png b/docs/team/img.png new file mode 100644 index 0000000000000000000000000000000000000000..8a1dec8df6457fa4e0fc1d7daa38c27289f393ac GIT binary patch literal 45254 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

}}^ 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 eO9!P!+gn3JzC# Date: Sun, 9 Apr 2023 22:43:02 +0800 Subject: [PATCH 237/252] no message --- docs/team/img.png | Bin 45254 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/team/img.png diff --git a/docs/team/img.png b/docs/team/img.png deleted file mode 100644 index 8a1dec8df6457fa4e0fc1d7daa38c27289f393ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45254 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

}}^ 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 eO9!P!+gn3JzC# Date: Mon, 10 Apr 2023 00:53:58 +0700 Subject: [PATCH 238/252] add more exception handling & testing for that, update PPP & DG --- docs/AboutUs.md | 2 +- docs/DeveloperGuide.md | 4 +- docs/UserGuide.md | 1 + docs/team/gurmankalkat.md | 41 ++++++- src/main/java/seedu/meal360/Meal360.java | 12 +- src/main/java/seedu/meal360/Parser.java | 39 +++++- src/test/java/seedu/meal360/Meal360Test.java | 120 ++++++++++++++++++- 7 files changed, 195 insertions(+), 24 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index cfb1b6e628..88c15fc251 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -4,6 +4,6 @@ |-----------------------------------------------------------|:------------------:|:--------------------------------------:|:---------------------------------:| | ![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](team/topgun2001.md) | | ![](https://via.placeholder.com/100.png?text=Photo) | Lu Bingyuan | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) | -| ![](https://via.placeholder.com/100.png?text=Photo) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](team/gurmankalkat.md) | +| ![](https://avatars.githubusercontent.com/gurmankalkat) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](team/gurmankalkat.md) | | ![](https://avatars.githubusercontent.com/u/88151966?v=4) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) | | ![](https://avatars.githubusercontent.com/u/88092096?v=4) | Jared Oong | [Github](https://github.com/jaredoong) | [Portfolio](team/jaredoong.md) | diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 25ffd9b4e2..ff0a0f443c 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -356,6 +356,7 @@ The sequence diagram below shows how this feature works: ![](./UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio.png) + ### Delete Recipes Feature The current implementation: @@ -377,6 +378,7 @@ It is implemented through the following step: ![](./UML/Implementation/DeleteFunction/DeleteFunction.jpg) + ### Add Recipes Feature The current implementation: @@ -555,7 +557,7 @@ It is implemented through the following steps: - In `Ui`, `printUserIngredients()` first checks if the list is empty. - If the list is empty, the user will be alerted with a relevant message and the function exits. - If the list is not empty, the list of ingredients will be printed out, with information regarding - the names, quanntity, and expiry date of each ingredient displayed. + the names, quantity, and expiry date of each ingredient displayed. The sequence diagram below shows how this feature works: diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 81182215df..9ebde205b9 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -151,6 +151,7 @@ Format: `delete INDEX/RANGE` or `delete /r NAME` * Deletes the recipe(s) specified by the user either through the recipe index or name. * The index refers to the index number shown in the displayed person list. * The name refers to the recipe name in the list. +* Example of usage: diff --git a/docs/team/gurmankalkat.md b/docs/team/gurmankalkat.md index 3221172fd7..433ae81150 100644 --- a/docs/team/gurmankalkat.md +++ b/docs/team/gurmankalkat.md @@ -9,25 +9,58 @@ apps. ### Summary of Contributions * __Code contributed__: [RepoSense link](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=gurmankalkat&breakdown=true) -* __Enhancements implemented__ + + +* __Enhancements implemented:__ * Added `delete` feature to give users the ability to delete a recipe in the list by its index or name + * [#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20) * Added `weeklyingredients` feature to list out all ingredients needed for the week based on user's weeklyplan + * [#50](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/50) * Added `weekly /clear` feature to be able to clear the entire weeklyplan + * [#50](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/50) * Updated `delete` feature so use can delete all or a range of recipes + * [#34](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/34) * Added exception handler for `delete` feature + * [#34](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/34) * Wrote tests for `delete`, `weeklyingredients` and `weekly /clear` features + * [#50](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/50) + * [#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20/files) + * Updated `add` feature so users can input all ingredients in one line and processed accurately + * [137](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/137) + + * __Documentation__: * User Guide * Added documentation for `delete`, `weeklyingredients`, and `weekly /clear` features + * Updated documentation for `add` * Developer Guide * Added documentation for `delete` feature * Added UML diagrams for `delete` feature -* __Review/Mentoring contributions__: + + +* __Contributions to the team-based tasks__: + * Maintaining & solving issues in tracker + * [#124](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/124) + * Solves issues: [#112](https://github.com/AY2223S2-CS2113-F10-3/tp/issues/112), + [#108](https://github.com/AY2223S2-CS2113-F10-3/tp/issues/108), + [#92](https://github.com/AY2223S2-CS2113-F10-3/tp/issues/92), + [#91](https://github.com/AY2223S2-CS2113-F10-3/tp/issues/91) + * [#137](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/137) + * Solves issues: [#79](https://github.com/AY2223S2-CS2113-F10-3/tp/issues/79), + [#76](https://github.com/AY2223S2-CS2113-F10-3/tp/issues/76), + [#78](https://github.com/AY2223S2-CS2113-F10-3/tp/issues/78) + * PRs reviewed: [#4](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/4), [#15](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/15), [#39](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/39), [#125](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/125), [#127](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/127), [#135](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/135) - - + + +* __Contributions beyond the project team__: + * Bugs & suggestions in PE-Dry Run: [#1](https://github.com/gurmankalkat/ped/issues/1), + [#2](https://github.com/gurmankalkat/ped/issues/2), + [#3](https://github.com/gurmankalkat/ped/issues/3), + [#4](https://github.com/gurmankalkat/ped/issues/4), + [#5](https://github.com/gurmankalkat/ped/issues/5) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index 9e3720341b..f104b29ffd 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -91,17 +91,9 @@ public static void receiveInput(String input) { ui.printMessage(deletedRecipe); ui.printMessage("Now you have " + recipeList.size() + " recipes in the list."); } catch (ArrayIndexOutOfBoundsException e) { - String errorMessage = "Please enter a valid recipe number or name in the correct format. You did not " + - "enter a recipe" - + - " number or name. See 'help' for more details."; - ui.printMessage(errorMessage); + ui.printMessage(e.getMessage()); } catch (IndexOutOfBoundsException e) { - String errorMessage = String.format( - "Please enter a valid recipe number or name. You entered %s, " - + "which is in invalid.", - command[1]); - ui.printMessage(errorMessage); + ui.printMessage(e.getMessage()); } ui.printSeparator(); } else if (command[0].equals("view")) { diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 9e7ecbbaa5..8dced425d3 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -357,14 +357,28 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { return recipeToEdit; } + /** + * This method deletes a single, range, or all recipes. + * + * @author gurmankalkat + * @param input array containing string of inputs + * @param recipeList list containing all recipes data + * @return a String of the recipe name deleted + * @throws ArrayIndexOutOfBoundsException If users enters an invalid recipe name. + * @throws RecipeNotFoundInTagException If users entered a recipe index or range that is out of bounds. + */ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { - // user inputted recipe name try { + // make sure user inputted recipe name or number if (!input[1].equals("/r") && !input[1].contains("-")) { Integer.parseInt(input[1]); } } catch (NumberFormatException e) { - throw new IndexOutOfBoundsException(); + throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in the " + + "correct format."); + } catch (ArrayIndexOutOfBoundsException e) { + throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in " + + "the correct format."); } if (input[1].contains("/r")) { // skip over /r in recipe name @@ -383,26 +397,36 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { return allRecipes; } else { int recipeIndex = 0; + boolean recipeFound = false; for (Recipe recipe : recipeList) { // find index of recipe we want to delete if (recipe.getName().equals(recipeToDelete)) { + recipeFound = true; break; } recipeIndex++; } + if (!recipeFound) { + throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in " + + "the correct format."); + } return recipeList.deleteRecipe(recipeIndex).getName(); } - // user inputted index of recipe in list + // user inputted index of recipe in list } else { // deleting a range of recipes - if (input[1].length() >= 3) { + if (input[1].length() >= 3 && input[1].contains("-")) { String[] range = input[1].trim().split("-"); + if (range.length != 2) { + throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in " + + "the correct format."); + } int startIndex = Integer.parseInt(range[0]); int endIndex = Integer.parseInt(range[1]); startIndex -= 1; endIndex -= 1; if (startIndex < 0 || endIndex >= recipeList.size() || endIndex < startIndex) { - throw new IndexOutOfBoundsException(); + throw new IndexOutOfBoundsException("Please enter a valid recipe number, name, or range."); } int newSize = recipeList.size() - ((endIndex - startIndex) + 1); String rangeRecipes = ""; @@ -412,9 +436,12 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { rangeRecipes = String.valueOf( new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2))); return rangeRecipes; + // deleting a single recipe } else { int recipeIndex = Integer.parseInt(input[1]); - ; + if (recipeIndex <= 0 || recipeIndex > recipeList.size()) { + throw new IndexOutOfBoundsException("Please enter a valid recipe number, name, or range."); + } recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based return recipeList.deleteRecipe(recipeIndex - 1).getName(); diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index d1e4c42796..86cbd304c3 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -183,7 +183,7 @@ public void testViewRecipe() { } } - //@@author + //@@author gurmankalkat @Test public void testDeleteRecipe() { HashMap testIngredients = new HashMap<>(); @@ -198,6 +198,118 @@ public void testDeleteRecipe() { int newRecipeListSize = recipes.size(); // check if recipe list size is 1 less than before assertEquals((oldRecipeListSize - 1), newRecipeListSize); + + // No recipe inputted + try { + String userInput = "delete"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(ArrayIndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range in the correct format.", + e.getMessage()); + } + + // Recipe in incorrect format + try { + String userInput = "delete pizza"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(ArrayIndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range in the correct format.", + e.getMessage()); + } + + // Index out of bounds + try { + String userInput = "delete 100000"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range.", e.getMessage()); + } + + // Index out of bounds + try { + String userInput = "delete -5"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range.", e.getMessage()); + } + + // Range invalid + try { + String userInput = "delete 0-2000000"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range.", e.getMessage()); + } + + // Range invalid + try { + String userInput = "delete 1---------"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(ArrayIndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range in the correct format.", + e.getMessage()); + } + + // Range invalid + HashMap testIngredients1 = new HashMap<>(); + testIngredients1.put("test ingredient", 100); + // create a fake recipe + Recipe testR1 = new Recipe("test recipe name", testIngredients); + recipes.addRecipe(testR1); + + HashMap testIngredients2 = new HashMap<>(); + testIngredients2.put("test ingredient", 100); + // create a fake recipe + Recipe testR2 = new Recipe("test recipe name", testIngredients); + recipes.addRecipe(testR2); + try { + String userInput = "delete 2-1"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range.", e.getMessage()); + } + + // Delete all + try { + String userInput = "delete /r all"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assertEquals(0, recipes.size()); + } catch (Exception e) { + assert false; + } + + // Recipe does not exist in recipe list) + try { + String userInput = "delete /r pizza"; + String[] command = parser.cleanUserInput(userInput); + parser.parseDeleteRecipe(command, recipes); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(ArrayIndexOutOfBoundsException.class, e.getClass()); + assertEquals("Please enter a valid recipe number, name, or range in the correct format.", e.getMessage()); + } } //@@author jaredoong @@ -807,10 +919,14 @@ public void testClearWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); weeklyPlan.put("salad", 1); weeklyPlan.put("pizza", 3); - // Testing clearing weekly plan weeklyPlan.clearPlan(); assertEquals(weeklyPlan.size(), 0); + + // weekly plan of size 0 + weeklyPlan = new WeeklyPlan(); + weeklyPlan.clearPlan(); + assertEquals(weeklyPlan.size(), 0); } @Test From 5e150a6063e8237c0367bb5abad8792ecab33e20 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 02:34:44 +0800 Subject: [PATCH 239/252] Update author tgas --- src/main/java/seedu/meal360/Parser.java | 27 +++++++++++++++++++- src/main/java/seedu/meal360/WeeklyPlan.java | 3 +++ src/test/java/seedu/meal360/Meal360Test.java | 6 ++--- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 9e7ecbbaa5..86ff73e774 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -357,6 +357,17 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { return recipeToEdit; } + //@@author gurmankalkat + /** + * This method deletes a single, range, or all recipes. + * + * @author gurmankalkat + * @param input array containing string of inputs + * @param recipeList list containing all recipes data + * @return a String of the recipe name deleted + * @throws ArrayIndexOutOfBoundsException If users enters an invalid recipe name. + * @throws RecipeNotFoundInTagException If users entered a recipe index or range that is out of bounds. + */ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { // user inputted recipe name try { @@ -422,6 +433,7 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } } + //@@author junenita /** * Extract inputs from users whether it is adding recipes to a tag or removing recipe from a tag. * Then, proceed to add or remove the recipes from the tag, and returns a string whether @@ -468,6 +480,7 @@ public String parseTagRecipe(String[] inputs, RecipeList recipeList) return returnMessage; } + //@@author junenita /** * Extract the tag label and recipes. Then, proceed to add the recipes to the tag, * and returns the tag label that users modified @@ -507,6 +520,7 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) throws No return tag; } + //@@author junenita /** * Extract the tag label and recipes. Then, proceed to remove the recipes from the tag, * and returns the tag label that users modified @@ -565,6 +579,7 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) return tag; } + //@@author junenita /** * Extract the filters from users' input. Then, proceed to extract the recipes by the filters. * @@ -605,6 +620,7 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) return recipeListToPrint; } + //@@author jaredoong /** * Extract the recipe index that the users wishes to view. Then, proceed to extract the recipe and returns * the recipe. @@ -641,6 +657,7 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { return requestedRecipe; } + //@@author AbijithRam /** * This method is designed to find the index of a recipe from * the recipe list of the user and return the recipe. @@ -661,6 +678,7 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { return recipes.get(recipeIndex - 1); } + // @@author junenita /** * Returns a Recipe object that contain a recipe's name and ingredients. * @@ -676,6 +694,7 @@ public Recipe parseRandomRecipe(RecipeList recipes) throws NoRecipeException { return recipes.randomRecipe(); } + // @@author jaredoong /** * Checks whether the user wants to edit single, multiple, or clear all the recipes in the weekly plan. * Then, return a WeeklyPlan object that contains the recipes that the user wants to add or delete. @@ -714,6 +733,7 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) return updatedWeeklyPlan; } + //@@author jaredoong /** * Parses the user input to extract the single recipe that the user wants to add or delete from the weekly * plan. @@ -762,6 +782,7 @@ private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipe } } + //@@author jaredoong /** * Parses the user input to extract the multiple recipes that the user wants to add or delete from the * weekly plan. @@ -839,6 +860,7 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes return recipesToEdit; } + //@@author jaredoong private StringBuilder getRecipeNames(String[] command, ArrayList recipeNames, StringBuilder recipeName, int nameStartIndex, int nameEndIndex) { recipeName.append(command[nameStartIndex].toLowerCase().trim()); @@ -850,7 +872,7 @@ private StringBuilder getRecipeNames(String[] command, ArrayList recipeN return recipeName; } - // @@author + //@@author notbingsu // parser to read dd/mm/yyyy format as local date catching invalid date format public LocalDate parseDate(String input) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); @@ -863,6 +885,7 @@ public LocalDate parseDate(String input) { } } + //@@author jaredoong /** * Parses the user input to extract the ingredient name, quantity, and expiry date that the user wants to * add to the ingredient list. Returns the Ingredient object that contains parsed data. @@ -922,6 +945,7 @@ public Ingredient parseAddUserIngredients(String[] command) return new Ingredient(ingredientName, ingredientCount, expiryDate); } + //@@author jaredoong /** * Parses the user input to extract the ingredient name and quantity that the user wants to delete from * the ingredient list. Returns the Ingredient object that contains parsed data. @@ -979,6 +1003,7 @@ public Ingredient parseDeleteUserIngredients(String[] command) return new Ingredient(ingredientName, ingredientCount, "01/01/2020"); } + //@@author jaredoong /** * Parses the user input to extract the recipe which the user wants to mark as done. Returns the recipe * name to be deleted from the weekly plan. diff --git a/src/main/java/seedu/meal360/WeeklyPlan.java b/src/main/java/seedu/meal360/WeeklyPlan.java index 00158461f2..39917a99bb 100644 --- a/src/main/java/seedu/meal360/WeeklyPlan.java +++ b/src/main/java/seedu/meal360/WeeklyPlan.java @@ -4,6 +4,7 @@ import java.util.HashMap; import seedu.meal360.exceptions.IngredientNotFoundException; +//@@author jaredoong public class WeeklyPlan extends HashMap { /** @@ -57,10 +58,12 @@ public void deletePlans(WeeklyPlan recipeMap) throws IllegalArgumentException { }); } + //@@author gurmankalkat public void clearPlan() { this.clear(); } + //@@author jaredoong /** * Checks if the weekly plan contains any invalid recipes. * diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index d1e4c42796..c6818c7dde 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -801,7 +801,7 @@ public void testDeleteMultiWeeklyPlan() { } } - //@@author + //@@author gurmankalkat @Test public void testClearWeeklyPlan() { WeeklyPlan weeklyPlan = new WeeklyPlan(); @@ -846,7 +846,7 @@ public void testViewNonEmptyWeeklyPlan() { "salad x1"), outContent.toString().trim()); } - //@@author + //@@author junenita @Test public void testListRecipe() { RecipeList recipeListToPrint; @@ -1417,7 +1417,7 @@ public void testLoadDatabase() { assertDoesNotThrow(database::loadRecipesDatabase); } - + //@@author AbijithRam @Test public void testCombineWords() { String[] input1 = {"One", "Two", "Three"}; From d02c0ce1f6df6f42bb5ab8ba571725a002bcda38 Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 02:45:57 +0800 Subject: [PATCH 240/252] Fix visual bugs in UG and DG Format code to allow UG and DG to load properly --- docs/DeveloperGuide.md | 21 ++++++++++++--------- docs/UserGuide.md | 16 +++++++++------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 25ffd9b4e2..6e57648c62 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -137,7 +137,6 @@ The `Parser` component: ![](./UML/Parser/ParserClassDiagram.png) - - receives the user input from the `Meal360` component - checks and filters input string - catches `exceptions` and throws error messages via `UI` to @@ -198,7 +197,8 @@ How the `WeeklyPlan` component works: 3. `Parser` component then returns a `WeeklyPlan` object to indicate the recipe(s) to be added or deleted from the weekly plan. 4. `WeeklyPlan` component then uses either `addPlans` or `deletePlans` method to add or delete - the recipe(s) from the weekly plan, `clearPlan` to clear the entire plan for the week, and `checkValidity` to + the recipe(s) from the weekly plan, `clearPlan` to clear the entire plan for the week, + and `checkValidity` to check the validness of the weekly plan (i.e. make sure all recipes are valid). The sequence diagram below shows how the `WeeklyPlan` component works when the user @@ -341,15 +341,20 @@ The sequence diagram below shows how this feature works: It is implemented through the following steps: -1. When the user enters and input `available`, an instance of `RecipeList` availableRecipes is created -2. This instance of recipe calls the `availableRecipes()` method in `RecipeList` on the current recipeList which +1. When the user enters and input `available`, an instance of `RecipeList` availableRecipes is + created +2. This instance of recipe calls the `availableRecipes()` method in `RecipeList` on the current + recipeList which returns a `RecipeList` object containing all available `Recipes` -3. `availableRecipes()` method iterates through `recipeList` and calls the `isAvailable()` method on each `Recipe`, +3. `availableRecipes()` method iterates through `recipeList` and calls the `isAvailable()` method on + each `Recipe`, appending the available recipes to `availableRecipes` 4. `isAvailable()` method - iterates through the `ingredients` Hashmap of each `Recipe` - - compares the quantity required for each recipe to the amount of the same `Ingredient` in the `ingredientList`, - - returns `true` if the quantity in the `ingredientList` is more than or equal to the quantity required + - compares the quantity required for each recipe to the amount of the same `Ingredient` in + the `ingredientList`, + - returns `true` if the quantity in the `ingredientList` is more than or equal to the quantity + required 5. The `listAvailableRecipes()` method is then called in `Ui` to print `availableRecipes` The sequence diagram below shows how this feature works: @@ -400,7 +405,6 @@ It is implemented through the following steps: ![](UML/Implementation/addRecipe/AddRecipe.png) - ### Edit Recipes Feature The current implementation: @@ -424,7 +428,6 @@ It is implemented through the following steps: ![](UML/Implementation/editRecipe/EditRecipe.png) - ### Random a Recipe Feature - randomly pick a recipe and display to the user diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 81182215df..710eaa052c 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,15 +1,16 @@ # User Guide - ## Introduction Meal360 is a desktop app for managing your recipes and weekly meal plans, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, Meal360 can get your recipe management tasks done faster than traditional GUI apps. + * [Quick Start](#quick-start) * [Features](#features) * [Command Summary](#command-summary) + ___ ## Quick Start @@ -21,7 +22,7 @@ ___ `tp.jar` file. This folder will contain all the data files that the app will use. Please do not touch these files to ensure smooth operation of the app. 4. To allow for immediate testing of features, the app comes preloaded with 10 recipes. -5. Take note that changes to the ingredient list, recipe list, and weekly meal plan would be saved +5. Take note that changes to the ingredient list, recipe list, and weekly meal plan would be saved only when exiting the program properly using `bye` command. ___ @@ -48,7 +49,6 @@ ___ * [Add User Ingredient](#add-user-ingredient) * [Delete User Ingredient](#delete-user-ingredient) - ### HOW TO ADD INGREDIENTS TO A RECIPE: * Please follow the below-mentioned format. @@ -56,14 +56,16 @@ ___ Format: `ingredient1_name=ingredient1_quantity and ingredient2_name=ingredient2_quantity ...` Examples of usage: - * `chicken=100 meat and oil=200` - * `white rice=300 vegetables=400 pepper,chilli and seeds=500` + +* `chicken=100 meat and oil=200` +* `white rice=300 vegetables=400 pepper,chilli and seeds=500` * Type the ingredient name followed by equal sign and quantity in positive integer values. * After the ingredients are key-in in, please type `done` in the next line to finish the process. - * **exception:** for editing ingredients partially, you just have to key in the 1 new ingredient and the recipe - manager knows that you have entered 1 ingredient. No need to type `done`. + * **exception:** for editing ingredients partially, you just have to key in the 1 new ingredient + and the recipe + manager knows that you have entered 1 ingredient. No need to type `done`.
From bdaadddcd412ad59b6d2b95bdd5723dc6a60818e Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 02:47:01 +0800 Subject: [PATCH 241/252] Fix visual bugs in UG and DG Format code to allow UG and DG to load properly --- docs/DeveloperGuide.md | 2 ++ docs/UserGuide.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 2c401a89c0..30a1d3e526 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -362,6 +362,7 @@ The sequence diagram below shows how this feature works: ![](./UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio.png) + ### Delete Recipes Feature The current implementation: @@ -384,6 +385,7 @@ It is implemented through the following step: ![](./UML/Implementation/DeleteFunction/DeleteFunction.jpg) + ### Add Recipes Feature The current implementation: diff --git a/docs/UserGuide.md b/docs/UserGuide.md index b47c39f0f6..aa1b0e9617 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -153,7 +153,7 @@ Format: `delete INDEX/RANGE` or `delete /r NAME` * Deletes the recipe(s) specified by the user either through the recipe index or name. * The index refers to the index number shown in the displayed person list. * The name refers to the recipe name in the list. -* +* Example of usage: From 4c1a11320aa0f116d07e0f3b41067413a61becc4 Mon Sep 17 00:00:00 2001 From: AbijithRam Date: Mon, 10 Apr 2023 10:44:29 +0800 Subject: [PATCH 242/252] Final edits made to add function. Updated help commands. --- docs/AboutUs.md | 2 +- docs/UserGuide.md | 25 +++++- .../java/seedu/meal360/IngredientList.java | 28 +++++- src/main/java/seedu/meal360/Parser.java | 76 +++++++++------- src/main/java/seedu/meal360/RecipeList.java | 4 + src/main/java/seedu/meal360/Ui.java | 88 +++++++++++++------ 6 files changed, 161 insertions(+), 62 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 3d098f7d36..420cf7fea8 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -2,7 +2,7 @@ | Display | Name | Github Profile | Portfolio | |------------------------------------------------------------|:------------------:|:--------------------------------------:|:---------------------------------:| -| ![](https://via.placeholder.com/100.png?text=Photo) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](team/topgun2001.md) | +| ![](https://avatars.githubusercontent.com/u/88262428?v=4) | Suresh Abijith Ram | [Github](https://github.com/) | [Portfolio](team/topgun2001.md) | | ![](https://avatars.githubusercontent.com/u/101538126?v=4) | Lu Bingyuan | [Github](https://github.com/notbingsu) | [Portfolio](team/notbingsu.md) | | ![](https://avatars.githubusercontent.com/gurmankalkat) | Gurman Kalkat | [Github](https://github.com/) | [Portfolio](team/gurmankalkat.md) | | ![](https://avatars.githubusercontent.com/u/88151966?v=4) | Nita Chenvisuwat | [Github](https://github.com/junenita) | [Portfolio](team/junenita.md) | diff --git a/docs/UserGuide.md b/docs/UserGuide.md index aa1b0e9617..ddf1247632 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -48,12 +48,14 @@ ___ * [Exit Program](#exit-the-program) * [Add User Ingredient](#add-user-ingredient) * [Delete User Ingredient](#delete-user-ingredient) +* [View Available Ingredients](#view-available-ingredients) +* [Help Tab](#help-tab) ### HOW TO ADD INGREDIENTS TO A RECIPE: * Please follow the below-mentioned format. -Format: `ingredient1_name=ingredient1_quantity and ingredient2_name=ingredient2_quantity ...` +Format: `ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ...` Examples of usage: @@ -62,6 +64,9 @@ Examples of usage: * Type the ingredient name followed by equal sign and quantity in positive integer values. +* There is no `and` between two separate ingredients. + * If user types, `meat=100 and chicken=200`, it will get stored as `meat=100`, `and chicken=200`. + * Use `and` only in cases like: `pepper and spices=100`, `meat and vegetables=200`. * After the ingredients are key-in in, please type `done` in the next line to finish the process. * **exception:** for editing ingredients partially, you just have to key in the 1 new ingredient and the recipe @@ -95,6 +100,8 @@ Format: `edit /r [RECIPE_NAME]` * Type the recipe name after typing `/r `. * If you want to edit fully: press 1, edit partially: press 2, or add new ingredients: press 3. * Follow the proper format while editing/adding ingredients. +* **NOTE:** If you add the same ingredient while editing, then the quantity will be the only one +that will be changed to avoid duplicates. Example of usage: @@ -387,7 +394,19 @@ Example of usage: View user's ingredients from the ingredient list. Format : `view_ingredients` ---- +
+ +### View available ingredients + +View the available ingredients. +Format: `available` + +
+ +### Help Tab + +View all the 21 proper commands used in the recipe manager. +Format: `help` ## Command Summary @@ -411,4 +430,6 @@ Format : `view_ingredients` | View user ingredients | `view_ingredients` | | Add user ingredient | `add_i /n NAME /c COUNT /d DATE`
e.g `add_i /n Rice /c 100 /d 04/09/2023` | | Delete user ingredient | `del_i /n NAME /c COUNT`
e.g `delete_i /n Rice /c 50` | +| Available ingredients | `available` | | Exit the program | `bye` | +| Help Tab | `help` | diff --git a/src/main/java/seedu/meal360/IngredientList.java b/src/main/java/seedu/meal360/IngredientList.java index 14c50efebf..a55d925bf4 100644 --- a/src/main/java/seedu/meal360/IngredientList.java +++ b/src/main/java/seedu/meal360/IngredientList.java @@ -8,7 +8,12 @@ public class IngredientList extends HashMap { private static final Parser parser = new Parser(); - // public method to find count of ingredient + /** + * This method is designed to find the count of a particular ingredient. + * + * @param ingredientName name of ingredient + * + **/ public Integer findIngredientCount(String ingredientName) throws IngredientNotFoundException { if (this.containsKey(ingredientName)) { return this.get(ingredientName).ingredientCount; @@ -16,7 +21,12 @@ public Integer findIngredientCount(String ingredientName) throws IngredientNotFo throw new IngredientNotFoundException("Ingredient not found"); } - // public method to find expiry date of ingredient + /** + * This method is designed to find the expiry date of a particular ingredient, + * + * @param ingredientName name of ingredient + * + **/ public LocalDate findExpiryDate(String ingredientName) throws IngredientNotFoundException { if (this.containsKey(ingredientName)) { return this.get(ingredientName).expiryDate; @@ -42,6 +52,15 @@ public void addIngredient(Ingredient ingredient) { } } + /** + * This method is designed to edit the ingredient count and expiry date. + * It also checks if the ingredient is expired or not. + * + * @param ingredient the ingredient we want to check + * @param ingredientCount count of ingredient + * @param expiryDate expiry date of ingredient + * + **/ public void editIngredient(Ingredient ingredient, Integer ingredientCount, String expiryDate) throws IngredientNotFoundException { if (this.containsKey(ingredient.ingredientName)) { @@ -80,7 +99,10 @@ public void deleteIngredient(Ingredient ingredient) throws IngredientNotFoundExc } } - // private indexed list of ingredients, count and expiry date + /** + * This method is designed to print the contents of an ingredient. + * + **/ private String listIngredients() { String ingredientList = ""; int index = 1; diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 448646bcda..a03cedf413 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -20,9 +20,10 @@ public class Parser { Ui ui = new Ui(); - String recipeErrorMessage = "Wrong Format or Invalid Quantity. Please enter ingredients properly " + - "[eg:chicken=100] and \"done\" when finished entering ingredients!"; + String recipeErrorMessage1 = "Wrong Format or Invalid Quantity. Please enter ingredients properly " + + "[eg:chicken=100]"; + String recipeErrorMessage2 = "Enter \"done\" when finished entering ingredients!"; /** * This method is designed to combine multiple words into a single sentence @@ -101,6 +102,7 @@ public HashMap parseIngredientName(String[] commands) { throw new IllegalArgumentException("Ingredient name cannot be empty"); } ingredients.put(currentIngredient, quantity); + currentIngredient = null; } } return ingredients; @@ -110,7 +112,6 @@ public HashMap parseIngredientName(String[] commands) { /** * This method is designed to add in a recipe to the user's * recipe list. - * * The method will also check if a recipe already exists or not * to prevent duplicate recipes. * @@ -130,39 +131,34 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { } HashMap ingredients = new HashMap<>(); Scanner userInput = new Scanner(System.in); - System.out.println("Please Enter The Ingredients & Quantity (enter \"done\" when complete): "); + ui.printMessage("Please Enter The Ingredients & Quantity (enter \"done\" when complete): "); + ui.printSeparator(); while (true) { try { String line = userInput.nextLine(); if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { - ui.printMessage( - "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { break; } } else { addedIngredient = 1; - String[] command = line.trim().split(" and "); + String[] command = line.trim().split(" "); ingredients = parseIngredientName(command); - boolean ingredientsInCorrectFormat = true; - for (String s : command) { - if (!s.contains("=")) { - ingredientsInCorrectFormat = false; - break; - } - } - if (ingredients.size() == 0 || !ingredientsInCorrectFormat) { + if (ingredients.size() == 0) { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(recipeErrorMessage1); + ui.printMessage(recipeErrorMessage2); ui.printSeparator(); } } } catch (IllegalArgumentException e) { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(recipeErrorMessage1); + ui.printMessage(recipeErrorMessage2); ui.printSeparator(); } } @@ -196,8 +192,10 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { return null; } recipeToEdit = recipeList.findByName(recipeName); - System.out.println("Do you want to edit recipe fully or partially?"); - System.out.println("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); + ui.printSeparator(); + ui.printMessage("Do you want to edit recipe fully or partially or add new ingredients?"); + ui.printMessage("Press 1 for full edit | Press 2 for partial edit | Press 3 to add ingredients"); + ui.printSeparator(); int index; Scanner getNum = new Scanner(System.in); while (true) { @@ -217,13 +215,16 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } } if (index == 1) { - System.out.println("Please Enter New Ingredients & Quantity: "); + ui.printSeparator(); + ui.printMessage("Please Enter New Ingredients & Quantity: "); + ui.printSeparator(); while (true) { try { String line = userInput.nextLine(); if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { + ui.printSeparator(); ui.printMessage( "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); @@ -238,23 +239,27 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { recipeList.editRecipe(recipeToEdit, ingredients); } else { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(recipeErrorMessage1); + ui.printMessage(recipeErrorMessage2); ui.printSeparator(); } } } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(recipeErrorMessage1); + ui.printMessage(recipeErrorMessage2); ui.printSeparator(); } } } else if (index == 2) { - System.out.println("These are the ingredients for the recipe:"); + ui.printSeparator(); + ui.printMessage("These are the ingredients for the recipe:"); ui.printSeparator(); Recipe recipe = parseViewRecipe(recipeName, recipeList); ui.printRecipe(recipe); ui.printSeparator(); - System.out.println("Which ingredient do you want to change?"); + ui.printMessage("Which ingredient do you want to change?"); + ui.printSeparator(); int ingredientIndex = 0; Scanner getIndex = new Scanner(System.in); while (true) { @@ -279,7 +284,8 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { for (String ingredient : recipeToEdit.getIngredients().keySet()) { if (ingredientIndex == count) { ingredientToRemove = ingredient; - System.out.println("Ingredient to be changed:"); + ui.printSeparator(); + ui.printMessage("Ingredient to be changed:"); ui.printSeparator(); String toPrint = String.format("%s(%d)", ingredient, recipeToEdit.getIngredients().get(ingredient)); @@ -289,7 +295,9 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } count++; } - System.out.println("Please enter the new ingredient:"); + ui.printSeparator(); + ui.printMessage("Please enter the new ingredient:"); + ui.printSeparator(); while (true) { try { @@ -310,24 +318,28 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(recipeErrorMessage1); + ui.printMessage("Enter only 1 ingredient!"); ui.printSeparator(); } } } else { HashMap newIngredientList = recipeToEdit.getIngredients(); - System.out.println("These are the current ingredients:"); + ui.printSeparator(); + ui.printMessage("These are the current ingredients:"); ui.printSeparator(); Recipe recipe = parseViewRecipe(recipeName, recipeList); ui.printRecipe(recipe); ui.printSeparator(); - System.out.println("Please Enter Additional Ingredients & Quantity: "); + ui.printMessage("Please Enter Additional Ingredients & Quantity: "); + ui.printSeparator(); while (true) { try { String line = userInput.nextLine(); if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { + ui.printSeparator(); ui.printMessage( "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); @@ -343,13 +355,15 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { recipeList.editRecipe(recipeToEdit, newIngredientList); } else { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(recipeErrorMessage1); + ui.printMessage(recipeErrorMessage2); ui.printSeparator(); } } } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { ui.printSeparator(); - ui.printMessage(recipeErrorMessage); + ui.printMessage(recipeErrorMessage1); + ui.printMessage(recipeErrorMessage2); ui.printSeparator(); } } diff --git a/src/main/java/seedu/meal360/RecipeList.java b/src/main/java/seedu/meal360/RecipeList.java index 0042f9eb8b..0ba12abf6e 100644 --- a/src/main/java/seedu/meal360/RecipeList.java +++ b/src/main/java/seedu/meal360/RecipeList.java @@ -159,6 +159,10 @@ public RecipeList listTagRecipes(String[] filters) throws TagNotFoundException, return filteredRecipeList; } + /** + * This method is designed to return any available recipes if they exist. + * + **/ public RecipeList availableRecipes() { RecipeList availableRecipeList = new RecipeList(); for (Recipe recipe : this) { diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index ac7dc2dcbe..2898d89fe1 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -48,6 +48,12 @@ public void printRecipe(Recipe recipe) { } } + /** + * This method is designed to print the weeklyplan. + * + * @param weeklyPlan weeklyPlan whose contents are to be printed. + * + **/ public void printWeeklyPlan(WeeklyPlan weeklyPlan) { if (weeklyPlan.isEmpty()) { printMessage("Your weekly plan is empty!"); @@ -61,6 +67,13 @@ public void printWeeklyPlan(WeeklyPlan weeklyPlan) { } + /** + * This method is designed to print the weekly ingredients. + * + * @param weeklyPlan weeklyPlan whose contents are to be printed. + * @param recipeList recipeList of user + * + **/ public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) { if (weeklyPlan.isEmpty()) { printMessage("Your weekly plan is empty!"); @@ -78,11 +91,25 @@ public void printWeeklyIngredients(WeeklyPlan weeklyPlan, RecipeList recipeList) } + + /** + * This method is designed to print all the recipes in the user's recipe list. + * + * @param recipeListToPrint recipeList of user + * + **/ public void listRecipe(RecipeList recipeListToPrint) { listRecipes(recipeListToPrint, "There is nothing to list.", "These are the recipes you have"); } + + /** + * This method is designed to print all the available recipes in the user's recipe list. + * + * @param recipeListToPrint recipeList of user + * + **/ public void listAvailableRecipes(RecipeList recipeListToPrint) { listRecipes(recipeListToPrint, "There are no available recipes.", "These are the recipes you can cook"); @@ -120,35 +147,46 @@ private void listRecipes(RecipeList recipeListToPrint, String emptyListMsg, Stri * @author AbijithRam */ public void printHelp() { - printMessage("These are the operations you can do. Please follow the proper input" - + " formats while typing."); - printMessage("1. Add Recipe: add /r {recipe name}"); - printMessage("2. View Recipe: view {index number}"); - printMessage("3. Edit Recipe: edit {recipe name}"); - printMessage("4. Delete Recipe: delete {index number} or delete {starting index-ending index} or"); - printMessage("delete /r {recipe name} or delete /r all"); + printMessage("These are the 21 operations you can do. Please follow the proper input" + + " formats while typing."); + printSeparator(); + printMessage("1. Add Recipe: add /r {RECIPE_NAME}"); + printMessage("2. Edit Recipe: edit /r {RECIPE_NAME}"); + printMessage("3. View Recipe: view {RECIPE_INDEX}"); + printMessage("4. Delete Recipe: delete {RECIPE_INDEX} or delete {START_INDEX-END_INDEX} or"); + printMessage(" delete /r {RECIPE_INDEX} or delete /r all"); printMessage("5. List All Recipes: list"); printMessage("6. List Available Recipes: available"); - printMessage("7. Add Single Recipe to Weekly Plan: weekly /add {recipe name} {quantity}"); - printMessage("8. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {recipe1 name} /q {quantity1}"); - printMessage(" /r {recipe2 name} /q {quantity2}"); - printMessage("9. Delete Single Recipe from Weekly Plan: weekly /delete {recipe name} {quantity}"); - printMessage("10. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {recipe1 name}"); - printMessage(" /q {quantity1} /r {recipe2 name} /q {quantity2}"); - printMessage("11. View Weekly Plan: weeklyplan"); - printMessage("12. Marking recipe in weekly plan as done: weekly /done RECIPE_NAME"); - printMessage("13. Clearing weekly plan: weekly /clear"); - printMessage("14. View Weekly Ingredients: weeklyingredients"); - printMessage("15. Give a random recipe: random"); - printMessage("16. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && " - + "...}"); - printMessage("17. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ." - + "..}"); - printMessage("18. Exit: bye"); - printMessage("HOW TO ADD INGREDIENTS?"); - printMessage("ingredient1_name=ingredient1_quantity ingredient2_name=ingredient2_quantity ..."); + printMessage("7. View Weekly Plan: weeklyplan"); + printMessage("8. View Weekly Ingredients: weeklyingredients"); + printMessage("9. Add Single Recipe to Weekly Plan: weekly /add {RECIPE_NAME} {QUANTITY}"); + printMessage("10. Add Multiple Recipes to Weekly Plan: weekly /multiadd /r {RECIPE1_NAME} /q {QUANTITY1}"); + printMessage(" /r {RECIPE2_NAME} /q {QUANTITY2}"); + printMessage("11. Delete Single Recipe from Weekly Plan: weekly /delete {RECIPE_NAME} {QUANTITY}"); + printMessage("12. Delete Multiple Recipes from Weekly Plan: weekly /multidelete /r {RECIPE1_NAME}"); + printMessage(" /q {QUANTITY1} /r {RECIPE2_NAME} /q {QUANTITY2}"); + printMessage("13. Marking recipe in weekly plan as done: weekly /done {RECIPE_NAME}"); + printMessage("14. Clear weekly plan: weekly /clear"); + printMessage("15. Tagging/Categorizing Recipes: tag {LABEL_name} << {RECIPE_NAME && RECIPE_NAME && ...}"); + printMessage("16. Removing recipes from a Tag: tag {LABEL_name} >> {RECIPE_NAME && RECIPE_NAME && ...}"); + printMessage("17. Add User Ingredient: add_i /n {INGREDIENT_NAME} /c {QUANTITY} /d {DATE}"); + printMessage("18. Delete User Ingredient: del_i /n {INGREDIENT_NAME} /c {QUANTITY}"); + printMessage("19. View User Ingredients: view_ingredients"); + printMessage("20. Exit Recipe Manager: bye"); + printMessage("21. Help Tab: help"); + printSeparator(); + printMessage("NOTE:"); + printMessage("* Curly brackets {} are just to indicate what goes inside the command!"); + printMessage("* No need to type them while entering commands!"); } + + /** + * This method is designed to print the user ingredients. + * + * @param userIngredients ingredient list of user + * + **/ public void printUserIngredients(IngredientList userIngredients) { if (userIngredients.isEmpty()) { printMessage("Your ingredient list is empty!"); From 4d2827df6c8d67122d79ac301b34559cbac04974 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Mon, 10 Apr 2023 10:42:25 +0700 Subject: [PATCH 243/252] update PPP & DG --- docs/DeveloperGuide.md | 19 +++++++++++-------- docs/team/gurmankalkat.md | 7 +++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 30a1d3e526..d9d069b262 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -361,8 +361,6 @@ The sequence diagram below shows how this feature works: ![](./UML/Implementation/ListAvailableFunction/availableSequenceDiagram.drawio.png) - - ### Delete Recipes Feature The current implementation: @@ -376,16 +374,21 @@ It is implemented through the following step: 1. When the user enters an input with the first word being `delete`, the input is passed to the `Parser` component. 2. In `Parser`, `parseDeleteRecipe()` is executed to identify whether the user wants to delete all - recipes, a single - recipe, or range of recipes. + recipes, a single recipe, or range of recipes. + + - If user inputs `delete /r {some recipe or all}`, assume user has inputted a recipe name or all. + - If user inputs `delete {index or range}`, assume user has inputted an index or range. + - Checks in place to ensure user has inputted recipe(s) in the correct format. + - Checks in place to ensure user is inputting a recipe that is currently in the list, a valid range, or a + valid index. + + `parseDeleteRecipe()` will return the name of the recipe that was just deleted. + 3. In `RecipeList`, `deleteRecipe()` is executed to delete the recipe at whatever index is passed as - a parameter, - and return the `Recipe` object at that index/the one just deleted. + a parameter, and return the `Recipe` object at that index/the one just deleted. ![](./UML/Implementation/DeleteFunction/DeleteFunction.jpg) - - ### Add Recipes Feature The current implementation: diff --git a/docs/team/gurmankalkat.md b/docs/team/gurmankalkat.md index 433ae81150..3dfe378ad0 100644 --- a/docs/team/gurmankalkat.md +++ b/docs/team/gurmankalkat.md @@ -22,11 +22,14 @@ apps. * [#34](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/34) * Added exception handler for `delete` feature * [#34](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/34) + * [#150](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/150) * Wrote tests for `delete`, `weeklyingredients` and `weekly /clear` features * [#50](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/50) * [#20](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/20/files) - * Updated `add` feature so users can input all ingredients in one line and processed accurately - * [137](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/137) + * [#150](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/150) + * Updated `add` feature so users can input all ingredients in one line with `and` between ingredients (code was + not used in final implementation as we decided to take a different approach) + * [#137](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/137) * __Documentation__: From 3189add05381f9d59125a7a9aa5a62b5d2e70773 Mon Sep 17 00:00:00 2001 From: jaredoong <88092096+jaredoong@users.noreply.github.com> Date: Mon, 10 Apr 2023 12:46:37 +0800 Subject: [PATCH 244/252] Update DeveloperGuide.md Fix numbering of subsystem diagrams not showing up properly in github pages --- docs/DeveloperGuide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index d9d069b262..d71626e2e2 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -79,15 +79,15 @@ respectively. The class diagrams below shows the subsystems for recipes, ingredi plan. For the class diagrams, `Meal360` and the `Ui` component are not shown for simplicity. Additionally, methods irrelevant to the subsystem shown are also omitted for simplicity. -1. Recipe related +- Recipe related ![](./UML/Architecture/RecipeRelated.png) -2. Ingredient related +- Ingredient related ![](./UML/Architecture/IngredientRelated.png) -3. WeeklyPlan related +- WeeklyPlan related ![](./UML/Architecture/WeeklyPlanRelated.png) From b253c9a4a150423179ce0e51eb9ef426911c9fdf Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 13:24:47 +0800 Subject: [PATCH 245/252] Fix weekly planner bug Fix bug where weekly /done not being read properly --- src/main/java/seedu/meal360/Parser.java | 48 +++++++++++++++++-------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index a03cedf413..9a251b6e9f 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -20,8 +20,8 @@ public class Parser { Ui ui = new Ui(); - String recipeErrorMessage1 = "Wrong Format or Invalid Quantity. Please enter ingredients properly " + - "[eg:chicken=100]"; + String recipeErrorMessage1 = + "Wrong Format or Invalid Quantity. Please enter ingredients properly " + "[eg:chicken=100]"; String recipeErrorMessage2 = "Enter \"done\" when finished entering ingredients!"; @@ -139,7 +139,8 @@ public Recipe parseAddRecipe(String[] input, RecipeList recipeList) { if (line.equals("done")) { ui.printSeparator(); if (addedIngredient == 0 || ingredients.size() == 0) { - ui.printMessage("Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); + ui.printMessage( + "Add at least 1 ingredient before entering 'done'! [eg: chicken=100]"); ui.printSeparator(); } else { break; @@ -372,6 +373,7 @@ public Recipe parseEditRecipe(String[] input, RecipeList recipeList) { } //@@author gurmankalkat + /** * This method deletes a single, range, or all recipes. * @@ -389,11 +391,11 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { Integer.parseInt(input[1]); } } catch (NumberFormatException e) { - throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in the " + - "correct format."); + throw new ArrayIndexOutOfBoundsException( + "Please enter a valid recipe number, name, or range in the " + "correct format."); } catch (ArrayIndexOutOfBoundsException e) { - throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in " + - "the correct format."); + throw new ArrayIndexOutOfBoundsException( + "Please enter a valid recipe number, name, or range in " + "the correct format."); } if (input[1].contains("/r")) { // skip over /r in recipe name @@ -422,26 +424,27 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { recipeIndex++; } if (!recipeFound) { - throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in " + - "the correct format."); + throw new ArrayIndexOutOfBoundsException( + "Please enter a valid recipe number, name, or range in " + "the correct format."); } return recipeList.deleteRecipe(recipeIndex).getName(); } - // user inputted index of recipe in list + // user inputted index of recipe in list } else { // deleting a range of recipes if (input[1].length() >= 3 && input[1].contains("-")) { String[] range = input[1].trim().split("-"); if (range.length != 2) { - throw new ArrayIndexOutOfBoundsException("Please enter a valid recipe number, name, or range in " + - "the correct format."); + throw new ArrayIndexOutOfBoundsException( + "Please enter a valid recipe number, name, or range in " + "the correct format."); } int startIndex = Integer.parseInt(range[0]); int endIndex = Integer.parseInt(range[1]); startIndex -= 1; endIndex -= 1; if (startIndex < 0 || endIndex >= recipeList.size() || endIndex < startIndex) { - throw new IndexOutOfBoundsException("Please enter a valid recipe number, name, or range."); + throw new IndexOutOfBoundsException( + "Please enter a valid recipe number, name, or range."); } int newSize = recipeList.size() - ((endIndex - startIndex) + 1); String rangeRecipes = ""; @@ -451,11 +454,12 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { rangeRecipes = String.valueOf( new StringBuilder(rangeRecipes.substring(0, rangeRecipes.length() - 2))); return rangeRecipes; - // deleting a single recipe + // deleting a single recipe } else { int recipeIndex = Integer.parseInt(input[1]); if (recipeIndex <= 0 || recipeIndex > recipeList.size()) { - throw new IndexOutOfBoundsException("Please enter a valid recipe number, name, or range."); + throw new IndexOutOfBoundsException( + "Please enter a valid recipe number, name, or range."); } recipeIndex = Integer.parseInt(input[1]); // need to subtract 1 since list is 1-based @@ -465,6 +469,7 @@ public String parseDeleteRecipe(String[] input, RecipeList recipeList) { } //@@author junenita + /** * Extract inputs from users whether it is adding recipes to a tag or removing recipe from a tag. * Then, proceed to add or remove the recipes from the tag, and returns a string whether @@ -512,6 +517,7 @@ public String parseTagRecipe(String[] inputs, RecipeList recipeList) } //@@author junenita + /** * Extract the tag label and recipes. Then, proceed to add the recipes to the tag, * and returns the tag label that users modified @@ -552,6 +558,7 @@ public String parseAddRecipeTag(String command, RecipeList recipeList) throws No } //@@author junenita + /** * Extract the tag label and recipes. Then, proceed to remove the recipes from the tag, * and returns the tag label that users modified @@ -611,6 +618,7 @@ public String parseRemoveRecipeTag(String command, RecipeList recipeList) } //@@author junenita + /** * Extract the filters from users' input. Then, proceed to extract the recipes by the filters. * @@ -652,6 +660,7 @@ public RecipeList parseListRecipe(String[] inputs, RecipeList recipeList) } //@@author jaredoong + /** * Extract the recipe index that the users wishes to view. Then, proceed to extract the recipe and returns * the recipe. @@ -689,6 +698,7 @@ public Recipe parseViewRecipe(String[] command, RecipeList recipes) { } //@@author AbijithRam + /** * This method is designed to find the index of a recipe from * the recipe list of the user and return the recipe. @@ -710,6 +720,7 @@ public Recipe parseViewRecipe(String recipeName, RecipeList recipes) { } //@@author junenita + /** * Returns a Recipe object that contain a recipe's name and ingredients. * @@ -726,6 +737,7 @@ public Recipe parseRandomRecipe(RecipeList recipes) throws NoRecipeException { } //@@author jaredoong + /** * Checks whether the user wants to edit single, multiple, or clear all the recipes in the weekly plan. * Then, return a WeeklyPlan object that contains the recipes that the user wants to add or delete. @@ -753,6 +765,7 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); break; case "/clear": + case "/done": updatedWeeklyPlan = new WeeklyPlan(); break; default: @@ -765,6 +778,7 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) } //@@author jaredoong + /** * Parses the user input to extract the single recipe that the user wants to add or delete from the weekly * plan. @@ -814,6 +828,7 @@ private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipe } //@@author jaredoong + /** * Parses the user input to extract the multiple recipes that the user wants to add or delete from the * weekly plan. @@ -917,6 +932,7 @@ public LocalDate parseDate(String input) { } //@@author jaredoong + /** * Parses the user input to extract the ingredient name, quantity, and expiry date that the user wants to * add to the ingredient list. Returns the Ingredient object that contains parsed data. @@ -977,6 +993,7 @@ public Ingredient parseAddUserIngredients(String[] command) } //@@author jaredoong + /** * Parses the user input to extract the ingredient name and quantity that the user wants to delete from * the ingredient list. Returns the Ingredient object that contains parsed data. @@ -1035,6 +1052,7 @@ public Ingredient parseDeleteUserIngredients(String[] command) } //@@author jaredoong + /** * Parses the user input to extract the recipe which the user wants to mark as done. Returns the recipe * name to be deleted from the weekly plan. From d4aaff8ff0bb5ae28a2a7929cc03c3fe652692ca Mon Sep 17 00:00:00 2001 From: JuneNita Date: Mon, 10 Apr 2023 15:16:29 +0800 Subject: [PATCH 246/252] remove case-sensitive --- docs/UserGuide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index ddf1247632..e7b3e7617b 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -180,7 +180,7 @@ Adding one or more recipes into a tag, so that users can organize the recipes in Format: `tag LABEL << [RECIPE_NAME && RECIPE_NAME && ...]` * `LABEL` is required, and replace with the tag label that user want to - add the recipes into. This is case-sensitive. + add the recipes into. * At least one `RECIPE_NAME` is required. * To add multiple recipes into the tag, use `&&` followed by next `RECIPE_NAME`. @@ -198,7 +198,7 @@ Remove recipes from a specific tag. Format: `tag LABEL >> [RECIPE_NAME && RECIPE_NAME && ...]` * `LABEL` is required, and replace with the tag label that user want to - remove the recipes from. This is case-sensitive. + remove the recipes from. * At least one `RECIPE_NAME` is required. * To remove multiple recipes from the tag, use `&&` followed by next `RECIPE_NAME`. From 4d4b5583e9e5ca570f3e8d3866e7957c9ccd0264 Mon Sep 17 00:00:00 2001 From: Gurman Kalkat Date: Mon, 10 Apr 2023 17:52:14 +0800 Subject: [PATCH 247/252] fix help command for delete --- src/main/java/seedu/meal360/Ui.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/meal360/Ui.java b/src/main/java/seedu/meal360/Ui.java index 2898d89fe1..814995f6b6 100644 --- a/src/main/java/seedu/meal360/Ui.java +++ b/src/main/java/seedu/meal360/Ui.java @@ -154,7 +154,7 @@ public void printHelp() { printMessage("2. Edit Recipe: edit /r {RECIPE_NAME}"); printMessage("3. View Recipe: view {RECIPE_INDEX}"); printMessage("4. Delete Recipe: delete {RECIPE_INDEX} or delete {START_INDEX-END_INDEX} or"); - printMessage(" delete /r {RECIPE_INDEX} or delete /r all"); + printMessage(" delete /r {RECIPE_NAME} or delete /r all"); printMessage("5. List All Recipes: list"); printMessage("6. List Available Recipes: available"); printMessage("7. View Weekly Plan: weeklyplan"); From 5933d39d8461d8e82cb3a695571c5bc1bd9f9f0d Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 19:39:53 +0800 Subject: [PATCH 248/252] Update error messages Edit error messages to give users better idea on the error --- docs/DeveloperGuide.md | 3 +- src/main/java/seedu/meal360/Parser.java | 218 +++++++++++------- .../IngredientNotFoundException.java | 4 + src/test/java/seedu/meal360/Meal360Test.java | 105 +++++++-- 4 files changed, 226 insertions(+), 104 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index d71626e2e2..12ee47abe1 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -644,8 +644,7 @@ driven app. ### Non-Functional Requirements 1. Should work on any _mainstream OS_ as long as it has Java 11 or above installed. -2. The number of recipes and user ingredients is limited to only 1000 items each. -3. A user with above average typing speed for regular English text (i.e. not code, not system +2. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse, especially for the more advanced commands that allow for editing multiple items at once. diff --git a/src/main/java/seedu/meal360/Parser.java b/src/main/java/seedu/meal360/Parser.java index 9a251b6e9f..d481e0eafd 100644 --- a/src/main/java/seedu/meal360/Parser.java +++ b/src/main/java/seedu/meal360/Parser.java @@ -1,5 +1,6 @@ package seedu.meal360; +import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.HashMap; import java.util.Objects; @@ -755,26 +756,31 @@ public WeeklyPlan parseWeeklyPlan(String[] command, RecipeList recipes) throws IllegalArgumentException, NumberFormatException, InvalidRecipeNameException, InvalidValueException { WeeklyPlan updatedWeeklyPlan; - switch (command[1]) { - case "/add": - case "/delete": - updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); - break; - case "/multiadd": - case "/multidelete": - updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); - break; - case "/clear": - case "/done": - updatedWeeklyPlan = new WeeklyPlan(); - break; - default: + try { + switch (command[1]) { + case "/add": + case "/delete": + updatedWeeklyPlan = parseEditSingleWeeklyPlan(command, recipes); + break; + case "/multiadd": + case "/multidelete": + updatedWeeklyPlan = parseEditMultiWeeklyPlan(command, recipes); + break; + case "/clear": + case "/done": + updatedWeeklyPlan = new WeeklyPlan(); + break; + default: + throw new InvalidParameterException(); + } + + return updatedWeeklyPlan; + } catch (ArrayIndexOutOfBoundsException | InvalidParameterException error) { throw new IllegalArgumentException( - "Please indicate if you would want to add to, delete from, or clear the weekly " - + "plan."); + "Please indicate if you would want to add to, delete from, clear weekly plan, or mark " + + "as done."); } - return updatedWeeklyPlan; } //@@author jaredoong @@ -799,13 +805,15 @@ private WeeklyPlan parseEditSingleWeeklyPlan(String[] command, RecipeList recipe int numDays; if (command.length < 4) { - throw new IllegalArgumentException("Please enter the command in the correct format."); + throw new IllegalArgumentException( + "Please enter the command in the correct format with all parameters provided."); } try { numDays = Integer.parseInt(command[command.length - 1]); } catch (NumberFormatException e) { - throw new NumberFormatException("Please enter a number between 1 to 1000 for the quantity."); + throw new NumberFormatException( + "Please ensure that you entered a valid quantity as the last argument."); } if (numDays > 1000 || numDays < 1) { @@ -848,7 +856,8 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes InvalidRecipeNameException { int quantity; if (command.length < 6) { - throw new IllegalArgumentException("Please enter the command in the correct format."); + throw new IllegalArgumentException( + "Please enter the command in the correct format with all parameters provided."); } WeeklyPlan recipesToEdit = new WeeklyPlan(); @@ -868,6 +877,8 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } catch (NumberFormatException e) { throw new NumberFormatException( "Please enter a positive number between 1 to 1000 for the quantity."); + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException("Please ensure a number is provided after /q."); } if (quantity < 1 || quantity > 1000) { throw new InvalidValueException( @@ -877,9 +888,17 @@ private WeeklyPlan parseEditMultiWeeklyPlan(String[] command, RecipeList recipes } } - // Checks that command is entered in the correct + // Checks that command is entered in the correct format if (startIndices.size() != endIndices.size() || startIndices.size() == 0) { - throw new IllegalArgumentException("Please enter the command in the correct format."); + throw new IllegalArgumentException("Please ensure the number of /r and /q are the same."); + } + + // Checks that command flags entered in correct order + for (int i = 0; i < startIndices.size(); i++) { + if (endIndices.get(i) < startIndices.get(i)) { + throw new IllegalArgumentException( + "Please ensure that the /r and /q flags are entered in the correct order."); + } } // Building the recipe names @@ -950,43 +969,54 @@ public Ingredient parseAddUserIngredients(String[] command) Integer ingredientCount = null; String expiryDate = null; - for (int i = 1; i < command.length; i++) { - switch (command[i]) { - case "/n": - StringBuilder nameBuilder = new StringBuilder(); - while (++i < command.length && !command[i].startsWith("/")) { - if (nameBuilder.length() > 0) { - nameBuilder.append(" "); + try { + for (int i = 1; i < command.length; i++) { + switch (command[i]) { + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); + } + nameBuilder.append(command[i]); } - nameBuilder.append(command[i]); - } - ingredientName = nameBuilder.toString(); - i--; // Move back to the previous flag - break; - case "/c": - try { - ingredientCount = Integer.parseInt(command[++i]); - } catch (NumberFormatException e) { - throw new NumberFormatException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag - if (ingredientCount < 1 || ingredientCount > 1000) { - throw new InvalidValueException( - "Please enter a positive number between 1 to 1000 for the quantity."); + // Check if ingredient name is empty + if (ingredientName.isEmpty()) { + throw new IllegalArgumentException("Ingredient name cannot be empty."); + } + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + break; + case "/d": + expiryDate = command[++i]; + break; + default: + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name, count, and expiry date."); } - break; - case "/d": - expiryDate = command[++i]; - break; - default: - throw new IllegalArgumentException("Missing required information. Please provide " - + "ingredient name, count, and expiry date."); } + } catch (ArrayIndexOutOfBoundsException error) { + throw new ArrayIndexOutOfBoundsException( + "Missing required information. Please provide ingredient name, count, and expiry date."); } if (ingredientName == null || ingredientCount == null || expiryDate == null) { - throw new IllegalArgumentException("Missing required information. Please use /n, /c, and /d."); + throw new IllegalArgumentException("Missing required information. Please provide " + + "ingredient name, count, and expiry date."); } return new Ingredient(ingredientName, ingredientCount, expiryDate); @@ -1012,40 +1042,51 @@ public Ingredient parseDeleteUserIngredients(String[] command) String ingredientName = null; Integer ingredientCount = null; - for (int i = 1; i < command.length; i++) { - switch (command[i]) { - case "/n": - StringBuilder nameBuilder = new StringBuilder(); - while (++i < command.length && !command[i].startsWith("/")) { - if (nameBuilder.length() > 0) { - nameBuilder.append(" "); + try { + for (int i = 1; i < command.length; i++) { + switch (command[i]) { + case "/n": + StringBuilder nameBuilder = new StringBuilder(); + while (++i < command.length && !command[i].startsWith("/")) { + if (nameBuilder.length() > 0) { + nameBuilder.append(" "); + } + nameBuilder.append(command[i]); } - nameBuilder.append(command[i]); - } - ingredientName = nameBuilder.toString(); - i--; // Move back to the previous flag - break; - case "/c": - try { - ingredientCount = Integer.parseInt(command[++i]); - } catch (NumberFormatException e) { - throw new NumberFormatException( - "Please enter a positive number between 1 to 1000 for the quantity."); - } + ingredientName = nameBuilder.toString(); + i--; // Move back to the previous flag - if (ingredientCount < 1 || ingredientCount > 1000) { - throw new InvalidValueException( - "Please enter a positive number between 1 to 1000 for the quantity."); + // Check if ingredient name is empty + if (ingredientName.isEmpty()) { + throw new IllegalArgumentException("Ingredient name cannot be empty."); + } + break; + case "/c": + try { + ingredientCount = Integer.parseInt(command[++i]); + } catch (NumberFormatException e) { + throw new NumberFormatException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + + if (ingredientCount < 1 || ingredientCount > 1000) { + throw new InvalidValueException( + "Please enter a positive number between 1 to 1000 for the quantity."); + } + break; + default: + throw new IllegalArgumentException( + "Missing required information. Please provide ingredient name and count."); } - break; - default: - throw new IllegalArgumentException( - "Missing required information. Please provide " + "ingredient name and count."); } + } catch (ArrayIndexOutOfBoundsException error) { + throw new ArrayIndexOutOfBoundsException( + "Missing required information. Please provide ingredient name and count."); } if (ingredientName == null || ingredientCount == null) { - throw new IllegalArgumentException("Missing required information. Please use /n and /c."); + throw new IllegalArgumentException( + "Missing required information. Please provide ingredient name and count."); } return new Ingredient(ingredientName, ingredientCount, "01/01/2020"); @@ -1084,15 +1125,18 @@ public String parseMarkDone(String[] command, IngredientList userIngredients, We throw new IllegalArgumentException("Recipe does not exist in weekly plan."); } - HashMap ingredients = recipes.findByName(recipeName).getIngredients(); - for (String ingredient : ingredients.keySet()) { - int currentCount = userIngredients.findIngredientCount(ingredient); - if (currentCount < ingredients.get(ingredient)) { - throw new IllegalArgumentException( - "You do not have enough ingredients to mark this recipe as done."); + try { + HashMap ingredients = recipes.findByName(recipeName).getIngredients(); + for (String ingredient : ingredients.keySet()) { + int currentCount = userIngredients.findIngredientCount(ingredient); + if (currentCount < ingredients.get(ingredient)) { + throw new IngredientNotFoundException(); + } } + return recipeName; + } catch (IngredientNotFoundException e) { + throw new IngredientNotFoundException( + "You do not have enough ingredients to mark this recipe as done."); } - - return recipeName; } } diff --git a/src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java b/src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java index 718367d593..3cdc934160 100644 --- a/src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java +++ b/src/main/java/seedu/meal360/exceptions/IngredientNotFoundException.java @@ -4,4 +4,8 @@ public class IngredientNotFoundException extends Exception { public IngredientNotFoundException(String message) { super(message); } + + public IngredientNotFoundException() { + super("Ingredient not found"); + } } diff --git a/src/test/java/seedu/meal360/Meal360Test.java b/src/test/java/seedu/meal360/Meal360Test.java index bd74fc3127..7ef7810e0e 100644 --- a/src/test/java/seedu/meal360/Meal360Test.java +++ b/src/test/java/seedu/meal360/Meal360Test.java @@ -308,7 +308,8 @@ public void testDeleteRecipe() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(ArrayIndexOutOfBoundsException.class, e.getClass()); - assertEquals("Please enter a valid recipe number, name, or range in the correct format.", e.getMessage()); + assertEquals("Please enter a valid recipe number, name, or range in the correct format.", + e.getMessage()); } } @@ -410,7 +411,8 @@ public void testAddWeeklyPlan() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(NumberFormatException.class, e.getClass()); - assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + assertEquals("Please ensure that you entered a valid quantity as the last argument.", + e.getMessage()); } // Testing negative case (recipe name is not specified) @@ -422,7 +424,8 @@ public void testAddWeeklyPlan() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please enter the command in the correct format with all parameters provided.", + e.getMessage()); } // Testing negative case (quantity is not specified) @@ -434,7 +437,8 @@ public void testAddWeeklyPlan() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please enter the command in the correct format with all parameters provided.", + e.getMessage()); } // Testing negative case (quantity specified is not an integer) @@ -446,7 +450,8 @@ public void testAddWeeklyPlan() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(NumberFormatException.class, e.getClass()); - assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + assertEquals("Please ensure that you entered a valid quantity as the last argument.", + e.getMessage()); } // Testing negative case (quantity specified causes integer overflow) @@ -458,7 +463,34 @@ public void testAddWeeklyPlan() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(NumberFormatException.class, e.getClass()); - assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + assertEquals("Please ensure that you entered a valid quantity as the last argument.", + e.getMessage()); + } + + // Testing negative case (missing all arguments) + try { + String userInput = "weekly"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please indicate if you would want to add to, delete from, clear weekly plan, or " + + "mark as done.", e.getMessage()); + } + + // Testing negative case (arguments are not in the correct order) + try { + String userInput = "weekly /add 1 burger"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please ensure that you entered a valid quantity as the last argument.", + e.getMessage()); } } @@ -578,7 +610,7 @@ public void testAddMultiWeeklyPlan() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please ensure the number of /r and /q are the same.", e.getMessage()); } // Testing negative case (quantity is not specified) @@ -590,7 +622,7 @@ public void testAddMultiWeeklyPlan() { assert false; // Not supposed to reach this line } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please ensure the number of /r and /q are the same.", e.getMessage()); } // Testing negative case (quantity given results in integer overflow) @@ -605,6 +637,19 @@ public void testAddMultiWeeklyPlan() { assertEquals("Please enter a positive number between 1 to 1000 for the quantity.", e.getMessage()); } + + // Testing negative case (arguments are not in the correct order) + try { + String userInput = "weekly /multiadd /q 1 /r burger"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.addPlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please ensure that the /r and /q flags are entered in the correct order.", + e.getMessage()); + } } @Test @@ -716,7 +761,8 @@ public void testDeleteWeeklyPlan() { assert false; // Not supposed to reach here } catch (Exception e) { assertEquals(NumberFormatException.class, e.getClass()); - assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + assertEquals("Please ensure that you entered a valid quantity as the last argument.", + e.getMessage()); } // Testing negative case (quantity is not specified) @@ -728,7 +774,8 @@ public void testDeleteWeeklyPlan() { assert false; // Not supposed to reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please enter the command in the correct format with all parameters provided.", + e.getMessage()); } // Testing negative case (recipe name is not specified) @@ -740,7 +787,8 @@ public void testDeleteWeeklyPlan() { assert false; // Not supposed to reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please enter the command in the correct format with all parameters provided.", + e.getMessage()); } // Testing negative case (quantity results in integer overflow) @@ -752,7 +800,21 @@ public void testDeleteWeeklyPlan() { assert false; // Not supposed to reach here } catch (Exception e) { assertEquals(NumberFormatException.class, e.getClass()); - assertEquals("Please enter a number between 1 to 1000 for the quantity.", e.getMessage()); + assertEquals("Please ensure that you entered a valid quantity as the last argument.", + e.getMessage()); + } + + // Testing negative case (arguments are not in the correct order) + try { + String userInput = "weekly /delete 1 burger"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(NumberFormatException.class, e.getClass()); + assertEquals("Please ensure that you entered a valid quantity as the last argument.", + e.getMessage()); } } @@ -820,7 +882,7 @@ public void testDeleteMultiWeeklyPlan() { assert false; // Not supposed to reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please ensure the number of /r and /q are the same.", e.getMessage()); } // Testing negative case (quantity is not specified) @@ -832,7 +894,7 @@ public void testDeleteMultiWeeklyPlan() { assert false; // Not supposed to reach here } catch (Exception e) { assertEquals(IllegalArgumentException.class, e.getClass()); - assertEquals("Please enter the command in the correct format.", e.getMessage()); + assertEquals("Please ensure the number of /r and /q are the same.", e.getMessage()); } // Testing negative case (quantity is not a number) @@ -911,6 +973,19 @@ public void testDeleteMultiWeeklyPlan() { assertEquals(InvalidRecipeNameException.class, e.getClass()); assertEquals("Please indicate a valid recipe name.", e.getMessage()); } + + // Testing negative case (arguments are not in the correct order) + try { + String userInput = "weekly /multidelete /q 1 /r burger"; + String[] command = parser.cleanUserInput(userInput); + WeeklyPlan recipeMap = parser.parseWeeklyPlan(command, recipes); + weeklyPlan.deletePlans(recipeMap); + assert false; // Not supposed to reach this line + } catch (Exception e) { + assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals("Please ensure that the /r and /q flags are entered in the correct order.", + e.getMessage()); + } } //@@author gurmankalkat @@ -1251,7 +1326,7 @@ public void testWeeklyDone() { } assert false; // should not reach here } catch (Exception e) { - assertEquals(IllegalArgumentException.class, e.getClass()); + assertEquals(IngredientNotFoundException.class, e.getClass()); assertEquals("You do not have enough ingredients to mark this recipe as done.", e.getMessage()); } } From 1ba76baeced5424f92281ea0177f9e20fae1690f Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 20:11:00 +0800 Subject: [PATCH 249/252] Add graceful force exit Add catching of Ctrl-C/Ctrl-Z and attempts to save data before exiting --- src/main/java/seedu/meal360/Meal360.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/meal360/Meal360.java b/src/main/java/seedu/meal360/Meal360.java index f104b29ffd..bcd654b073 100644 --- a/src/main/java/seedu/meal360/Meal360.java +++ b/src/main/java/seedu/meal360/Meal360.java @@ -305,11 +305,15 @@ public static void main(String[] args) { String line; Scanner userInput = new Scanner(System.in); - do { - line = userInput.nextLine(); - receiveInput(line); - } while (!canExit); - - exitApp(); + try { + do { + line = userInput.nextLine(); + receiveInput(line); + } while (!canExit); + } catch (Exception error) { + ui.printMessage("Force exit detected, attempting to save data..."); + } finally { + exitApp(); + } } } From d5b4a5a9e1424a82314dc64514e93f2fd109e86b Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 20:16:14 +0800 Subject: [PATCH 250/252] Update PPP --- docs/team/jaredoong.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/team/jaredoong.md b/docs/team/jaredoong.md index ee8f825a2d..5d8dc68966 100644 --- a/docs/team/jaredoong.md +++ b/docs/team/jaredoong.md @@ -50,8 +50,6 @@ apps. * Added documentation for the following components: * `Meal360`, `RecipeList`, `IngredientList`, `WeeklyPlan`, `Database` - * Added documentation for the following classes: - * `Database`, `WeeklyPlan` * Added documentation for the following implementations: * Add Ingredient Feature * Delete Ingredient Feature @@ -62,7 +60,7 @@ apps. * __Contributions to the team-based tasks__: * Setting up of GitHub team org/repo * Maintaining issue tracker - * Release management (`v1.0`, `v2.0`) + * Release management (`v1.0`, `v2.0`, `v2.1`) * __Review/mentoring contributions__: * [#14](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/14), [#26](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/26), @@ -83,7 +81,9 @@ apps. [#121](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/121), [#122](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/122), [#130](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/130), - [#133](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/133) + [#133](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/133), + [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139), + * __Tools__: * Integrated third party library (GSON) to save and load data from databases. ([#39](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/39)) \ No newline at end of file From 540139e6ef75b758b46d4a2019e2ccab5b4296af Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 20:16:55 +0800 Subject: [PATCH 251/252] Fix PPP visual bug --- docs/team/jaredoong.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/team/jaredoong.md b/docs/team/jaredoong.md index 5d8dc68966..c2d95da666 100644 --- a/docs/team/jaredoong.md +++ b/docs/team/jaredoong.md @@ -82,7 +82,7 @@ apps. [#122](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/122), [#130](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/130), [#133](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/133), - [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139), + [#139](https://github.com/AY2223S2-CS2113-F10-3/tp/pull/139) * __Tools__: * Integrated third party library (GSON) to save and load data from From 50135b2ab45729189881e1ea6d6178898f9534aa Mon Sep 17 00:00:00 2001 From: jaredoong Date: Mon, 10 Apr 2023 20:28:08 +0800 Subject: [PATCH 252/252] Update testing to pass checks --- text-ui-test/EXPECTED.TXT | 71 ++++++++++++++++++++++++++++++++++++--- text-ui-test/input.txt | 18 ++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index a26c8f108e..da922933cc 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -79,10 +79,10 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please enter a valid recipe number. You entered abc, which is not a valid number. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Index 1 out of bounds for length 1 | +| Please indicate if you would want to add to, delete from, clear weekly plan, or mark as done. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please indicate if you would want to add to, delete from, or clear the weekly plan. | +| Please indicate if you would want to add to, delete from, clear weekly plan, or mark as done. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Please indicate a valid recipe name. | @@ -91,13 +91,74 @@ Welcome to Meal360, your ultimate Recipe Manager! | Please indicate a valid recipe name. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Your weekly plan is empty! | +| Please ensure that you entered a valid quantity as the last argument. | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Please enter a number between 1 to 1000 for the quantity. | +| I've added the recipes to your weekly plan! | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- -| Your weekly plan is empty! | +| Please ensure that you entered a valid quantity as the last argument. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please ensure that you entered a valid quantity as the last argument. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| I've deleted the recipes from your weekly plan! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your weekly plan: | +| avocado toast x5 | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Please ensure that you entered a valid quantity as the last argument. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your weekly plan: | +| avocado toast x5 | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Missing required information. Please provide ingredient name, count, and expiry date. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Ingredient name cannot be empty. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Ingredient successfully added! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your ingredient list: | +| carrot (99) [by:01/01/2020] | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Ingredient successfully added! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your ingredient list: | +| carrot (198) [by:01/01/2020] | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Ingredient successfully added! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your ingredient list: | +| carrot (297) [by:01/01/2020] | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Missing required information. Please provide ingredient name and count. | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Ingredients successfully deleted! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your ingredient list: | +| carrot (287) [by:01/01/2020] | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Ingredients successfully deleted! | +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +| Here is your ingredient list: | +| carrot (277) [by:01/01/2020] | ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- | Saving recipes... | diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index f0a2ddbdad..b4b9113b55 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -23,7 +23,25 @@ weekly weekly random name weekly /add random name 1 weekly /add test recipe name 1 +weekly /add 10 avocado toast +weekly /add avocado toast 10 +weekly /delete avocado toast +weekly /delete 10 avocado toast +weekly /delete avocado toast 5 weeklyplan weekly /delete test recipe name weeklyplan +add_i +add_i /n /c /d +add_i /n carrot /c 99 /d 01/01/2020 +view_ingredients +add_i /d 01/01/2020 /n carrot /c 99 +view_ingredients +add_i /c 99 /n carrot /d 01/01/2020 +view_ingredients +del_i +del_i /n carrot /c 10 +view_ingredients +del_i /c 10 /n carrot +view_ingredients bye \ No newline at end of file