From 6fcc6fb36066d94c67e6b4d2bf82601912472b3f Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Thu, 2 Mar 2023 23:40:47 +0800 Subject: [PATCH 001/210] Edit the about us file --- docs/AboutUs.md | 13 ++++++------- docs/team/Zhao_Lixiuqi.md | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 docs/team/Zhao_Lixiuqi.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..0e6bcffe26 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) | 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://avatars.githubusercontent.com/u/88603534?s=400&u=3007dc79299805aa3b8f71aeb61899ea9fb64f6e&v=4) | Zhao Lixiuqi | [Github](https://github.com/alexgoexercise) | [Portfolio](docs/team/Zhao_Lixiuqi.md) +![](https://via.placeholder.com/100.png?text=Photo) | Toh Hongfeng | [Github](https://github.com/Toh-HongFeng) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Li Mingyuan | [Github](https://github.com/mingyuannus) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Nguyen Duc Thang | [Github](https://github.com/Mnsd05) | [Portfolio](docs/team/johndoe.md) diff --git a/docs/team/Zhao_Lixiuqi.md b/docs/team/Zhao_Lixiuqi.md new file mode 100644 index 0000000000..8d85b84f82 --- /dev/null +++ b/docs/team/Zhao_Lixiuqi.md @@ -0,0 +1 @@ +I need to think of how to write this some day. From b071768ebf33c7cb28ffa28646d0a9e4347abcb8 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Thu, 2 Mar 2023 23:41:09 +0800 Subject: [PATCH 002/210] Revert "Edit the about us file" This reverts commit 6fcc6fb36066d94c67e6b4d2bf82601912472b3f. --- docs/AboutUs.md | 13 +++++++------ docs/team/Zhao_Lixiuqi.md | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 docs/team/Zhao_Lixiuqi.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0e6bcffe26..0f072953ea 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -1,8 +1,9 @@ # About us -Display | Name | Github Profile | Portfolio ---------|:------------:|:-------------------------------------------:|:---------: -![](https://avatars.githubusercontent.com/u/88603534?s=400&u=3007dc79299805aa3b8f71aeb61899ea9fb64f6e&v=4) | Zhao Lixiuqi | [Github](https://github.com/alexgoexercise) | [Portfolio](docs/team/Zhao_Lixiuqi.md) -![](https://via.placeholder.com/100.png?text=Photo) | Toh Hongfeng | [Github](https://github.com/Toh-HongFeng) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Li Mingyuan | [Github](https://github.com/mingyuannus) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Nguyen Duc Thang | [Github](https://github.com/Mnsd05) | [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) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) diff --git a/docs/team/Zhao_Lixiuqi.md b/docs/team/Zhao_Lixiuqi.md deleted file mode 100644 index 8d85b84f82..0000000000 --- a/docs/team/Zhao_Lixiuqi.md +++ /dev/null @@ -1 +0,0 @@ -I need to think of how to write this some day. From bfdc40205c6098d81b3b13d688763334f75a9541 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Thu, 2 Mar 2023 23:46:14 +0800 Subject: [PATCH 003/210] add tohhongfeng.md --- docs/AboutUs.md | 2 +- docs/team/johndoe.md | 6 ------ docs/team/tohhongfeng.md | 7 +++++++ 3 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 docs/team/johndoe.md create mode 100644 docs/team/tohhongfeng.md diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..7778d7f50a 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -5,5 +5,5 @@ 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) | Toh Hong Feng | [Github](https://github.com/Toh-HongFeng) | [Portfolio](docs/team/tohhongfeng.md) ![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md deleted file mode 100644 index ab75b391b8..0000000000 --- a/docs/team/johndoe.md +++ /dev/null @@ -1,6 +0,0 @@ -# John Doe - Project Portfolio Page - -## Overview - - -### Summary of Contributions diff --git a/docs/team/tohhongfeng.md b/docs/team/tohhongfeng.md new file mode 100644 index 0000000000..d7d6acd3d3 --- /dev/null +++ b/docs/team/tohhongfeng.md @@ -0,0 +1,7 @@ +# Toh Hong Feng - Project Portfolio Page + +## Overview + + +### Summary of Contributions +Set up team org and repo \ No newline at end of file From 72810b4628cffc9770389fa3ca6a5835f4f72dcc Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Thu, 2 Mar 2023 23:46:32 +0800 Subject: [PATCH 004/210] Edit the aboutus file --- docs/team/Zhao_Lixiuqi.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/team/Zhao_Lixiuqi.md diff --git a/docs/team/Zhao_Lixiuqi.md b/docs/team/Zhao_Lixiuqi.md new file mode 100644 index 0000000000..e69de29bb2 From d6c6598f3c071fb1fb7b28b74dabb46fbcd959cc Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Thu, 2 Mar 2023 23:47:07 +0800 Subject: [PATCH 005/210] Edit the about us file --- docs/AboutUs.md | 13 ++++++------- docs/team/Zhao_Lixiuqi.md | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..8387fcd4fb 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) | 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://avatars.githubusercontent.com/u/88603534?s=400&u=3007dc79299805aa3b8f71aeb61899ea9fb64f6e&v=4) | Zhao Lixiuqi | [Github](https://github.com/alexgoexercise) | [Portfolio](docs/team/Zhao_Lixiuqi.md) +![](https://via.placeholder.com/100.png?text=Photo) | Toh Hongfeng | [Github](https://github.com/Toh-HongFeng) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Li Mingyuan | [Github](https://github.com/mingyuannus) | [Portfolio](docs/team/johndoe.md) +![](https://via.placeholder.com/100.png?text=Photo) | Nguyen Duc Thang | [Github](https://github.com/Mnsd05) | [Portfolio](docs/team/johndoe.md) diff --git a/docs/team/Zhao_Lixiuqi.md b/docs/team/Zhao_Lixiuqi.md index e69de29bb2..64d83dd502 100644 --- a/docs/team/Zhao_Lixiuqi.md +++ b/docs/team/Zhao_Lixiuqi.md @@ -0,0 +1 @@ +I don't have any remarkable achievements ... I think I'm just a normal student. I'm not good at programming, but I'm willing to learn. \ No newline at end of file From 507ba3888c94783d3a784c926d1def7ecd2fab74 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Fri, 3 Mar 2023 07:31:04 +0800 Subject: [PATCH 006/210] Add Nguyen Duc Thang readme file --- docs/team/johndoe.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md index ab75b391b8..79f239cbce 100644 --- a/docs/team/johndoe.md +++ b/docs/team/johndoe.md @@ -1,6 +1,7 @@ -# John Doe - Project Portfolio Page +# Nguyen Duc Thang - Project Portfolio Page ## Overview - +A normal computer engineering student hoping to live a peaceful life. ### Summary of Contributions +Add Readme file for Nguyen Duc Thang. \ No newline at end of file From f400050a667104fa86b665ef6966c2e930b55694 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Fri, 3 Mar 2023 07:35:10 +0800 Subject: [PATCH 007/210] Add Readme file for Nguyen Duc Thang --- docs/team/johndoe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md index 79f239cbce..90a301828d 100644 --- a/docs/team/johndoe.md +++ b/docs/team/johndoe.md @@ -4,4 +4,4 @@ A normal computer engineering student hoping to live a peaceful life. ### Summary of Contributions -Add Readme file for Nguyen Duc Thang. \ No newline at end of file +Add Readme file for Nguyen Duc Thang - Project Portfolio Page. \ No newline at end of file From ee06ffc3bbb94f180382b397ffed7c8b1302bd1c Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 4 Mar 2023 22:30:24 +0800 Subject: [PATCH 008/210] Add three different new classes --- src/main/java/seedu/duke/Category.java | 109 +++++++++++++++++++++ src/main/java/seedu/duke/CategoryList.java | 63 ++++++++++++ src/main/java/seedu/duke/Event.java | 101 +++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 src/main/java/seedu/duke/Category.java create mode 100644 src/main/java/seedu/duke/CategoryList.java create mode 100644 src/main/java/seedu/duke/Event.java diff --git a/src/main/java/seedu/duke/Category.java b/src/main/java/seedu/duke/Category.java new file mode 100644 index 0000000000..a870d65ba0 --- /dev/null +++ b/src/main/java/seedu/duke/Category.java @@ -0,0 +1,109 @@ +package seedu.duke; + +import java.util.ArrayList; + +public class Category { + private String name; + + ArrayList events = new ArrayList<>(); + + /** + * A constructor with name. + */ + public Category(String name) { + this.name = name; + } + + /** + * Gets the name of the category. + * + * @return the name of the category + */ + public String getName() { + return name; + } + + /** + * Add the event to the list. + */ + public void addEvent(Event event) { + events.add(event); + } + + /** + * Delete the event from the list. + */ + public void deleteEvent(int index) { + events.remove(index); + } + + /** + * Gets the list of events. + */ + public void viewEventList() { + for (int i = 0; i < events.size(); i++) { + System.out.println(i + 1 + ". " + events.get(i).toString()); + } + } + + /** + * to edit the parameters of the event. + * + * @param index the index of the event in the list + * @param description the description of the event + * @param budget the budget of the event + */ + public void editEvent(int index, String description, int budget) { + events.get(index).setDescription(description); + events.get(index).setBudget(budget); + } + + /** + * to edit the parameters of the event. + * + * @param index the index of the event in the list + * @param description the description of the event + * @param budget the budget of the event + * @param expense the expense of the event + */ + public void editEvent(int index, String description, int budget, int expense) { + events.get(index).setDescription(description); + events.get(index).setBudget(budget); + events.get(index).setExpense(expense); + } + + /** + * Gets the total expense of the category. + * + * @return the total expense of the category + */ + public int getTotalBudget() { + int totalBudget = 0; + for (int i = 0; i < events.size(); i++) { + totalBudget += events.get(i).getBudget(); + } + return totalBudget; + } + + /** + * Gets the total expense of the category. + * + * @return the total expense of the category + */ + public int getTotalExpense() { + int totalExpense = 0; + for (int i = 0; i < events.size(); i++) { + totalExpense += events.get(i).getExpense(); + } + return totalExpense; + } + + /** + * Gets the remaining budget of the category. + * + * @return the remaining budget of the category + */ + public int getRemainingBudget() { + return getTotalBudget() - getTotalExpense(); + } +} \ No newline at end of file diff --git a/src/main/java/seedu/duke/CategoryList.java b/src/main/java/seedu/duke/CategoryList.java new file mode 100644 index 0000000000..0a656121b1 --- /dev/null +++ b/src/main/java/seedu/duke/CategoryList.java @@ -0,0 +1,63 @@ +package seedu.duke; + +import java.util.ArrayList; + +public class CategoryList { + public static ArrayList categories = new ArrayList(); + + /** + * Add the category to the list. + */ + public static void addCategory(String category) { + Category newCategory = new Category(category); + categories.add(newCategory); + } + + /** + * Find the category with specific keyword in the list. + * + * @param name the name of the category + */ + public static void findCategory(String name) { + int count = 0; + for (int i = 0; i < categories.size(); i++) { + if (categories.get(i).getName().contains(name)) { + count++; + System.out.println("index " + (i + 1) + ". " + categories.get(i).getName()); + } + if (count == 0) { + System.out.println("Category not found!"); + } + } + System.out.println("Category not found!"); + } + + /** + * Gets the category with specific index in the list. + * + * @param index the index of the category in the list + * @return + */ + public static Category getCategory(int index) { + return categories.get(index); + } + + /** + * Delete the category from the list. + * + * @param index the index of the category in the list + */ + public static void deleteCategory(int index) { + categories.remove(index); + } + + public static void viewCategoryList() { + for (int i = 0; i < categories.size(); i++) { + System.out.println(i + 1 + ". " + categories.get(i).getName()); + } + } + + public static void viewEventList(int index) { + categories.get(index).viewEventList(); + } +} \ No newline at end of file diff --git a/src/main/java/seedu/duke/Event.java b/src/main/java/seedu/duke/Event.java new file mode 100644 index 0000000000..a89ae5b820 --- /dev/null +++ b/src/main/java/seedu/duke/Event.java @@ -0,0 +1,101 @@ +package seedu.duke; + +public class Event { + private static final int DEFAULT_EXPENSE = 0; + private String description; + private int budget; + private int expense = DEFAULT_EXPENSE; + + /** + * A constructor with both description and budget. + */ + public Event(String description, int budget) { + this.description = description; + this.budget = budget; + } + + /** + * A constructor with all parameters. + */ + public Event(String description, int budget, int expense) { + this.description = description; + this.budget = budget; + this.expense = expense; + } + + /** + * Gets the description of the event. + * + * @return the description of the event + */ + public String getDescription() { + return description; + } + + /** + * Gets the budget of the event. + * + * @return the budget of the event + */ + public int getBudget() { + return budget; + } + + /** + * Gets the expense of the event. + * + * @return the expense of the event + */ + public int getExpense() { + return expense; + } + + /** + * Sets the description of the event. + * + * @param description the description of the event + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Sets the budget of the event. + * + * @param budget the budget of the event + */ + public void setBudget(int budget) { + this.budget = budget; + } + + /** + * Sets the expense of the event. + * + * @param expense the expense of the event + */ + public void setExpense(int expense) { + this.expense = expense; + } + + /** + * Checks if the event is over budget. + * + * @return true if the event is over budget, false otherwise + */ + public boolean isOverBudget() { + return expense > budget; + } + + /** + * Gets the remaining budget of the event. + * + * @return the remaining budget of the event + */ + public int remainingBudget() { + return budget - expense; + } + + public String toString() { + return description + " [budget]" + budget + " [expense]" + expense; + } +} \ No newline at end of file From 891efb37ac61b923512d1dd2aed144cc83096b8b Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 4 Mar 2023 22:33:27 +0800 Subject: [PATCH 009/210] Make sure the codes end with a new line --- src/main/java/seedu/duke/Category.java | 2 +- src/main/java/seedu/duke/CategoryList.java | 2 +- src/main/java/seedu/duke/Event.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/duke/Category.java b/src/main/java/seedu/duke/Category.java index a870d65ba0..14338c2e48 100644 --- a/src/main/java/seedu/duke/Category.java +++ b/src/main/java/seedu/duke/Category.java @@ -106,4 +106,4 @@ public int getTotalExpense() { public int getRemainingBudget() { return getTotalBudget() - getTotalExpense(); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/duke/CategoryList.java b/src/main/java/seedu/duke/CategoryList.java index 0a656121b1..bdecf9bf3b 100644 --- a/src/main/java/seedu/duke/CategoryList.java +++ b/src/main/java/seedu/duke/CategoryList.java @@ -60,4 +60,4 @@ public static void viewCategoryList() { public static void viewEventList(int index) { categories.get(index).viewEventList(); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/duke/Event.java b/src/main/java/seedu/duke/Event.java index a89ae5b820..86528644bd 100644 --- a/src/main/java/seedu/duke/Event.java +++ b/src/main/java/seedu/duke/Event.java @@ -98,4 +98,4 @@ public int remainingBudget() { public String toString() { return description + " [budget]" + budget + " [expense]" + expense; } -} \ No newline at end of file +} From 1b6dde039dc9fedd2950294d7eecfdca54fc2c31 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 4 Mar 2023 22:37:49 +0800 Subject: [PATCH 010/210] Change the ordering of defining variables --- src/main/java/seedu/duke/Category.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/Category.java b/src/main/java/seedu/duke/Category.java index 14338c2e48..6f286b26e6 100644 --- a/src/main/java/seedu/duke/Category.java +++ b/src/main/java/seedu/duke/Category.java @@ -3,10 +3,10 @@ import java.util.ArrayList; public class Category { - private String name; - ArrayList events = new ArrayList<>(); + private String name; + /** * A constructor with name. */ From 8cca72174354b82461b6b35b0548b65b22c961cb Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Mon, 6 Mar 2023 16:35:18 +0800 Subject: [PATCH 011/210] add skeletal Storage class --- src/main/java/seedu/duke/Storage.java | 89 +++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/main/java/seedu/duke/Storage.java diff --git a/src/main/java/seedu/duke/Storage.java b/src/main/java/seedu/duke/Storage.java new file mode 100644 index 0000000000..80ca21bea4 --- /dev/null +++ b/src/main/java/seedu/duke/Storage.java @@ -0,0 +1,89 @@ +package seedu.duke; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Scanner; +import java.io.FileWriter; +import java.io.IOException; + +public class Storage { + /** + * Divider used to separate details of a task saved in file + */ + private static final String SAVEFILESEPARATOR = ", "; + private static String filePath = "DukeTaskList.txt"; + private static File textFile; + private static Scanner textFileScanner; + + public Storage() { + loadFromFile(); + } + + private static void setupFile() { + textFile = new File(filePath); + + try { + textFileScanner = new Scanner(textFile); + } catch (FileNotFoundException e) { + System.out.println("I cannot seem to access the saved tasks. Did you perhaps lock it away?"); + } + } + + /** + * Saves an ArrayList of tasks to DukeTaskList.txt file + * + * @param list ArrayList of tasks + */ + public static void saveToFile(ArrayList list) { + String writeToFile = ""; + + for (Event dukeTasks : list) { + // extracting details from task object + String[] dataToTextFile= {"", "", ""}; + dataToTextFile[0] = dukeTasks.toString(); + + // save task details split by regex ", " + writeToFile += dataToTextFile[0] + SAVEFILESEPARATOR + dataToTextFile[1] + SAVEFILESEPARATOR + dataToTextFile[2] + System.lineSeparator(); + } + + // write task list to text file + try { + textFile = new File(filePath); + FileWriter dukeWriter = new FileWriter(textFile); + dukeWriter.write(writeToFile); + dukeWriter.close(); + } catch (IOException e) { + System.out.println("I cannot seem to access the saved file. Did you perhaps delete it?"); + } + } + + /** + * Returns an ArrayList of tasks from DukeTaskList.txt file + * + * @return ArrayList of tasks + */ + public static ArrayList loadFromFile() { + ArrayList savedList = new ArrayList<>(); + setupFile(); + + while (textFileScanner.hasNext()) { + String[] loadTaskInfo = new String[3]; + loadTaskInfo = textFileScanner.nextLine().split(SAVEFILESEPARATOR, 3); + + // create tasks individually + switch (loadTaskInfo[0]) { + case "T": + break; + + case "D": + break; + + default: + break; + } + } + + return savedList; + } +} \ No newline at end of file From 7a5f23a2ef264a63f626f292bb30da52890104c1 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 7 Mar 2023 10:12:27 +0800 Subject: [PATCH 012/210] fix code quality for storage --- src/main/java/seedu/duke/Storage.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/duke/Storage.java b/src/main/java/seedu/duke/Storage.java index 80ca21bea4..768596739d 100644 --- a/src/main/java/seedu/duke/Storage.java +++ b/src/main/java/seedu/duke/Storage.java @@ -44,7 +44,8 @@ public static void saveToFile(ArrayList list) { dataToTextFile[0] = dukeTasks.toString(); // save task details split by regex ", " - writeToFile += dataToTextFile[0] + SAVEFILESEPARATOR + dataToTextFile[1] + SAVEFILESEPARATOR + dataToTextFile[2] + System.lineSeparator(); + writeToFile += dataToTextFile[0] + SAVEFILESEPARATOR + dataToTextFile[1] + + SAVEFILESEPARATOR + dataToTextFile[2] + System.lineSeparator(); } // write task list to text file @@ -86,4 +87,4 @@ public static ArrayList loadFromFile() { return savedList; } -} \ No newline at end of file +} From a985b4a3fdb774ccfc99dcb6cb69dd68a4328bf0 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 7 Mar 2023 16:38:43 +0800 Subject: [PATCH 013/210] Implement Command and Ui classes and rename Duke to Moneymind --- build.gradle | 4 +- src/main/java/seedu/duke/Duke.java | 21 -------- .../seedu/{duke => moneymind}/Category.java | 2 +- .../{duke => moneymind}/CategoryList.java | 2 +- src/main/java/seedu/moneymind/Command.java | 47 ++++++++++++++++ .../java/seedu/{duke => moneymind}/Event.java | 2 +- .../moneymind/InvalidCommandException.java | 5 ++ src/main/java/seedu/moneymind/Moneymind.java | 34 ++++++++++++ .../seedu/{duke => moneymind}/Storage.java | 2 +- src/main/java/seedu/moneymind/Ui.java | 54 +++++++++++++++++++ .../seedu/{duke => moneymind}/DukeTest.java | 2 +- text-ui-test/EXPECTED.TXT | 17 +++--- text-ui-test/input.txt | 3 +- 13 files changed, 158 insertions(+), 37 deletions(-) delete mode 100644 src/main/java/seedu/duke/Duke.java rename src/main/java/seedu/{duke => moneymind}/Category.java (99%) rename src/main/java/seedu/{duke => moneymind}/CategoryList.java (98%) create mode 100644 src/main/java/seedu/moneymind/Command.java rename src/main/java/seedu/{duke => moneymind}/Event.java (98%) create mode 100644 src/main/java/seedu/moneymind/InvalidCommandException.java create mode 100644 src/main/java/seedu/moneymind/Moneymind.java rename src/main/java/seedu/{duke => moneymind}/Storage.java (99%) create mode 100644 src/main/java/seedu/moneymind/Ui.java rename src/test/java/seedu/{duke => moneymind}/DukeTest.java (88%) diff --git a/build.gradle b/build.gradle index d5e548e85f..4ffd7f5e7d 100644 --- a/build.gradle +++ b/build.gradle @@ -29,11 +29,11 @@ test { } application { - mainClass = "seedu.duke.Duke" + mainClass = "seedu.moneymind.Moneymind" } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "moneymind" 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/duke/Category.java b/src/main/java/seedu/moneymind/Category.java similarity index 99% rename from src/main/java/seedu/duke/Category.java rename to src/main/java/seedu/moneymind/Category.java index 6f286b26e6..1de5b96300 100644 --- a/src/main/java/seedu/duke/Category.java +++ b/src/main/java/seedu/moneymind/Category.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.moneymind; import java.util.ArrayList; diff --git a/src/main/java/seedu/duke/CategoryList.java b/src/main/java/seedu/moneymind/CategoryList.java similarity index 98% rename from src/main/java/seedu/duke/CategoryList.java rename to src/main/java/seedu/moneymind/CategoryList.java index bdecf9bf3b..d0a92b61f2 100644 --- a/src/main/java/seedu/duke/CategoryList.java +++ b/src/main/java/seedu/moneymind/CategoryList.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.moneymind; import java.util.ArrayList; diff --git a/src/main/java/seedu/moneymind/Command.java b/src/main/java/seedu/moneymind/Command.java new file mode 100644 index 0000000000..d7c4881cb9 --- /dev/null +++ b/src/main/java/seedu/moneymind/Command.java @@ -0,0 +1,47 @@ +package seedu.moneymind; + +public class Command { + private CommandType type; + private String value; + + public Command(String input) throws InvalidCommandException { + String[] tokens = input.split(" ", 2); + + String command = tokens[0]; + + // assign command type only + switch (command) { + case "bye": + this.type = CommandType.EXIT; + break; + case "echo": + this.type = CommandType.ECHO; + break; + default: + throw new InvalidCommandException(); + } + + // process value based on command type, only for commands with parameters + switch (type) { + case ECHO: + this.value = tokens[1]; + break; + } + } + + public void execute(Ui ui) { + switch (type) { + case ECHO: + ui.echo(value); + break; + } + } + + public boolean isExit() { + return type == CommandType.EXIT; + } +} + +enum CommandType { + ECHO, EXIT +} diff --git a/src/main/java/seedu/duke/Event.java b/src/main/java/seedu/moneymind/Event.java similarity index 98% rename from src/main/java/seedu/duke/Event.java rename to src/main/java/seedu/moneymind/Event.java index 86528644bd..405e1ffa9d 100644 --- a/src/main/java/seedu/duke/Event.java +++ b/src/main/java/seedu/moneymind/Event.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.moneymind; public class Event { private static final int DEFAULT_EXPENSE = 0; diff --git a/src/main/java/seedu/moneymind/InvalidCommandException.java b/src/main/java/seedu/moneymind/InvalidCommandException.java new file mode 100644 index 0000000000..90b831ebcd --- /dev/null +++ b/src/main/java/seedu/moneymind/InvalidCommandException.java @@ -0,0 +1,5 @@ +package seedu.moneymind; + +public class InvalidCommandException extends Exception { + +} diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java new file mode 100644 index 0000000000..99e0cbc482 --- /dev/null +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -0,0 +1,34 @@ +package seedu.moneymind; + +public class Moneymind { + private Ui ui; + private Storage storage; + + public Moneymind() { + this.ui = new Ui(); + // this line crashes the app currently, so it is commented out + // this.storage = new Storage(); + } + + public void run() { + ui.greet(); + boolean isExit = false; + while (!isExit) { + try { + Command command = ui.processNextCommand(); + if (command.isExit()) { + ui.goodbye(); + isExit = true; + } else { + command.execute(ui); // should also accept storage object as parameter + } + } catch (Exception e) { + ui.error(e); + } + } + } + + public static void main(String[] args) { + new Moneymind().run(); + } +} diff --git a/src/main/java/seedu/duke/Storage.java b/src/main/java/seedu/moneymind/Storage.java similarity index 99% rename from src/main/java/seedu/duke/Storage.java rename to src/main/java/seedu/moneymind/Storage.java index 768596739d..21234448eb 100644 --- a/src/main/java/seedu/duke/Storage.java +++ b/src/main/java/seedu/moneymind/Storage.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.moneymind; import java.io.File; import java.io.FileNotFoundException; diff --git a/src/main/java/seedu/moneymind/Ui.java b/src/main/java/seedu/moneymind/Ui.java new file mode 100644 index 0000000000..18d6227cf9 --- /dev/null +++ b/src/main/java/seedu/moneymind/Ui.java @@ -0,0 +1,54 @@ +package seedu.moneymind; + +import java.util.Scanner; + +public class Ui { + private static final String LINE = "____________________________________________________________\n"; + private static final String LOGO = + "███╗░░░███╗░█████╗░███╗░░██╗███████╗██╗░░░██╗███╗░░░███╗██╗███╗░░██╗██████╗░\n" + + "████╗░████║██╔══██╗████╗░██║██╔════╝╚██╗░██╔╝████╗░████║██║████╗░██║██╔══██╗\n" + + "██╔████╔██║██║░░██║██╔██╗██║█████╗░░░╚████╔╝░██╔████╔██║██║██╔██╗██║██║░░██║\n" + + "██║╚██╔╝██║██║░░██║██║╚████║██╔══╝░░░░╚██╔╝░░██║╚██╔╝██║██║██║╚████║██║░░██║\n" + + "██║░╚═╝░██║╚█████╔╝██║░╚███║███████╗░░░██║░░░██║░╚═╝░██║██║██║░╚███║██████╔╝\n" + + "╚═╝░░░░░╚═╝░╚════╝░╚═╝░░╚══╝╚══════╝░░░╚═╝░░░╚═╝░░░░░╚═╝╚═╝╚═╝░░╚══╝╚═════╝░\n"; + private static final String GREETING = "Hello from\n" + LOGO + "How may I help you?"; + private static final String NAME_REQUEST = "What is your name?"; + private static final String GOODBYE = "Bye. Hope to see you again soon!"; + private static final String ERROR = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; + private static final String LIST = "Here are the events in your list:"; + + Scanner in; + + public Ui() { + this.in = new Scanner(System.in); + } + + public Command processNextCommand() throws InvalidCommandException { + String input = in.nextLine(); + return new Command(input); + } + + public void greet() { + System.out.println(GREETING); + } + + public void requestName() { + System.out.println(NAME_REQUEST); + } + + public void goodbye() { + System.out.println(GOODBYE); + } + + public void error(Exception e) { + System.out.println(ERROR + "\n" + e); + } + + public void list() { + System.out.println(LIST); + } + + public void echo(String value) { + System.out.println(value); + } +} diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/moneymind/DukeTest.java similarity index 88% rename from src/test/java/seedu/duke/DukeTest.java rename to src/test/java/seedu/moneymind/DukeTest.java index 2dda5fd651..da0a58e0fc 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/moneymind/DukeTest.java @@ -1,4 +1,4 @@ -package seedu.duke; +package seedu.moneymind; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 892cb6cae7..006f22c35e 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,9 +1,10 @@ Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| - -What is your name? -Hello James Gosling +███╗░░░███╗░█████╗░███╗░░██╗███████╗██╗░░░██╗███╗░░░███╗██╗███╗░░██╗██████╗░ +████╗░████║██╔══██╗████╗░██║██╔════╝╚██╗░██╔╝████╗░████║██║████╗░██║██╔══██╗ +██╔████╔██║██║░░██║██╔██╗██║█████╗░░░╚████╔╝░██╔████╔██║██║██╔██╗██║██║░░██║ +██║╚██╔╝██║██║░░██║██║╚████║██╔══╝░░░░╚██╔╝░░██║╚██╔╝██║██║██║╚████║██║░░██║ +██║░╚═╝░██║╚█████╔╝██║░╚███║███████╗░░░██║░░░██║░╚═╝░██║██║██║░╚███║██████╔╝ +╚═╝░░░░░╚═╝░╚════╝░╚═╝░░╚══╝╚══════╝░░░╚═╝░░░╚═╝░░░░░╚═╝╚═╝╚═╝░░╚══╝╚═════╝░ +How may I help you? +test +Bye. Hope to see you again soon! diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index f6ec2e9f95..8e24493055 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1 +1,2 @@ -James Gosling \ No newline at end of file +echo test +bye From eee42ea69a91a52a98b7db71ed6dd5d7640b74c8 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 7 Mar 2023 16:53:47 +0800 Subject: [PATCH 014/210] Fix indentation issues --- src/main/java/seedu/moneymind/Command.java | 32 ++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/seedu/moneymind/Command.java b/src/main/java/seedu/moneymind/Command.java index d7c4881cb9..f31c5ba27c 100644 --- a/src/main/java/seedu/moneymind/Command.java +++ b/src/main/java/seedu/moneymind/Command.java @@ -11,29 +11,33 @@ public Command(String input) throws InvalidCommandException { // assign command type only switch (command) { - case "bye": - this.type = CommandType.EXIT; - break; - case "echo": - this.type = CommandType.ECHO; - break; - default: - throw new InvalidCommandException(); + case "bye": + this.type = CommandType.EXIT; + break; + case "echo": + this.type = CommandType.ECHO; + break; + default: + throw new InvalidCommandException(); } // process value based on command type, only for commands with parameters switch (type) { - case ECHO: - this.value = tokens[1]; - break; + case ECHO: + this.value = tokens[1]; + break; + default: + break; } } public void execute(Ui ui) { switch (type) { - case ECHO: - ui.echo(value); - break; + case ECHO: + ui.echo(value); + break; + default: + break; } } From 38bb2839ddfcf190c754846abbf2428aa56c96ce Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 7 Mar 2023 17:06:17 +0800 Subject: [PATCH 015/210] Replace logo with a placeholder as the special characters are causing tests to fail --- src/main/java/seedu/moneymind/Command.java | 1 + src/main/java/seedu/moneymind/Ui.java | 8 +------- text-ui-test/EXPECTED.TXT | 7 +------ 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/main/java/seedu/moneymind/Command.java b/src/main/java/seedu/moneymind/Command.java index f31c5ba27c..fa32f68bab 100644 --- a/src/main/java/seedu/moneymind/Command.java +++ b/src/main/java/seedu/moneymind/Command.java @@ -49,3 +49,4 @@ public boolean isExit() { enum CommandType { ECHO, EXIT } + diff --git a/src/main/java/seedu/moneymind/Ui.java b/src/main/java/seedu/moneymind/Ui.java index 18d6227cf9..8c15145998 100644 --- a/src/main/java/seedu/moneymind/Ui.java +++ b/src/main/java/seedu/moneymind/Ui.java @@ -4,13 +4,7 @@ public class Ui { private static final String LINE = "____________________________________________________________\n"; - private static final String LOGO = - "███╗░░░███╗░█████╗░███╗░░██╗███████╗██╗░░░██╗███╗░░░███╗██╗███╗░░██╗██████╗░\n" + - "████╗░████║██╔══██╗████╗░██║██╔════╝╚██╗░██╔╝████╗░████║██║████╗░██║██╔══██╗\n" + - "██╔████╔██║██║░░██║██╔██╗██║█████╗░░░╚████╔╝░██╔████╔██║██║██╔██╗██║██║░░██║\n" + - "██║╚██╔╝██║██║░░██║██║╚████║██╔══╝░░░░╚██╔╝░░██║╚██╔╝██║██║██║╚████║██║░░██║\n" + - "██║░╚═╝░██║╚█████╔╝██║░╚███║███████╗░░░██║░░░██║░╚═╝░██║██║██║░╚███║██████╔╝\n" + - "╚═╝░░░░░╚═╝░╚════╝░╚═╝░░╚══╝╚══════╝░░░╚═╝░░░╚═╝░░░░░╚═╝╚═╝╚═╝░░╚══╝╚═════╝░\n"; + private static final String LOGO = "[LOGO_PLACEHOLDER]\n"; private static final String GREETING = "Hello from\n" + LOGO + "How may I help you?"; private static final String NAME_REQUEST = "What is your name?"; private static final String GOODBYE = "Bye. Hope to see you again soon!"; diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 006f22c35e..d1e320a6f0 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,10 +1,5 @@ Hello from -███╗░░░███╗░█████╗░███╗░░██╗███████╗██╗░░░██╗███╗░░░███╗██╗███╗░░██╗██████╗░ -████╗░████║██╔══██╗████╗░██║██╔════╝╚██╗░██╔╝████╗░████║██║████╗░██║██╔══██╗ -██╔████╔██║██║░░██║██╔██╗██║█████╗░░░╚████╔╝░██╔████╔██║██║██╔██╗██║██║░░██║ -██║╚██╔╝██║██║░░██║██║╚████║██╔══╝░░░░╚██╔╝░░██║╚██╔╝██║██║██║╚████║██║░░██║ -██║░╚═╝░██║╚█████╔╝██║░╚███║███████╗░░░██║░░░██║░╚═╝░██║██║██║░╚███║██████╔╝ -╚═╝░░░░░╚═╝░╚════╝░╚═╝░░╚══╝╚══════╝░░░╚═╝░░░╚═╝░░░░░╚═╝╚═╝╚═╝░░╚══╝╚═════╝░ +[LOGO_PLACEHOLDER] How may I help you? test Bye. Hope to see you again soon! From f12926106b91c8ab23fa5c231906ec5b80e6aa53 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Wed, 8 Mar 2023 23:18:13 +0800 Subject: [PATCH 016/210] Add some classes to execute different commands and add parser --- src/main/java/seedu/duke/ByeCommand.java | 20 +++++ src/main/java/seedu/duke/CategoryCommand.java | 18 ++++ src/main/java/seedu/duke/DeleteCommand.java | 34 +++++++ src/main/java/seedu/duke/EventCommand.java | 58 ++++++++++++ .../duke/InvalidCategoryNumberException.java | 5 ++ src/main/java/seedu/duke/Parser.java | 89 +++++++++++++++++++ src/main/java/seedu/duke/ViewCommand.java | 34 +++++++ 7 files changed, 258 insertions(+) create mode 100644 src/main/java/seedu/duke/ByeCommand.java create mode 100644 src/main/java/seedu/duke/CategoryCommand.java create mode 100644 src/main/java/seedu/duke/DeleteCommand.java create mode 100644 src/main/java/seedu/duke/EventCommand.java create mode 100644 src/main/java/seedu/duke/InvalidCategoryNumberException.java create mode 100644 src/main/java/seedu/duke/Parser.java create mode 100644 src/main/java/seedu/duke/ViewCommand.java diff --git a/src/main/java/seedu/duke/ByeCommand.java b/src/main/java/seedu/duke/ByeCommand.java new file mode 100644 index 0000000000..9899e9aa6b --- /dev/null +++ b/src/main/java/seedu/duke/ByeCommand.java @@ -0,0 +1,20 @@ +package seedu.duke; + +public class ByeCommand { + + private static final String BYE_MESSAGE = "Bye. Hope to see you again soon!"; + public static final String HORIZONTAL_LINE = "____________________________________________________________"; + /** + * Constructs a new ByeCommand object and exits the program. + */ + public ByeCommand() { + doByeCommand(); + } + + private void doByeCommand() { + System.out.println(BYE_MESSAGE); + System.out.println(HORIZONTAL_LINE); + System.exit(0); + } + +} diff --git a/src/main/java/seedu/duke/CategoryCommand.java b/src/main/java/seedu/duke/CategoryCommand.java new file mode 100644 index 0000000000..16257a8b86 --- /dev/null +++ b/src/main/java/seedu/duke/CategoryCommand.java @@ -0,0 +1,18 @@ +package seedu.duke; + +import java.util.HashMap; + +public class CategoryCommand { + private String name; + public static HashMap categoryMap = new HashMap(); + public CategoryCommand(String name) { + this.name = name; + addCategory(); + } + private void addCategory() { + Category category = new Category(name); + CategoryList.categories.add(category); + categoryMap.put(name, CategoryList.categories.size() - 1); + System.out.println("New category added: " + name); + } +} diff --git a/src/main/java/seedu/duke/DeleteCommand.java b/src/main/java/seedu/duke/DeleteCommand.java new file mode 100644 index 0000000000..3bd1b9426c --- /dev/null +++ b/src/main/java/seedu/duke/DeleteCommand.java @@ -0,0 +1,34 @@ +package seedu.duke; + +public class DeleteCommand { + private String categoryName; + private String eventName; + + public DeleteCommand(String categoryName, String eventName) { + this.categoryName = categoryName; + this.eventName = eventName; + deleteEvent(); + } + + public DeleteCommand(String categoryName) { + this.categoryName = categoryName; + deleteCategory(); + } + + // delete the event + private void deleteEvent() { + int categoryIndex = CategoryCommand.categoryMap.get(categoryName); + Category category = CategoryList.categories.get(categoryIndex); + for (int i = 0; i < category.events.size(); i++) { + if (category.events.get(i).getDescription().equals(eventName)) { + category.events.remove(i); + } + } + } + + // delete the category + private void deleteCategory() { + int categoryIndex = CategoryCommand.categoryMap.get(categoryName); + CategoryList.categories.remove(categoryIndex); + } +} diff --git a/src/main/java/seedu/duke/EventCommand.java b/src/main/java/seedu/duke/EventCommand.java new file mode 100644 index 0000000000..bd3e7f5e79 --- /dev/null +++ b/src/main/java/seedu/duke/EventCommand.java @@ -0,0 +1,58 @@ +package seedu.duke; + +import java.util.ArrayList; +import java.util.Scanner; + +public class EventCommand { + private String eventName; + private int budget; + private int expense; + + public EventCommand(String eventName, int budget, int expense) { + this.eventName = eventName; + this.budget = budget; + this.expense = expense; + addEvent(); + } + + private void addEvent() { + Event event = new Event(eventName, budget, expense); + System.out.println("Please select the category you want to add the event to: "); + String userInput; + Scanner in; + in = new Scanner(System.in); + userInput = in.nextLine(); + while (!isChooseCategorySuccessful(userInput)) { + userInput = in.nextLine(); + System.out.println("Please try again"); + } + } + + private void addEventToCategory(int categoryPosition, Event event) { + Category category = CategoryList.getCategory(categoryPosition - 1); + category.addEvent(event); + System.out.println("New event added: " + event.getDescription()); + } + + private boolean isChooseCategorySuccessful(String userInput) { + try { + int categoryPosition = Integer.parseInt(userInput); + testCategoryNumber(categoryPosition); + addEventToCategory(categoryPosition, new Event(eventName, budget, expense)); + return true; + } catch (NumberFormatException e) { + System.out.println("Please enter a number."); + } catch (InvalidCategoryNumberException e) { + System.out.println("The category number you entered is out of range"); + } catch (Exception e) { + System.out.println("Something went wrong, please report to the developer"); + } + return false; + } + + private void testCategoryNumber(int categoryPosition) throws InvalidCategoryNumberException { + if (categoryPosition > CategoryList.categories.size() || categoryPosition <= 0) { + throw new InvalidCategoryNumberException(); + } + } +} diff --git a/src/main/java/seedu/duke/InvalidCategoryNumberException.java b/src/main/java/seedu/duke/InvalidCategoryNumberException.java new file mode 100644 index 0000000000..286621fdb6 --- /dev/null +++ b/src/main/java/seedu/duke/InvalidCategoryNumberException.java @@ -0,0 +1,5 @@ +package seedu.duke; + +public class InvalidCategoryNumberException extends Exception{ + // no need to write the code +} diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java new file mode 100644 index 0000000000..a314175656 --- /dev/null +++ b/src/main/java/seedu/duke/Parser.java @@ -0,0 +1,89 @@ +package seedu.duke; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +public class Parser { + private String[] separatedKeywordAndDescription; + private String keyword; + // split the input into keyword and description + public void splitKeywordAndDescription(String input) { + separatedKeywordAndDescription = input.split(" ", 2); + keyword = separatedKeywordAndDescription[0]; + } + public void executeUserInput() { + switch (keyword) { + case "bye": + executeByeCommand(); + break; + case "view": + executeViewCommand(); + break; + case "delete": + executeDeleteCommand(); + break; + case "event": + executeEventCommand(); + break; + case "category": + executeCategoryCommand(); + break; + default: + System.out.println("☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + break; + } + } + + private void executeByeCommand() { + ByeCommand byeCommand = new ByeCommand(); + } + + // execute view command + private void executeViewCommand() { + if (separatedKeywordAndDescription.length == 1) { + new ViewCommand(); + } else { + new ViewCommand(separatedKeywordAndDescription[1]); + } + } + + // execute delete command + private void executeDeleteCommand() { + Pattern pattern = Pattern.compile("c/(.+) e/(.+)?"); + Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + + if (matcher.find()) { + String categoryName = matcher.group(1); + String eventName = matcher.group(2); + + System.out.println("Category name: " + categoryName); + System.out.println("Event name: " + eventName); + if (eventName == null) { + new DeleteCommand(categoryName); + } else { + new DeleteCommand(categoryName, eventName); + } + } + } + + // execute event command + private void executeEventCommand() { + Pattern pattern = Pattern.compile("(.+) b/(\\d+) e/(\\d+)?"); + Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + + if (matcher.find()) { + String eventName = matcher.group(1); + String budgetNumber = matcher.group(2); + String expenseNumber = matcher.group(3); + + System.out.println("Event name: " + eventName); + System.out.println("Budget number: " + budgetNumber); + System.out.println("Expense number: " + expenseNumber); + new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); + } + } + + // execute category command + private void executeCategoryCommand() { + new CategoryCommand(separatedKeywordAndDescription[1]); + } + +} diff --git a/src/main/java/seedu/duke/ViewCommand.java b/src/main/java/seedu/duke/ViewCommand.java new file mode 100644 index 0000000000..0ced3e5469 --- /dev/null +++ b/src/main/java/seedu/duke/ViewCommand.java @@ -0,0 +1,34 @@ +package seedu.duke; + +public class ViewCommand { + private String categoryName; + + public ViewCommand(String categoryName) { + this.categoryName = categoryName; + viewCategory(); + } + public ViewCommand() { + viewAll(); + } + + // view the category + private void viewCategory() { + int categoryIndex = CategoryCommand.categoryMap.get(categoryName); + Category category = CategoryList.categories.get(categoryIndex); + category.viewEventList(); + } + + // view all the categories + private void viewAll() { + int count = 1; + for (Category category : CategoryList.categories) { + System.out.println(count + "." + category.getName()); + count++; + // print all the events in the category + for (Event event : category.events) { + System.out.println(event.toString()); + } + } + } + +} From 5816d0ce87bc4f6023de575291d71936395b0839 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Thu, 9 Mar 2023 02:13:40 +0800 Subject: [PATCH 017/210] Handle exceptions and add java doc --- src/main/java/seedu/duke/ByeCommand.java | 3 + src/main/java/seedu/duke/DeleteCommand.java | 36 ++++++- src/main/java/seedu/duke/EventCommand.java | 47 ++++++-- src/main/java/seedu/duke/Parser.java | 113 ++++++++++++++------ src/main/java/seedu/duke/ViewCommand.java | 25 ++++- 5 files changed, 180 insertions(+), 44 deletions(-) diff --git a/src/main/java/seedu/duke/ByeCommand.java b/src/main/java/seedu/duke/ByeCommand.java index 9899e9aa6b..e045c7fb94 100644 --- a/src/main/java/seedu/duke/ByeCommand.java +++ b/src/main/java/seedu/duke/ByeCommand.java @@ -1,5 +1,8 @@ package seedu.duke; +/** + * Represents the command to exit the program. + */ public class ByeCommand { private static final String BYE_MESSAGE = "Bye. Hope to see you again soon!"; diff --git a/src/main/java/seedu/duke/DeleteCommand.java b/src/main/java/seedu/duke/DeleteCommand.java index 3bd1b9426c..f9a7965cd6 100644 --- a/src/main/java/seedu/duke/DeleteCommand.java +++ b/src/main/java/seedu/duke/DeleteCommand.java @@ -1,34 +1,66 @@ package seedu.duke; +/** + * Represents the command to delete an event or a category. + */ public class DeleteCommand { + public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; + public static final String EVENT_DELETION_MESSAGE = "Event deleted: "; + public static final String CATEGORY_DELETION_MESSAGE = "Category deleted: "; private String categoryName; private String eventName; + /** + * Constructs a new DeleteCommand object and deletes the event. + * + * @param categoryName the name of the category + * @param eventName the name of the event + */ public DeleteCommand(String categoryName, String eventName) { this.categoryName = categoryName; this.eventName = eventName; deleteEvent(); } + /** + * Constructs a new DeleteCommand object and deletes the category. + * + * @param categoryName the name of the category + */ public DeleteCommand(String categoryName) { this.categoryName = categoryName; deleteCategory(); } - // delete the event + /** + * Deletes the event. + */ private void deleteEvent() { + if (CategoryCommand.categoryMap.get(categoryName) == null) { + System.out.println(NO_CATEGORY_MESSAGE); + return; + } int categoryIndex = CategoryCommand.categoryMap.get(categoryName); Category category = CategoryList.categories.get(categoryIndex); for (int i = 0; i < category.events.size(); i++) { if (category.events.get(i).getDescription().equals(eventName)) { category.events.remove(i); + System.out.println(EVENT_DELETION_MESSAGE + eventName); } } } - // delete the category + /** + * Deletes the category. + */ private void deleteCategory() { + if (CategoryCommand.categoryMap.get(categoryName) == null) { + System.out.println(NO_CATEGORY_MESSAGE); + return; + } int categoryIndex = CategoryCommand.categoryMap.get(categoryName); CategoryList.categories.remove(categoryIndex); + CategoryCommand.categoryMap.remove(categoryName); + System.out.println(CATEGORY_DELETION_MESSAGE + categoryName); } } diff --git a/src/main/java/seedu/duke/EventCommand.java b/src/main/java/seedu/duke/EventCommand.java index bd3e7f5e79..9a790c3714 100644 --- a/src/main/java/seedu/duke/EventCommand.java +++ b/src/main/java/seedu/duke/EventCommand.java @@ -3,11 +3,28 @@ import java.util.ArrayList; import java.util.Scanner; +/** + * A class to add an event + */ public class EventCommand { + public static final String SELECTING_CATEGORY_MESSAGE = "Please select the category you want to add the event to: "; + public static final String GO_BACK_MESSAGE = "Please enter back to go back to the main program"; + public static final String BACK = "back"; + public static final String EVENT_ADDED_MESSAGE = "New event added: "; + public static final String REMINDING_MESSAGE_TO_GIVE_A_NUMBER = "Please enter a number."; + public static final String CATEGORY_OUT_OF_RANGE = "The category number you entered is out of range"; + public static final String SUBTLE_BUG_MESSAGE = "Something went wrong, please report to the developer"; private String eventName; private int budget; private int expense; + /** + * Constructor for EventCommand. + * + * @param eventName The name of the event. + * @param budget The budget of the event. + * @param expense The expense of the event. + */ public EventCommand(String eventName, int budget, int expense) { this.eventName = eventName; this.budget = budget; @@ -17,23 +34,35 @@ public EventCommand(String eventName, int budget, int expense) { private void addEvent() { Event event = new Event(eventName, budget, expense); - System.out.println("Please select the category you want to add the event to: "); + System.out.println(SELECTING_CATEGORY_MESSAGE); String userInput; Scanner in; in = new Scanner(System.in); userInput = in.nextLine(); while (!isChooseCategorySuccessful(userInput)) { + System.out.println(GO_BACK_MESSAGE); userInput = in.nextLine(); - System.out.println("Please try again"); + if (userInput.equals(BACK)) { + break; + } } } + /** + * Add an event to a category. + */ private void addEventToCategory(int categoryPosition, Event event) { Category category = CategoryList.getCategory(categoryPosition - 1); category.addEvent(event); - System.out.println("New event added: " + event.getDescription()); + System.out.println(EVENT_ADDED_MESSAGE + event.getDescription()); } + /** + * Check if the user input is valid. + * + * @param userInput The user input. + * @return True if the user input is valid. + */ private boolean isChooseCategorySuccessful(String userInput) { try { int categoryPosition = Integer.parseInt(userInput); @@ -41,15 +70,21 @@ private boolean isChooseCategorySuccessful(String userInput) { addEventToCategory(categoryPosition, new Event(eventName, budget, expense)); return true; } catch (NumberFormatException e) { - System.out.println("Please enter a number."); + System.out.println(REMINDING_MESSAGE_TO_GIVE_A_NUMBER); } catch (InvalidCategoryNumberException e) { - System.out.println("The category number you entered is out of range"); + System.out.println(CATEGORY_OUT_OF_RANGE); } catch (Exception e) { - System.out.println("Something went wrong, please report to the developer"); + System.out.println(SUBTLE_BUG_MESSAGE); } return false; } + /** + * Check if the category number is valid. + * + * @param categoryPosition The category number. + * @throws InvalidCategoryNumberException If the category number is invalid. + */ private void testCategoryNumber(int categoryPosition) throws InvalidCategoryNumberException { if (categoryPosition > CategoryList.categories.size() || categoryPosition <= 0) { throw new InvalidCategoryNumberException(); diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index a314175656..84659f2d97 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -1,33 +1,63 @@ package seedu.duke; import java.util.regex.Matcher; import java.util.regex.Pattern; + +/** + * A class to parse the user input. + */ public class Parser { + public static final String WHITE_SPACE = " "; + public static final String BYE = "bye"; + public static final String VIEW = "view"; + public static final String DELETE = "delete"; + public static final String EVENT = "event"; + public static final String CATEGORY = "category"; + public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; + public static final String DELETE_REGEX = "c/(.+) e/(.+)?"; + public static final String CATEGORY_ADDED_MESSAGE = "Category name: "; + public static final String EVENT_ADDED_MESSAGE = "Event name: "; + public static final String DELETE_FORMAT = "Please following the correct format: delete c/ e/"; + public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things inside the brackets empty!"; + public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; + public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; + public static final String EVENT_REGEX = "(.+) b/(\\d+) e/(\\d+)?"; + public static final String EVENT_FORMAT = "Please following the correct format: event b/ e/"; + public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; + public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = "☹ OOPS!!! The budget and expense must be a number."; + public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; private String[] separatedKeywordAndDescription; private String keyword; - // split the input into keyword and description + + /** + * Splits the user input into keyword and description. + */ public void splitKeywordAndDescription(String input) { - separatedKeywordAndDescription = input.split(" ", 2); + separatedKeywordAndDescription = input.split(WHITE_SPACE, 2); keyword = separatedKeywordAndDescription[0]; } + + /** + * Executes the user input. + */ public void executeUserInput() { switch (keyword) { - case "bye": + case BYE: executeByeCommand(); break; - case "view": + case VIEW: executeViewCommand(); break; - case "delete": + case DELETE: executeDeleteCommand(); break; - case "event": + case EVENT: executeEventCommand(); break; - case "category": + case CATEGORY: executeCategoryCommand(); break; default: - System.out.println("☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + System.out.println(INVALID_INPUT); break; } } @@ -36,7 +66,6 @@ private void executeByeCommand() { ByeCommand byeCommand = new ByeCommand(); } - // execute view command private void executeViewCommand() { if (separatedKeywordAndDescription.length == 1) { new ViewCommand(); @@ -45,45 +74,63 @@ private void executeViewCommand() { } } - // execute delete command private void executeDeleteCommand() { Pattern pattern = Pattern.compile("c/(.+) e/(.+)?"); - Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + try { + Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + if (matcher.find()) { + String categoryName = matcher.group(1); + String eventName = matcher.group(2); - if (matcher.find()) { - String categoryName = matcher.group(1); - String eventName = matcher.group(2); - - System.out.println("Category name: " + categoryName); - System.out.println("Event name: " + eventName); - if (eventName == null) { - new DeleteCommand(categoryName); + System.out.println(CATEGORY_ADDED_MESSAGE + categoryName); + System.out.println(EVENT_ADDED_MESSAGE + eventName); + if (eventName == null) { + new DeleteCommand(categoryName); + } else { + new DeleteCommand(categoryName, eventName); + } } else { - new DeleteCommand(categoryName, eventName); + System.out.println(DELETE_FORMAT); + System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } + } catch (IndexOutOfBoundsException e) { + System.out.println(EMPTY_DELETION); + } catch (Exception e) { + System.out.println(SUBTLE_BUG_MESSAGE); } + } // execute event command private void executeEventCommand() { - Pattern pattern = Pattern.compile("(.+) b/(\\d+) e/(\\d+)?"); - Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); - - if (matcher.find()) { - String eventName = matcher.group(1); - String budgetNumber = matcher.group(2); - String expenseNumber = matcher.group(3); - - System.out.println("Event name: " + eventName); - System.out.println("Budget number: " + budgetNumber); - System.out.println("Expense number: " + expenseNumber); - new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); + Pattern pattern = Pattern.compile(EVENT_REGEX); + try { + Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + if (matcher.find()) { + String eventName = matcher.group(1); + String budgetNumber = matcher.group(2); + String expenseNumber = matcher.group(3); + new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); + } else { + System.out.println(EVENT_FORMAT); + System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + } + } catch (IndexOutOfBoundsException e) { + System.out.println(EVENT_EMPTY); + } catch (NumberFormatException e) { + System.out.println(REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER); + } catch (Exception e) { + System.out.println(SUBTLE_BUG_MESSAGE); } } // execute category command private void executeCategoryCommand() { - new CategoryCommand(separatedKeywordAndDescription[1]); + try { + new CategoryCommand(separatedKeywordAndDescription[1]); + } catch (IndexOutOfBoundsException e) { + System.out.println(CATEGORY_EMPTY); + } } } diff --git a/src/main/java/seedu/duke/ViewCommand.java b/src/main/java/seedu/duke/ViewCommand.java index 0ced3e5469..6702bb6d5a 100644 --- a/src/main/java/seedu/duke/ViewCommand.java +++ b/src/main/java/seedu/duke/ViewCommand.java @@ -1,28 +1,47 @@ package seedu.duke; +/** + * ViewCommand class to view the categories and events. + */ public class ViewCommand { + public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; + public static final String DOT = "."; private String categoryName; + /** + * Constructs a new ViewCommand object and views the category. + * + * @param categoryName the name of the category + */ public ViewCommand(String categoryName) { this.categoryName = categoryName; viewCategory(); } + + /** + * Constructs a new ViewCommand object and views all the categories. + */ public ViewCommand() { viewAll(); } - // view the category private void viewCategory() { + if (CategoryCommand.categoryMap.get(categoryName) == null) { + System.out.println(NO_CATEGORY_MESSAGE); + return; + } int categoryIndex = CategoryCommand.categoryMap.get(categoryName); Category category = CategoryList.categories.get(categoryIndex); category.viewEventList(); } - // view all the categories + /** + * Views all the categories and events. + */ private void viewAll() { int count = 1; for (Category category : CategoryList.categories) { - System.out.println(count + "." + category.getName()); + System.out.println(count + DOT + category.getName()); count++; // print all the events in the category for (Event event : category.events) { From 478019dc17177b8ae706ecbc964ca8f4e9d3cb60 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Thu, 9 Mar 2023 10:15:41 +0800 Subject: [PATCH 018/210] Fix bug for delete in parser --- src/main/java/seedu/duke/Parser.java | 35 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 84659f2d97..6c5eb8e35e 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -75,30 +75,29 @@ private void executeViewCommand() { } private void executeDeleteCommand() { - Pattern pattern = Pattern.compile("c/(.+) e/(.+)?"); - try { - Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); - if (matcher.find()) { - String categoryName = matcher.group(1); - String eventName = matcher.group(2); - - System.out.println(CATEGORY_ADDED_MESSAGE + categoryName); - System.out.println(EVENT_ADDED_MESSAGE + eventName); - if (eventName == null) { - new DeleteCommand(categoryName); - } else { + if (separatedKeywordAndDescription[1].startsWith("c/")) { + try { + String afterCategorySpecifier = separatedKeywordAndDescription[1].substring(2); + Pattern pattern = Pattern.compile("(.+) e/(.+)"); + Matcher matcher = pattern.matcher(afterCategorySpecifier); + if (matcher.find()) { + String categoryName = matcher.group(1); + String eventName = matcher.group(2); new DeleteCommand(categoryName, eventName); + } else { + System.out.println(afterCategorySpecifier); + new DeleteCommand(afterCategorySpecifier); } - } else { + } catch (IndexOutOfBoundsException e) { System.out.println(DELETE_FORMAT); System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + } catch (Exception e) { + System.out.println(SUBTLE_BUG_MESSAGE); } - } catch (IndexOutOfBoundsException e) { - System.out.println(EMPTY_DELETION); - } catch (Exception e) { - System.out.println(SUBTLE_BUG_MESSAGE); + } else { + System.out.println(DELETE_FORMAT); + System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } - } // execute event command From bb91daebbdbaa7915c1b4636bd907aefa484427c Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Thu, 9 Mar 2023 10:33:48 +0800 Subject: [PATCH 019/210] Improve coding standard --- src/main/java/seedu/duke/ByeCommand.java | 2 +- src/main/java/seedu/duke/CategoryCommand.java | 3 ++- src/main/java/seedu/duke/Parser.java | 14 ++++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/duke/ByeCommand.java b/src/main/java/seedu/duke/ByeCommand.java index e045c7fb94..13f0c0ad31 100644 --- a/src/main/java/seedu/duke/ByeCommand.java +++ b/src/main/java/seedu/duke/ByeCommand.java @@ -6,7 +6,7 @@ public class ByeCommand { private static final String BYE_MESSAGE = "Bye. Hope to see you again soon!"; - public static final String HORIZONTAL_LINE = "____________________________________________________________"; + private static final String HORIZONTAL_LINE = "____________________________________________________________"; /** * Constructs a new ByeCommand object and exits the program. */ diff --git a/src/main/java/seedu/duke/CategoryCommand.java b/src/main/java/seedu/duke/CategoryCommand.java index 16257a8b86..33d3ebd2fd 100644 --- a/src/main/java/seedu/duke/CategoryCommand.java +++ b/src/main/java/seedu/duke/CategoryCommand.java @@ -3,8 +3,9 @@ import java.util.HashMap; public class CategoryCommand { - private String name; public static HashMap categoryMap = new HashMap(); + private String name; + public CategoryCommand(String name) { this.name = name; addCategory(); diff --git a/src/main/java/seedu/duke/Parser.java b/src/main/java/seedu/duke/Parser.java index 6c5eb8e35e..23e1276db9 100644 --- a/src/main/java/seedu/duke/Parser.java +++ b/src/main/java/seedu/duke/Parser.java @@ -16,14 +16,18 @@ public class Parser { public static final String DELETE_REGEX = "c/(.+) e/(.+)?"; public static final String CATEGORY_ADDED_MESSAGE = "Category name: "; public static final String EVENT_ADDED_MESSAGE = "Event name: "; - public static final String DELETE_FORMAT = "Please following the correct format: delete c/ e/"; - public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things inside the brackets empty!"; + public static final String DELETE_FORMAT = "Please following the correct format: " + + "delete c/ e/"; + public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + + "inside the brackets empty!"; public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; public static final String EVENT_REGEX = "(.+) b/(\\d+) e/(\\d+)?"; - public static final String EVENT_FORMAT = "Please following the correct format: event b/ e/"; + public static final String EVENT_FORMAT = "Please following the correct format: " + + "event b/ e/"; public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; - public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = "☹ OOPS!!! The budget and expense must be a number."; + public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = + "☹ OOPS!!! The budget and expense must be a number."; public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; private String[] separatedKeywordAndDescription; private String keyword; @@ -100,7 +104,6 @@ private void executeDeleteCommand() { } } - // execute event command private void executeEventCommand() { Pattern pattern = Pattern.compile(EVENT_REGEX); try { @@ -123,7 +126,6 @@ private void executeEventCommand() { } } - // execute category command private void executeCategoryCommand() { try { new CategoryCommand(separatedKeywordAndDescription[1]); From baca562c14abfeb74e54d456405d9af8bf7777da Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Thu, 9 Mar 2023 10:37:30 +0800 Subject: [PATCH 020/210] Delete unused import --- src/main/java/seedu/duke/EventCommand.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/duke/EventCommand.java b/src/main/java/seedu/duke/EventCommand.java index 9a790c3714..8040f92a4f 100644 --- a/src/main/java/seedu/duke/EventCommand.java +++ b/src/main/java/seedu/duke/EventCommand.java @@ -1,6 +1,5 @@ package seedu.duke; -import java.util.ArrayList; import java.util.Scanner; /** From 318dcc08d059c441769a94a83e69e6ea19293444 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Thu, 9 Mar 2023 12:34:16 +0800 Subject: [PATCH 021/210] update storage.java --- src/main/java/seedu/duke/Storage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/duke/Storage.java b/src/main/java/seedu/duke/Storage.java index 768596739d..ded92c8328 100644 --- a/src/main/java/seedu/duke/Storage.java +++ b/src/main/java/seedu/duke/Storage.java @@ -12,7 +12,7 @@ public class Storage { * Divider used to separate details of a task saved in file */ private static final String SAVEFILESEPARATOR = ", "; - private static String filePath = "DukeTaskList.txt"; + private static String filePath = "EventList.txt"; private static File textFile; private static Scanner textFileScanner; @@ -20,6 +20,9 @@ public Storage() { loadFromFile(); } + /** + * Sets up the file to be read + */ private static void setupFile() { textFile = new File(filePath); From d28575435d280c736bdb7bcb701e2b6d4bad697e Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Thu, 9 Mar 2023 15:01:29 +0800 Subject: [PATCH 022/210] Resolve merge conflict --- src/main/java/seedu/moneymind/Storage.java | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/main/java/seedu/moneymind/Storage.java b/src/main/java/seedu/moneymind/Storage.java index 21234448eb..530c7df0c9 100644 --- a/src/main/java/seedu/moneymind/Storage.java +++ b/src/main/java/seedu/moneymind/Storage.java @@ -12,7 +12,7 @@ public class Storage { * Divider used to separate details of a task saved in file */ private static final String SAVEFILESEPARATOR = ", "; - private static String filePath = "DukeTaskList.txt"; + private static String filePath = "EventList.txt"; private static File textFile; private static Scanner textFileScanner; @@ -20,6 +20,9 @@ public Storage() { loadFromFile(); } + /** + * Sets up the file to be read + */ private static void setupFile() { textFile = new File(filePath); @@ -29,22 +32,22 @@ private static void setupFile() { System.out.println("I cannot seem to access the saved tasks. Did you perhaps lock it away?"); } } - + /** * Saves an ArrayList of tasks to DukeTaskList.txt file - * + * * @param list ArrayList of tasks */ public static void saveToFile(ArrayList list) { String writeToFile = ""; - + for (Event dukeTasks : list) { // extracting details from task object String[] dataToTextFile= {"", "", ""}; dataToTextFile[0] = dukeTasks.toString(); // save task details split by regex ", " - writeToFile += dataToTextFile[0] + SAVEFILESEPARATOR + dataToTextFile[1] + + writeToFile += dataToTextFile[0] + SAVEFILESEPARATOR + dataToTextFile[1] + SAVEFILESEPARATOR + dataToTextFile[2] + System.lineSeparator(); } @@ -61,7 +64,7 @@ public static void saveToFile(ArrayList list) { /** * Returns an ArrayList of tasks from DukeTaskList.txt file - * + * * @return ArrayList of tasks */ public static ArrayList loadFromFile() { @@ -71,20 +74,20 @@ public static ArrayList loadFromFile() { while (textFileScanner.hasNext()) { String[] loadTaskInfo = new String[3]; loadTaskInfo = textFileScanner.nextLine().split(SAVEFILESEPARATOR, 3); - + // create tasks individually switch (loadTaskInfo[0]) { - case "T": - break; - - case "D": - break; - - default: - break; + case "T": + break; + + case "D": + break; + + default: + break; } } return savedList; } -} +} \ No newline at end of file From a3cdca43b909e1888e3fcadcee0f327d97964695 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Thu, 9 Mar 2023 22:34:52 +0800 Subject: [PATCH 023/210] add JUnit tests for Storage.java --- EventList.txt | 1 + src/main/java/seedu/duke/Storage.java | 38 +++++++----- src/test/java/seedu/duke/StorageTest.java | 72 +++++++++++++++++++++++ 3 files changed, 97 insertions(+), 14 deletions(-) create mode 100644 EventList.txt create mode 100644 src/test/java/seedu/duke/StorageTest.java diff --git a/EventList.txt b/EventList.txt new file mode 100644 index 0000000000..78185d9146 --- /dev/null +++ b/EventList.txt @@ -0,0 +1 @@ +test [budget]1234 [expense]5678, , diff --git a/src/main/java/seedu/duke/Storage.java b/src/main/java/seedu/duke/Storage.java index ded92c8328..d21a3c0ed4 100644 --- a/src/main/java/seedu/duke/Storage.java +++ b/src/main/java/seedu/duke/Storage.java @@ -12,19 +12,29 @@ public class Storage { * Divider used to separate details of a task saved in file */ private static final String SAVEFILESEPARATOR = ", "; - private static String filePath = "EventList.txt"; private static File textFile; private static Scanner textFileScanner; + private static String filePath = "EventList.txt"; + /** + * Constructor for Storage class + */ public Storage() { - loadFromFile(); + setupFile(); } /** - * Sets up the file to be read + * Sets up the file to be read and written to */ private static void setupFile() { textFile = new File(filePath); + + // create file if it does not exist + try { + textFile.createNewFile(); + } catch (IOException e) { + System.out.println("The file already exists."); + } try { textFileScanner = new Scanner(textFile); @@ -34,13 +44,13 @@ private static void setupFile() { } /** - * Saves an ArrayList of tasks to DukeTaskList.txt file + * Saves an ArrayList of Events to EventList.txt file * - * @param list ArrayList of tasks + * @param list ArrayList of Events */ - public static void saveToFile(ArrayList list) { + public void saveToFile(ArrayList list) { String writeToFile = ""; - + // TODO: Object to string conversion for (Event dukeTasks : list) { // extracting details from task object String[] dataToTextFile= {"", "", ""}; @@ -53,7 +63,6 @@ public static void saveToFile(ArrayList list) { // write task list to text file try { - textFile = new File(filePath); FileWriter dukeWriter = new FileWriter(textFile); dukeWriter.write(writeToFile); dukeWriter.close(); @@ -63,24 +72,25 @@ public static void saveToFile(ArrayList list) { } /** - * Returns an ArrayList of tasks from DukeTaskList.txt file + * Returns an ArrayList of Events from EventList.txt file * - * @return ArrayList of tasks + * @return ArrayList of Events */ - public static ArrayList loadFromFile() { + public ArrayList loadFromFile() { ArrayList savedList = new ArrayList<>(); - setupFile(); + //setupFile(); while (textFileScanner.hasNext()) { + // TODO: Loading of objects from file String[] loadTaskInfo = new String[3]; loadTaskInfo = textFileScanner.nextLine().split(SAVEFILESEPARATOR, 3); // create tasks individually switch (loadTaskInfo[0]) { - case "T": + case "CATEGORY": break; - case "D": + case "EVENT": break; default: diff --git a/src/test/java/seedu/duke/StorageTest.java b/src/test/java/seedu/duke/StorageTest.java new file mode 100644 index 0000000000..7a42abe83e --- /dev/null +++ b/src/test/java/seedu/duke/StorageTest.java @@ -0,0 +1,72 @@ +package seedu.duke; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +public class StorageTest { + /** + * Tests setupFile() method

+ * Expected outcome: No exception thrown + */ + @Test + public void setupFile_null_noExceptionThrown() { + assertDoesNotThrow(() -> { + Storage storage = new Storage(); + System.out.println(storage.getClass()); + }); + } + + /** + * Tests saveToFile() method

+ * Input: ArrayList of 1 Event(description: "test", budget: 1234, expense: 5678)

+ * Expected outcome: No exception thrown + */ + @Test + public void saveToFile_descInput_exptOutcome() { + Storage storage = new Storage(); + ArrayList list = new ArrayList<>(); + list.add(new Event("test", 1234, 5678)); + assertDoesNotThrow(() -> { + storage.saveToFile(list); + }); + } + + /** + * Tests loadFromFile() method

+ * Expected outcome: No exception thrown + */ + @Test + public void loadFromFile_null_noExceptionThrown() { + try { + Storage storage = new Storage(); + ArrayList list = storage.loadFromFile(); + System.out.println(list); + } catch (Exception e) { + assertTrue(false, e.getMessage()); + } + } + + /** + * Tests save and load from file sequence

+ * Input: ArrayList of Events

+ * Expected outcome: No exception thrown + */ + @Test + public void saveAndLoadFromFile_descInput_exptOutcome() { + try { + Storage storage = new Storage(); + ArrayList list = new ArrayList<>(); + list.add(new Event("test", 1234, 5678)); + list.add(new Event("test2", 9876, 5432)); + storage.saveToFile(list); + ArrayList list2 = storage.loadFromFile(); + System.out.println(list2); + } catch (Exception e) { + assertTrue(false, e.getMessage()); + } + } +} From f08662832a249849e1107804152423ff7ddcff01 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Fri, 10 Mar 2023 11:40:43 +0800 Subject: [PATCH 024/210] Add Junit test for three commands --- .../java/seedu/moneymind/CommandTest.java | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/test/java/seedu/moneymind/CommandTest.java diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java new file mode 100644 index 0000000000..90ad7870b8 --- /dev/null +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -0,0 +1,121 @@ +package seedu.moneymind; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class CommandTest { + Category food = new Category("food"); + Category book = new Category("book"); + Event salad = new Event("salad", 100, 50); + Event pizza = new Event("pizza", 200, 100); + Event harryPotter = new Event("Harry Potter", 70, 50); + Event lordOfTheRings = new Event("Lord of the Rings", 90, 20); + + { + food.addEvent(salad); + food.addEvent(pizza); + book.addEvent(harryPotter); + book.addEvent(lordOfTheRings); + CategoryList.categories.add(food); + CategoryList.categories.add(book); + CategoryCommand.categoryMap.put("food", 0); + CategoryCommand.categoryMap.put("book", 1); + } + + @Test + void addCategory_oneCategory_expectThreeCategoryInCategoryList() { + String input = "category travel"; + executeInput(input); + assertTrue(CategoryList.categories.size() == 3); + assertTrue(CategoryList.categories.get(2).getName().equals("travel")); + clear(); + } + + @Test + void addEvent_oneFoodEvent_expectThreeEventsInFoodCategory() { + String input = "event banana b/20 e/10"; + String categoryIndex = "1\n"; // replace with the correct input string + InputStream in = new ByteArrayInputStream(categoryIndex.getBytes()); + System.setIn(in); + executeInput(input); + assertTrue(food.events.get(2).getDescription().equals("banana")); + assertTrue(food.events.get(2).getBudget() == 20); + assertTrue(food.events.get(2).getExpense() == 10); + clear(); + } + + @Test + void deleteWholeCategory_oneCategory_expectOneCategoryInList() { + String input = "delete c/food"; + executeInput(input); + assertTrue(CategoryList.categories.size() == 1); + assertTrue(CategoryList.categories.get(0).getName().equals("book")); + clear(); + } + + @Test + void deleteEvent_oneBookEvent_expectOneEventInBookCategory() { + String input = "delete c/book e/Harry Potter"; + executeInput(input); + assertTrue(book.events.size() == 1); + assertTrue(book.events.get(0).getDescription().equals("Lord of the Rings")); + clear(); + } + + @Test + void viewAll_expectEverythingToBePrintedOut() { + String input = "view"; + Parser parser = new Parser(); + // Get help from chatGPT for the next 2 lines + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outputStream)); + parser.splitKeywordAndDescription(input); + parser.executeUserInput(); + String actual = outputStream.toString(); + String expected = "1.food\r\n" + + "salad [budget]100 [expense]50\r\n" + + "pizza [budget]200 [expense]100\r\n" + + "2.book\r\n" + + "Harry Potter [budget]70 [expense]50\r\n" + + "Lord of the Rings [budget]90 [expense]20\r\n"; + assertEquals(expected, actual); + clear(); + } + + @Test + void viewCategory_expectCategoryToBePrintedOut() { + String input = "view food"; + Parser parser = new Parser(); + // Get help from chatGPT for the next 2 lines + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outputStream)); + parser.splitKeywordAndDescription(input); + parser.executeUserInput(); + String actual = outputStream.toString(); + String expected = "1. salad [budget]100 [expense]50\r\n" + + "2. pizza [budget]200 [expense]100\r\n"; + assertEquals(expected, actual); + clear(); + } + + private static void executeInput(String input) { + Parser parser = new Parser(); + // Get help from chatGPT for the next 2 lines + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outputStream)); + parser.splitKeywordAndDescription(input); + parser.executeUserInput(); + } + + /** Clears all static variables + */ + private static void clear() { + CategoryList.categories.clear(); + CategoryCommand.categoryMap.clear(); + } + +} From 73c9702831a3c729b38fd77be22887f1da9084e7 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Fri, 10 Mar 2023 11:46:31 +0800 Subject: [PATCH 025/210] Fix checkstyle --- src/test/java/seedu/moneymind/CommandTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index 90ad7870b8..2cda1ce91b 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -5,7 +5,9 @@ import java.io.PrintStream; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class CommandTest { Category food = new Category("food"); @@ -111,7 +113,8 @@ private static void executeInput(String input) { parser.executeUserInput(); } - /** Clears all static variables + /** + * Clears all static variables */ private static void clear() { CategoryList.categories.clear(); From 7b65113fdf84967f03193cc0a0e7423ca61753d1 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Fri, 10 Mar 2023 12:55:03 +0800 Subject: [PATCH 026/210] Replace /r/n with /n --- .../java/seedu/moneymind/CommandTest.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index 2cda1ce91b..f9f1dee53b 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -17,7 +17,7 @@ public class CommandTest { Event harryPotter = new Event("Harry Potter", 70, 50); Event lordOfTheRings = new Event("Lord of the Rings", 90, 20); - { + private void setup() { food.addEvent(salad); food.addEvent(pizza); book.addEvent(harryPotter); @@ -30,6 +30,7 @@ public class CommandTest { @Test void addCategory_oneCategory_expectThreeCategoryInCategoryList() { + setup(); String input = "category travel"; executeInput(input); assertTrue(CategoryList.categories.size() == 3); @@ -39,6 +40,7 @@ void addCategory_oneCategory_expectThreeCategoryInCategoryList() { @Test void addEvent_oneFoodEvent_expectThreeEventsInFoodCategory() { + setup(); String input = "event banana b/20 e/10"; String categoryIndex = "1\n"; // replace with the correct input string InputStream in = new ByteArrayInputStream(categoryIndex.getBytes()); @@ -52,6 +54,7 @@ void addEvent_oneFoodEvent_expectThreeEventsInFoodCategory() { @Test void deleteWholeCategory_oneCategory_expectOneCategoryInList() { + setup(); String input = "delete c/food"; executeInput(input); assertTrue(CategoryList.categories.size() == 1); @@ -61,6 +64,7 @@ void deleteWholeCategory_oneCategory_expectOneCategoryInList() { @Test void deleteEvent_oneBookEvent_expectOneEventInBookCategory() { + setup(); String input = "delete c/book e/Harry Potter"; executeInput(input); assertTrue(book.events.size() == 1); @@ -70,6 +74,7 @@ void deleteEvent_oneBookEvent_expectOneEventInBookCategory() { @Test void viewAll_expectEverythingToBePrintedOut() { + setup(); String input = "view"; Parser parser = new Parser(); // Get help from chatGPT for the next 2 lines @@ -78,18 +83,19 @@ void viewAll_expectEverythingToBePrintedOut() { parser.splitKeywordAndDescription(input); parser.executeUserInput(); String actual = outputStream.toString(); - String expected = "1.food\r\n" - + "salad [budget]100 [expense]50\r\n" - + "pizza [budget]200 [expense]100\r\n" - + "2.book\r\n" - + "Harry Potter [budget]70 [expense]50\r\n" - + "Lord of the Rings [budget]90 [expense]20\r\n"; + String expected = "1.food\n" + + "salad [budget]100 [expense]50\n" + + "pizza [budget]200 [expense]100\n" + + "2.book\n" + + "Harry Potter [budget]70 [expense]50\n" + + "Lord of the Rings [budget]90 [expense]20\n"; assertEquals(expected, actual); clear(); } @Test void viewCategory_expectCategoryToBePrintedOut() { + setup(); String input = "view food"; Parser parser = new Parser(); // Get help from chatGPT for the next 2 lines @@ -98,8 +104,8 @@ void viewCategory_expectCategoryToBePrintedOut() { parser.splitKeywordAndDescription(input); parser.executeUserInput(); String actual = outputStream.toString(); - String expected = "1. salad [budget]100 [expense]50\r\n" - + "2. pizza [budget]200 [expense]100\r\n"; + String expected = "1. salad [budget]100 [expense]50\n" + + "2. pizza [budget]200 [expense]100\n"; assertEquals(expected, actual); clear(); } From 1857278d67066ee8c657d59c06181f197a2051a0 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Fri, 10 Mar 2023 13:05:49 +0800 Subject: [PATCH 027/210] Use System.lineSeparator() to work for all platforms --- src/test/java/seedu/moneymind/CommandTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index f9f1dee53b..6a31399633 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -83,12 +83,12 @@ void viewAll_expectEverythingToBePrintedOut() { parser.splitKeywordAndDescription(input); parser.executeUserInput(); String actual = outputStream.toString(); - String expected = "1.food\n" - + "salad [budget]100 [expense]50\n" - + "pizza [budget]200 [expense]100\n" - + "2.book\n" - + "Harry Potter [budget]70 [expense]50\n" - + "Lord of the Rings [budget]90 [expense]20\n"; + String expected = "1.food" + System.lineSeparator() + + "salad [budget]100 [expense]50" + System.lineSeparator() + + "pizza [budget]200 [expense]100" + System.lineSeparator() + + "2.book" + System.lineSeparator() + + "Harry Potter [budget]70 [expense]50" + System.lineSeparator() + + "Lord of the Rings [budget]90 [expense]20" + System.lineSeparator(); assertEquals(expected, actual); clear(); } @@ -104,8 +104,8 @@ void viewCategory_expectCategoryToBePrintedOut() { parser.splitKeywordAndDescription(input); parser.executeUserInput(); String actual = outputStream.toString(); - String expected = "1. salad [budget]100 [expense]50\n" - + "2. pizza [budget]200 [expense]100\n"; + String expected = "1. salad [budget]100 [expense]50" + System.lineSeparator() + + "2. pizza [budget]200 [expense]100" + System.lineSeparator(); assertEquals(expected, actual); clear(); } From f0f5404e281595fbd1806a9eea40c66576a93c62 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Fri, 10 Mar 2023 15:39:46 +0800 Subject: [PATCH 028/210] Add test cases for main class --- .../java/seedu/moneymind/MoneymindTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/java/seedu/moneymind/MoneymindTest.java diff --git a/src/test/java/seedu/moneymind/MoneymindTest.java b/src/test/java/seedu/moneymind/MoneymindTest.java new file mode 100644 index 0000000000..f2b1e52e48 --- /dev/null +++ b/src/test/java/seedu/moneymind/MoneymindTest.java @@ -0,0 +1,20 @@ +package seedu.moneymind; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +public class MoneymindTest { + @Test + public void initialize_null_noExceptionThrown() { + assertDoesNotThrow(() -> { + Moneymind moneymind = new Moneymind(); + }); + } + + @Test + public void run_null_noExceptionThrown() { + Moneymind moneymind = new Moneymind(); + assertDoesNotThrow(moneymind::run); + } +} From af60b3f7b77f5550dad3d13ac27f340f1de1aa1f Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Fri, 10 Mar 2023 15:52:59 +0800 Subject: [PATCH 029/210] Remove test that requires user input and sample test --- src/test/java/seedu/moneymind/DukeTest.java | 12 ------------ src/test/java/seedu/moneymind/MoneymindTest.java | 10 ++++------ 2 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 src/test/java/seedu/moneymind/DukeTest.java diff --git a/src/test/java/seedu/moneymind/DukeTest.java b/src/test/java/seedu/moneymind/DukeTest.java deleted file mode 100644 index da0a58e0fc..0000000000 --- a/src/test/java/seedu/moneymind/DukeTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package seedu.moneymind; - -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/moneymind/MoneymindTest.java b/src/test/java/seedu/moneymind/MoneymindTest.java index f2b1e52e48..2315a5b6c7 100644 --- a/src/test/java/seedu/moneymind/MoneymindTest.java +++ b/src/test/java/seedu/moneymind/MoneymindTest.java @@ -2,6 +2,10 @@ import org.junit.jupiter.api.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; public class MoneymindTest { @@ -11,10 +15,4 @@ public void initialize_null_noExceptionThrown() { Moneymind moneymind = new Moneymind(); }); } - - @Test - public void run_null_noExceptionThrown() { - Moneymind moneymind = new Moneymind(); - assertDoesNotThrow(moneymind::run); - } } From fdd71892fbfd150b524b7510d980ce7b3c9f20bb Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Fri, 10 Mar 2023 16:00:08 +0800 Subject: [PATCH 030/210] Remove unused imports --- src/test/java/seedu/moneymind/MoneymindTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/java/seedu/moneymind/MoneymindTest.java b/src/test/java/seedu/moneymind/MoneymindTest.java index 2315a5b6c7..6ac93a9b4b 100644 --- a/src/test/java/seedu/moneymind/MoneymindTest.java +++ b/src/test/java/seedu/moneymind/MoneymindTest.java @@ -2,10 +2,6 @@ import org.junit.jupiter.api.Test; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; - import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; public class MoneymindTest { From 87668ae2231805522cffb9fe6701a14cf8130439 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 11 Mar 2023 03:19:12 +0800 Subject: [PATCH 031/210] Add two JunitTest including EventTest and CategoryListTest --- .../seedu/moneymind/CategoryListTest.java | 28 +++++++++++++++ .../java/seedu/moneymind/CommandTest.java | 1 - src/test/java/seedu/moneymind/EventTest.java | 36 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/test/java/seedu/moneymind/CategoryListTest.java create mode 100644 src/test/java/seedu/moneymind/EventTest.java diff --git a/src/test/java/seedu/moneymind/CategoryListTest.java b/src/test/java/seedu/moneymind/CategoryListTest.java new file mode 100644 index 0000000000..dba92c3465 --- /dev/null +++ b/src/test/java/seedu/moneymind/CategoryListTest.java @@ -0,0 +1,28 @@ +package seedu.moneymind; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class CategoryListTest { + + /** + * Setup the list with two categories. + */ + public void setup() { + CategoryList.addCategory("food"); + CategoryList.addCategory("book"); + + } + + /** + * Test if the category is added to the list. + * Expected outcome: Category is added to the list. + */ + @Test + void getCategory_index_exptOutcome() { + setup(); + CategoryList.addCategory("test"); //to ensure that the list is not empty + assertEquals(CategoryList.categories.get(0), CategoryList.getCategory(0)); + } +} diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index 6a31399633..f92cfae180 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -126,5 +126,4 @@ private static void clear() { CategoryList.categories.clear(); CategoryCommand.categoryMap.clear(); } - } diff --git a/src/test/java/seedu/moneymind/EventTest.java b/src/test/java/seedu/moneymind/EventTest.java new file mode 100644 index 0000000000..c80264f72d --- /dev/null +++ b/src/test/java/seedu/moneymind/EventTest.java @@ -0,0 +1,36 @@ +package seedu.moneymind; + +import org.junit.jupiter.api.Test; +import seedu.moneymind.Event; + +import static org.junit.jupiter.api.Assertions.*; + +class EventTest { + Event salad = new Event("salad", 100); + Event pizza = new Event("pizza", 200); + Event harryPotter = new Event("Harry Potter", 70, 80); + + @Test + void getBudget_twoEvent_exptOutput() { + assertEquals(100, salad.getBudget()); + assertEquals(100, salad.getBudget()); + } + + @Test + void getExpense_twoEvent_exptOutput() { + assertEquals(0, salad.getExpense()); + assertEquals(80, harryPotter.getExpense()); + } + + @Test + void setBudget_oneBudget_exptBudgetSet() { + salad.setBudget(200); + assertEquals(200, salad.getBudget()); + } + + @Test + void remainingBudget_twoEvent_successCalculation() { + assertEquals(100, salad.remainingBudget()); + assertEquals(120, pizza.remainingBudget()); + } +} \ No newline at end of file From 54db72ce8fec47ae0e4aac1163d366ec28139005 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 11 Mar 2023 03:23:17 +0800 Subject: [PATCH 032/210] Ammended the code quality --- src/test/java/seedu/moneymind/CategoryListTest.java | 2 +- src/test/java/seedu/moneymind/EventTest.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/moneymind/CategoryListTest.java b/src/test/java/seedu/moneymind/CategoryListTest.java index dba92c3465..46c5509a62 100644 --- a/src/test/java/seedu/moneymind/CategoryListTest.java +++ b/src/test/java/seedu/moneymind/CategoryListTest.java @@ -2,7 +2,7 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; class CategoryListTest { diff --git a/src/test/java/seedu/moneymind/EventTest.java b/src/test/java/seedu/moneymind/EventTest.java index c80264f72d..1213f0c03a 100644 --- a/src/test/java/seedu/moneymind/EventTest.java +++ b/src/test/java/seedu/moneymind/EventTest.java @@ -1,9 +1,8 @@ package seedu.moneymind; import org.junit.jupiter.api.Test; -import seedu.moneymind.Event; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; class EventTest { Event salad = new Event("salad", 100); @@ -33,4 +32,4 @@ void remainingBudget_twoEvent_successCalculation() { assertEquals(100, salad.remainingBudget()); assertEquals(120, pizza.remainingBudget()); } -} \ No newline at end of file +} From b99b1eb16bed33baf96f7df7156337b9d27475a5 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 11 Mar 2023 03:27:25 +0800 Subject: [PATCH 033/210] Fix a bug in the code EventTest --- src/test/java/seedu/moneymind/EventTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/moneymind/EventTest.java b/src/test/java/seedu/moneymind/EventTest.java index 1213f0c03a..034c2a907a 100644 --- a/src/test/java/seedu/moneymind/EventTest.java +++ b/src/test/java/seedu/moneymind/EventTest.java @@ -30,6 +30,6 @@ void setBudget_oneBudget_exptBudgetSet() { @Test void remainingBudget_twoEvent_successCalculation() { assertEquals(100, salad.remainingBudget()); - assertEquals(120, pizza.remainingBudget()); + assertEquals(200, pizza.remainingBudget()); } } From 2f7948d8de505422eb27819ee322742573e45a30 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 11 Mar 2023 16:28:32 +0800 Subject: [PATCH 034/210] Add a clear method to CategoryListTest --- src/test/java/seedu/moneymind/CategoryListTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/moneymind/CategoryListTest.java b/src/test/java/seedu/moneymind/CategoryListTest.java index 46c5509a62..f87299f6ca 100644 --- a/src/test/java/seedu/moneymind/CategoryListTest.java +++ b/src/test/java/seedu/moneymind/CategoryListTest.java @@ -12,7 +12,6 @@ class CategoryListTest { public void setup() { CategoryList.addCategory("food"); CategoryList.addCategory("book"); - } /** @@ -24,5 +23,10 @@ void getCategory_index_exptOutcome() { setup(); CategoryList.addCategory("test"); //to ensure that the list is not empty assertEquals(CategoryList.categories.get(0), CategoryList.getCategory(0)); + clear(); + } + + void clear() { + CategoryList.categories.clear(); } } From aa60b7a1e2515c97f905807cd6a542e8a7770198 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Mon, 13 Mar 2023 15:52:52 +0800 Subject: [PATCH 035/210] Add assertions to CategoryList class --- src/main/java/seedu/moneymind/CategoryList.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/seedu/moneymind/CategoryList.java b/src/main/java/seedu/moneymind/CategoryList.java index d0a92b61f2..08fd46b2ba 100644 --- a/src/main/java/seedu/moneymind/CategoryList.java +++ b/src/main/java/seedu/moneymind/CategoryList.java @@ -22,6 +22,7 @@ public static void findCategory(String name) { int count = 0; for (int i = 0; i < categories.size(); i++) { if (categories.get(i).getName().contains(name)) { + assert categories.get(i) != null : "Category should not be null"; count++; System.out.println("index " + (i + 1) + ". " + categories.get(i).getName()); } @@ -53,6 +54,7 @@ public static void deleteCategory(int index) { public static void viewCategoryList() { for (int i = 0; i < categories.size(); i++) { + assert categories.get(i) != null : "Category should not be null"; System.out.println(i + 1 + ". " + categories.get(i).getName()); } } From 36d47a468debe83084b36ef090aeac9360d8eb90 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 11:27:26 +0800 Subject: [PATCH 036/210] add saveFile method and package storage class files --- .../seedu/moneymind/CategoryToString.java | 32 +++++++++++++++++++ .../java/seedu/moneymind/EventCommand.java | 1 + src/main/java/seedu/moneymind/Moneymind.java | 2 ++ .../seedu/moneymind/storage/FormatToTxt.java | 25 +++++++++++++++ .../moneymind/{ => storage}/Storage.java | 27 +++++++--------- .../java/seedu/moneymind/StorageTest.java | 18 +++++++---- 6 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 src/main/java/seedu/moneymind/CategoryToString.java create mode 100644 src/main/java/seedu/moneymind/storage/FormatToTxt.java rename src/main/java/seedu/moneymind/{ => storage}/Storage.java (76%) diff --git a/src/main/java/seedu/moneymind/CategoryToString.java b/src/main/java/seedu/moneymind/CategoryToString.java new file mode 100644 index 0000000000..708e98d501 --- /dev/null +++ b/src/main/java/seedu/moneymind/CategoryToString.java @@ -0,0 +1,32 @@ +package seedu.moneymind; + +/** + * Converts a Category object to a String. + */ +public class CategoryToString { + // String separating each variable of an Event object + private static final String NEXT_VARIABLE = "&&next_detail&&"; + // Creates a new line + private static final String NEW_LINE = System.lineSeparator(); + // Save file symbol for a new category + private static final String CATEGORY_NAME = "&&new_category&&"; + + /** + * Converts a Category object to a String. + * + * @param category the Category object to be converted + * @return the String representation of the Category object + */ + public static String categoryToString(Category category) { + // String of category, to be returned + String output = ""; + + // Adds the category name to the output + output += CATEGORY_NAME + category.getName() + NEW_LINE; + for (Event event : category.events) { + output += NEXT_VARIABLE + event.getDescription() + NEXT_VARIABLE + event.getBudget() + + NEXT_VARIABLE + event.getExpense() + NEW_LINE; + } + return output; + } +} diff --git a/src/main/java/seedu/moneymind/EventCommand.java b/src/main/java/seedu/moneymind/EventCommand.java index 1df1b3722b..66ed72abc7 100644 --- a/src/main/java/seedu/moneymind/EventCommand.java +++ b/src/main/java/seedu/moneymind/EventCommand.java @@ -45,6 +45,7 @@ private void addEvent() { break; } } + in.close(); } /** diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index 99e0cbc482..4d76669c4e 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -1,5 +1,7 @@ package seedu.moneymind; +import seedu.moneymind.storage.Storage; + public class Moneymind { private Ui ui; private Storage storage; diff --git a/src/main/java/seedu/moneymind/storage/FormatToTxt.java b/src/main/java/seedu/moneymind/storage/FormatToTxt.java new file mode 100644 index 0000000000..e082af00da --- /dev/null +++ b/src/main/java/seedu/moneymind/storage/FormatToTxt.java @@ -0,0 +1,25 @@ +package seedu.moneymind.storage; + +import java.util.ArrayList; + +import seedu.moneymind.Category; +import seedu.moneymind.CategoryToString; + +/** + * Converts an ArrayList of Category objects to a String. + */ +public class FormatToTxt { + /** + * Converts an ArrayList of Category objects to a String. + * + * @param categories the ArrayList of Category objects to be converted + * @return the String representation of the ArrayList of Category objects + */ + public static String formatToTxt(ArrayList categories) { + String output = ""; + for (Category category : categories) { + output += CategoryToString.categoryToString(category); + } + return output; + } +} diff --git a/src/main/java/seedu/moneymind/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java similarity index 76% rename from src/main/java/seedu/moneymind/Storage.java rename to src/main/java/seedu/moneymind/storage/Storage.java index 6f0051be4a..dc9d605b7f 100644 --- a/src/main/java/seedu/moneymind/Storage.java +++ b/src/main/java/seedu/moneymind/storage/Storage.java @@ -1,12 +1,18 @@ -package seedu.moneymind; +package seedu.moneymind.storage; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Scanner; + +import seedu.moneymind.Category; + import java.io.FileWriter; import java.io.IOException; +/** + * Storage class to save and load data from a file + */ public class Storage { /** * Divider used to separate details of a task saved in file @@ -48,18 +54,8 @@ private static void setupFile() { * * @param list ArrayList of Events */ - public void saveToFile(ArrayList list) { - String writeToFile = ""; - // TODO: Object to string conversion - for (Event dukeTasks : list) { - // extracting details from task object - String[] dataToTextFile= {"", "", ""}; - dataToTextFile[0] = dukeTasks.toString(); - - // save task details split by regex ", " - writeToFile += dataToTextFile[0] + SAVEFILESEPARATOR + dataToTextFile[1] + - SAVEFILESEPARATOR + dataToTextFile[2] + System.lineSeparator(); - } + public void saveToFile(ArrayList list) { + String writeToFile = FormatToTxt.formatToTxt(list); // write task list to text file try { @@ -76,9 +72,8 @@ public void saveToFile(ArrayList list) { * * @return ArrayList of Events */ - public ArrayList loadFromFile() { - ArrayList savedList = new ArrayList<>(); - //setupFile(); + public ArrayList loadFromFile() { + ArrayList savedList = new ArrayList<>(); while (textFileScanner.hasNext()) { // TODO: Loading of objects from file diff --git a/src/test/java/seedu/moneymind/StorageTest.java b/src/test/java/seedu/moneymind/StorageTest.java index d96286785c..28f5818351 100644 --- a/src/test/java/seedu/moneymind/StorageTest.java +++ b/src/test/java/seedu/moneymind/StorageTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.Test; +import seedu.moneymind.storage.Storage; + public class StorageTest { /** * Tests setupFile() method

@@ -28,8 +30,9 @@ public void setupFile_null_noExceptionThrown() { @Test public void saveToFile_descInput_exptOutcome() { Storage storage = new Storage(); - ArrayList list = new ArrayList<>(); - list.add(new Event("test", 1234, 5678)); + ArrayList list = new ArrayList<>(); + // TODO: Add a test case for saving a list of events + // list.add(new Event("test", 1234, 5678)); assertDoesNotThrow(() -> { storage.saveToFile(list); }); @@ -43,7 +46,7 @@ public void saveToFile_descInput_exptOutcome() { public void loadFromFile_null_noExceptionThrown() { try { Storage storage = new Storage(); - ArrayList list = storage.loadFromFile(); + ArrayList list = storage.loadFromFile(); System.out.println(list); } catch (Exception e) { assertTrue(false, e.getMessage()); @@ -59,11 +62,12 @@ public void loadFromFile_null_noExceptionThrown() { public void saveAndLoadFromFile_descInput_exptOutcome() { try { Storage storage = new Storage(); - ArrayList list = new ArrayList<>(); - list.add(new Event("test", 1234, 5678)); - list.add(new Event("test2", 9876, 5432)); + ArrayList list = new ArrayList<>(); + // TODO: Add a test case for saving a list of events + // list.add(new Event("test", 1234, 5678)); + // list.add(new Event("test2", 9876, 5432)); storage.saveToFile(list); - ArrayList list2 = storage.loadFromFile(); + ArrayList list2 = storage.loadFromFile(); System.out.println(list2); } catch (Exception e) { assertTrue(false, e.getMessage()); From 3ba7247f8a758f667c2421bac72213df357079bc Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Tue, 14 Mar 2023 11:29:42 +0800 Subject: [PATCH 037/210] Improve parser for delete command --- .../java/seedu/moneymind/DeleteCommand.java | 6 ++++ src/main/java/seedu/moneymind/Parser.java | 35 ++++++++----------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/main/java/seedu/moneymind/DeleteCommand.java b/src/main/java/seedu/moneymind/DeleteCommand.java index a40da1ee3a..b430300db7 100644 --- a/src/main/java/seedu/moneymind/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/DeleteCommand.java @@ -7,6 +7,7 @@ public class DeleteCommand { public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; public static final String EVENT_DELETION_MESSAGE = "Event deleted: "; public static final String CATEGORY_DELETION_MESSAGE = "Category deleted: "; + public static final String NON_EXISTENT_EVENT = "Event does not exist"; private String categoryName; private String eventName; @@ -36,6 +37,7 @@ public DeleteCommand(String categoryName) { * Deletes the event. */ private void deleteEvent() { + boolean isEventDeleted = false; if (CategoryCommand.categoryMap.get(categoryName) == null) { System.out.println(NO_CATEGORY_MESSAGE); return; @@ -46,8 +48,12 @@ private void deleteEvent() { if (category.events.get(i).getDescription().equals(eventName)) { category.events.remove(i); System.out.println(EVENT_DELETION_MESSAGE + eventName); + isEventDeleted = true; } } + if (!isEventDeleted) { + System.out.println(NON_EXISTENT_EVENT); + } } /** diff --git a/src/main/java/seedu/moneymind/Parser.java b/src/main/java/seedu/moneymind/Parser.java index 6d5cf8600a..d129596009 100644 --- a/src/main/java/seedu/moneymind/Parser.java +++ b/src/main/java/seedu/moneymind/Parser.java @@ -13,9 +13,6 @@ public class Parser { public static final String EVENT = "event"; public static final String CATEGORY = "category"; public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; - public static final String DELETE_REGEX = "c/(.+) e/(.+)?"; - public static final String CATEGORY_ADDED_MESSAGE = "Category name: "; - public static final String EVENT_ADDED_MESSAGE = "Event name: "; public static final String DELETE_FORMAT = "Please following the correct format: " + "delete c/ e/"; public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + @@ -29,6 +26,7 @@ public class Parser { public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = "☹ OOPS!!! The budget and expense must be a number."; public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; + public static final String DELETE_REGEX = "^c\\/(?=\\S)(.*?)(?:\\s+e\\/(.*))?\\s*$"; private String[] separatedKeywordAndDescription; private String keyword; @@ -79,25 +77,20 @@ private void executeViewCommand() { } private void executeDeleteCommand() { - if (separatedKeywordAndDescription[1].startsWith("c/")) { - try { - String afterCategorySpecifier = separatedKeywordAndDescription[1].substring(2); - Pattern pattern = Pattern.compile("(.+) e/(.+)"); - Matcher matcher = pattern.matcher(afterCategorySpecifier); - if (matcher.find()) { - String categoryName = matcher.group(1); - String eventName = matcher.group(2); - new DeleteCommand(categoryName, eventName); - } else { - System.out.println(afterCategorySpecifier); - new DeleteCommand(afterCategorySpecifier); - } - } catch (IndexOutOfBoundsException e) { - System.out.println(DELETE_FORMAT); - System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); - } catch (Exception e) { - System.out.println(SUBTLE_BUG_MESSAGE); + Pattern pattern = Pattern.compile(DELETE_REGEX); + if (separatedKeywordAndDescription.length == 1) { + System.out.println(EMPTY_DELETION); + return; + } + Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + if (matcher.find()) { + String categoryName = matcher.group(1); + String eventName = matcher.group(2); + if (eventName == null) { + new DeleteCommand(categoryName); + return; } + new DeleteCommand(categoryName, eventName); } else { System.out.println(DELETE_FORMAT); System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); From 0ee54675ed3a15d912c5c3ef4c578f65be163c5d Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Tue, 14 Mar 2023 11:31:37 +0800 Subject: [PATCH 038/210] Add assertions for parser and different commands --- .../java/seedu/moneymind/DeleteCommand.java | 5 ++++ .../java/seedu/moneymind/EventCommand.java | 8 ++++++ .../InvalidCategoryNumberException.java | 3 ++ .../moneymind/NegativeNumberException.java | 10 +++++++ src/main/java/seedu/moneymind/Parser.java | 28 ++++++++++++++----- .../java/seedu/moneymind/ViewCommand.java | 11 ++++++++ 6 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/main/java/seedu/moneymind/NegativeNumberException.java diff --git a/src/main/java/seedu/moneymind/DeleteCommand.java b/src/main/java/seedu/moneymind/DeleteCommand.java index b430300db7..511a2bf009 100644 --- a/src/main/java/seedu/moneymind/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/DeleteCommand.java @@ -8,6 +8,8 @@ public class DeleteCommand { public static final String EVENT_DELETION_MESSAGE = "Event deleted: "; public static final String CATEGORY_DELETION_MESSAGE = "Category deleted: "; public static final String NON_EXISTENT_EVENT = "Event does not exist"; + public static final String NULL_CATEGORY_ASSERTION = "Category name should not be null"; + public static final String NULL_EVENT_ASSERTION = "Event name should not be null"; private String categoryName; private String eventName; @@ -20,6 +22,8 @@ public class DeleteCommand { public DeleteCommand(String categoryName, String eventName) { this.categoryName = categoryName; this.eventName = eventName; + assert categoryName != null : NULL_CATEGORY_ASSERTION; + assert eventName != null : NULL_EVENT_ASSERTION; deleteEvent(); } @@ -30,6 +34,7 @@ public DeleteCommand(String categoryName, String eventName) { */ public DeleteCommand(String categoryName) { this.categoryName = categoryName; + assert categoryName != null : NULL_CATEGORY_ASSERTION; deleteCategory(); } diff --git a/src/main/java/seedu/moneymind/EventCommand.java b/src/main/java/seedu/moneymind/EventCommand.java index 1df1b3722b..7f9b38d4f7 100644 --- a/src/main/java/seedu/moneymind/EventCommand.java +++ b/src/main/java/seedu/moneymind/EventCommand.java @@ -13,6 +13,10 @@ public class EventCommand { public static final String REMINDING_MESSAGE_TO_GIVE_A_NUMBER = "Please enter a number."; public static final String CATEGORY_OUT_OF_RANGE = "The category number you entered is out of range"; public static final String SUBTLE_BUG_MESSAGE = "Something went wrong, please report to the developer"; + public static final String NON_NEGATIVE_POSITION_ASSERTION = "Category position cannot be negative"; + public static final String NULL_EVENT_ASSERTION = "Event name cannot be null"; + public static final String NON_NEGATIVE_BUDGET_ASSERTION = "Budget cannot be negative"; + public static final String NON_NEGATIVE_EXPENSE_ASSERTION = "Expense cannot be negative"; private String eventName; private int budget; private int expense; @@ -28,6 +32,9 @@ public EventCommand(String eventName, int budget, int expense) { this.eventName = eventName; this.budget = budget; this.expense = expense; + assert eventName != null : NULL_EVENT_ASSERTION; + assert budget >= 0 : NON_NEGATIVE_BUDGET_ASSERTION; + assert expense >= 0 : NON_NEGATIVE_EXPENSE_ASSERTION; addEvent(); } @@ -51,6 +58,7 @@ private void addEvent() { * Add an event to a category. */ private void addEventToCategory(int categoryPosition, Event event) { + assert categoryPosition > 0 : NON_NEGATIVE_POSITION_ASSERTION; Category category = CategoryList.getCategory(categoryPosition - 1); category.addEvent(event); System.out.println(EVENT_ADDED_MESSAGE + event.getDescription()); diff --git a/src/main/java/seedu/moneymind/InvalidCategoryNumberException.java b/src/main/java/seedu/moneymind/InvalidCategoryNumberException.java index 6e24818deb..bfc13298dd 100644 --- a/src/main/java/seedu/moneymind/InvalidCategoryNumberException.java +++ b/src/main/java/seedu/moneymind/InvalidCategoryNumberException.java @@ -1,5 +1,8 @@ package seedu.moneymind; +/** + * Throws exception when the user input an invalid category number. + */ public class InvalidCategoryNumberException extends Exception{ // no need to write the code } diff --git a/src/main/java/seedu/moneymind/NegativeNumberException.java b/src/main/java/seedu/moneymind/NegativeNumberException.java new file mode 100644 index 0000000000..61cfe791f3 --- /dev/null +++ b/src/main/java/seedu/moneymind/NegativeNumberException.java @@ -0,0 +1,10 @@ +package seedu.moneymind; + +/** + * Throws exception when the user input a negative number. + */ +public class NegativeNumberException extends Exception { + public NegativeNumberException() { + // no need to write the code + } +} diff --git a/src/main/java/seedu/moneymind/Parser.java b/src/main/java/seedu/moneymind/Parser.java index d129596009..47ceecde9c 100644 --- a/src/main/java/seedu/moneymind/Parser.java +++ b/src/main/java/seedu/moneymind/Parser.java @@ -19,14 +19,17 @@ public class Parser { "inside the brackets empty!"; public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; - public static final String EVENT_REGEX = "(.+) b/(\\d+) e/(\\d+)?"; + public static final String EVENT_REGEX = "(.+) b/(-?\\d+) e/(-?\\d+)"; public static final String EVENT_FORMAT = "Please following the correct format: " + "event b/ e/"; public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = "☹ OOPS!!! The budget and expense must be a number."; public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; - public static final String DELETE_REGEX = "^c\\/(?=\\S)(.*?)(?:\\s+e\\/(.*))?\\s*$"; + public static final String DELETE_REGEX = "^c/(?=\\S)(.*?)(?:\\s+e/(.*))?\\s*$"; + public static final String NULL_INPUT_ASSERTION = "Input cannot be null"; + public static final String NULL_DESCRIPTION = "Separated keyword and description cannot be null"; + public static final String REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER = "Please enter a positive number for budget and expense"; private String[] separatedKeywordAndDescription; private String keyword; @@ -34,6 +37,7 @@ public class Parser { * Splits the user input into keyword and description. */ public void splitKeywordAndDescription(String input) { + assert input != null : NULL_INPUT_ASSERTION; separatedKeywordAndDescription = input.split(WHITE_SPACE, 2); keyword = separatedKeywordAndDescription[0]; } @@ -42,6 +46,7 @@ public void splitKeywordAndDescription(String input) { * Executes the user input. */ public void executeUserInput() { + assert separatedKeywordAndDescription != null : NULL_DESCRIPTION; switch (keyword) { case BYE: executeByeCommand(); @@ -65,7 +70,7 @@ public void executeUserInput() { } private void executeByeCommand() { - ByeCommand byeCommand = new ByeCommand(); + new ByeCommand(); } private void executeViewCommand() { @@ -105,24 +110,33 @@ private void executeEventCommand() { String eventName = matcher.group(1); String budgetNumber = matcher.group(2); String expenseNumber = matcher.group(3); + checkNegativeBudgetAndExpense(Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); } else { System.out.println(EVENT_FORMAT); System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } - } catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException error) { System.out.println(EVENT_EMPTY); - } catch (NumberFormatException e) { + } catch (NumberFormatException error) { System.out.println(REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER); - } catch (Exception e) { + } catch (NegativeNumberException error) { + System.out.println(REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER); + } catch (Exception error) { System.out.println(SUBTLE_BUG_MESSAGE); } } + private void checkNegativeBudgetAndExpense(int budget, int expense) throws NegativeNumberException { + if (budget < 0 || expense < 0) { + throw new NegativeNumberException(); + } + } + private void executeCategoryCommand() { try { new CategoryCommand(separatedKeywordAndDescription[1]); - } catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException error) { System.out.println(CATEGORY_EMPTY); } } diff --git a/src/main/java/seedu/moneymind/ViewCommand.java b/src/main/java/seedu/moneymind/ViewCommand.java index f717bcb82b..da065e0443 100644 --- a/src/main/java/seedu/moneymind/ViewCommand.java +++ b/src/main/java/seedu/moneymind/ViewCommand.java @@ -6,6 +6,10 @@ public class ViewCommand { public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; public static final String DOT = "."; + public static final String NO_CATEGORIES_TO_VIEW = "There are no categories to view"; + public static final String COUNT_ASSERTION = "Count should be greater than 1"; + public static final String NULL_CATEGORY_ASSERTION = "Category name should not be null"; + public static final String NULL_CATEGORY_LIST_ASSERTION = "Category list should not be null"; private String categoryName; /** @@ -15,6 +19,7 @@ public class ViewCommand { */ public ViewCommand(String categoryName) { this.categoryName = categoryName; + assert categoryName != null : NULL_CATEGORY_ASSERTION; viewCategory(); } @@ -22,6 +27,7 @@ public ViewCommand(String categoryName) { * Constructs a new ViewCommand object and views all the categories. */ public ViewCommand() { + assert CategoryList.categories != null : NULL_CATEGORY_LIST_ASSERTION; viewAll(); } @@ -39,6 +45,10 @@ private void viewCategory() { * Views all the categories and events. */ private void viewAll() { + if (CategoryList.categories.size() == 0) { + System.out.println(NO_CATEGORIES_TO_VIEW); + return; + } int count = 1; for (Category category : CategoryList.categories) { System.out.println(count + DOT + category.getName()); @@ -48,6 +58,7 @@ private void viewAll() { System.out.println(event.toString()); } } + assert count > 1 : COUNT_ASSERTION; } } From 69049ddf60aecdd09e491b9324204a988b7caa31 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Tue, 14 Mar 2023 11:39:23 +0800 Subject: [PATCH 039/210] Fix checkstyle for parser --- src/main/java/seedu/moneymind/Parser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/moneymind/Parser.java b/src/main/java/seedu/moneymind/Parser.java index 47ceecde9c..9e44d18825 100644 --- a/src/main/java/seedu/moneymind/Parser.java +++ b/src/main/java/seedu/moneymind/Parser.java @@ -29,7 +29,8 @@ public class Parser { public static final String DELETE_REGEX = "^c/(?=\\S)(.*?)(?:\\s+e/(.*))?\\s*$"; public static final String NULL_INPUT_ASSERTION = "Input cannot be null"; public static final String NULL_DESCRIPTION = "Separated keyword and description cannot be null"; - public static final String REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER = "Please enter a positive number for budget and expense"; + public static final String REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER = + "Please enter a positive number for budget and expense"; private String[] separatedKeywordAndDescription; private String keyword; From 3b494f43e2a3788d473b1def42213e15f770f05d Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 13:39:02 +0800 Subject: [PATCH 040/210] add StringToCategory class for load method from storage --- EventList.txt | 1 - .../seedu/moneymind/CategoryToString.java | 8 +-- .../java/seedu/moneymind/EventCommand.java | 1 - .../seedu/moneymind/StringToCategory.java | 39 +++++++++++++++ .../java/seedu/moneymind/storage/Storage.java | 49 +++++++------------ 5 files changed, 60 insertions(+), 38 deletions(-) create mode 100644 src/main/java/seedu/moneymind/StringToCategory.java diff --git a/EventList.txt b/EventList.txt index 78185d9146..e69de29bb2 100644 --- a/EventList.txt +++ b/EventList.txt @@ -1 +0,0 @@ -test [budget]1234 [expense]5678, , diff --git a/src/main/java/seedu/moneymind/CategoryToString.java b/src/main/java/seedu/moneymind/CategoryToString.java index 708e98d501..baf80c4c8b 100644 --- a/src/main/java/seedu/moneymind/CategoryToString.java +++ b/src/main/java/seedu/moneymind/CategoryToString.java @@ -4,12 +4,12 @@ * Converts a Category object to a String. */ public class CategoryToString { - // String separating each variable of an Event object - private static final String NEXT_VARIABLE = "&&next_detail&&"; + // String symbol separating each variable of an Event object + protected static final String NEXT_VARIABLE = "&&next_detail&&"; // Creates a new line - private static final String NEW_LINE = System.lineSeparator(); + protected static final String NEW_LINE = System.lineSeparator(); // Save file symbol for a new category - private static final String CATEGORY_NAME = "&&new_category&&"; + protected static final String CATEGORY_NAME = "&&new_category&&"; /** * Converts a Category object to a String. diff --git a/src/main/java/seedu/moneymind/EventCommand.java b/src/main/java/seedu/moneymind/EventCommand.java index 66ed72abc7..1df1b3722b 100644 --- a/src/main/java/seedu/moneymind/EventCommand.java +++ b/src/main/java/seedu/moneymind/EventCommand.java @@ -45,7 +45,6 @@ private void addEvent() { break; } } - in.close(); } /** diff --git a/src/main/java/seedu/moneymind/StringToCategory.java b/src/main/java/seedu/moneymind/StringToCategory.java new file mode 100644 index 0000000000..651f4c5029 --- /dev/null +++ b/src/main/java/seedu/moneymind/StringToCategory.java @@ -0,0 +1,39 @@ +package seedu.moneymind; + +import java.util.ArrayList; + +/** + * Converts a String from file.txt to an ArrayList of Category objects. + */ +public class StringToCategory extends CategoryToString{ + /** + * Converts a String from file.txt to an ArrayList of Category objects. + * + * @param inputFromFile String from file.txt + * @return ArrayList of Category objects + */ + public static ArrayList stringToCategory(String inputFromFile) { + // ArrayList of Categories objects, to be returned + ArrayList categories = new ArrayList<>(); + + // Reads inputFromFile line by line + String[] lines = inputFromFile.split(System.lineSeparator()); + for (String string : lines) { + // Creates a new Category object if the line is a new category, ignoring the save file symbol + if (string.startsWith(CATEGORY_NAME)) { + categories.add(new Category(string.substring(CATEGORY_NAME.length()))); + } else if (string.startsWith(NEXT_VARIABLE)) { + // Remove the first next variable symbol + string = string.substring(NEXT_VARIABLE.length()); + // Splits the line into 3 parts, each part being a variable of an Event object + String[] eventDetails = string.split(NEXT_VARIABLE); + // Creates a new Event object + Event event = new Event(eventDetails[0], Integer.parseInt(eventDetails[1]), + Integer.parseInt(eventDetails[2])); + // Adds an Event object to the last Category object in the ArrayList + categories.get(categories.size() - 1).addEvent(event); + } + } + return categories; + } +} diff --git a/src/main/java/seedu/moneymind/storage/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java index dc9d605b7f..c1c0a32d06 100644 --- a/src/main/java/seedu/moneymind/storage/Storage.java +++ b/src/main/java/seedu/moneymind/storage/Storage.java @@ -6,6 +6,7 @@ import java.util.Scanner; import seedu.moneymind.Category; +import seedu.moneymind.StringToCategory; import java.io.FileWriter; import java.io.IOException; @@ -14,12 +15,7 @@ * Storage class to save and load data from a file */ public class Storage { - /** - * Divider used to separate details of a task saved in file - */ - private static final String SAVEFILESEPARATOR = ", "; private static File textFile; - private static Scanner textFileScanner; private static String filePath = "EventList.txt"; /** @@ -41,18 +37,12 @@ private static void setupFile() { } catch (IOException e) { System.out.println("The file already exists."); } - - try { - textFileScanner = new Scanner(textFile); - } catch (FileNotFoundException e) { - System.out.println("I cannot seem to access the saved tasks. Did you perhaps lock it away?"); - } } /** - * Saves an ArrayList of Events to EventList.txt file + * Saves an ArrayList of Category to EventList.txt file * - * @param list ArrayList of Events + * @param list ArrayList of Category */ public void saveToFile(ArrayList list) { String writeToFile = FormatToTxt.formatToTxt(list); @@ -68,31 +58,26 @@ public void saveToFile(ArrayList list) { } /** - * Returns an ArrayList of Events from EventList.txt file + * Loads an ArrayList of Category from EventList.txt file * - * @return ArrayList of Events + * @return ArrayList of Category */ public ArrayList loadFromFile() { - ArrayList savedList = new ArrayList<>(); + Scanner textFileScanner; + // String to store the text file + String fileString = ""; - while (textFileScanner.hasNext()) { - // TODO: Loading of objects from file - String[] loadTaskInfo = new String[3]; - loadTaskInfo = textFileScanner.nextLine().split(SAVEFILESEPARATOR, 3); - - // create tasks individually - switch (loadTaskInfo[0]) { - case "CATEGORY": - break; - - case "EVENT": - break; - - default: - break; + try { + textFileScanner = new Scanner(textFile); + // read file line by line and add to fileString + while (textFileScanner.hasNextLine()) { + fileString += textFileScanner.nextLine() + System.lineSeparator(); } + } catch (FileNotFoundException e) { + System.out.println("I cannot seem to access the saved tasks. Did you perhaps lock it away?"); } - + // convert fileString to ArrayList of Category + ArrayList savedList = StringToCategory.stringToCategory(fileString); return savedList; } } From e5bb41ab098f71d8266b145591e5d1765cfa1c67 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 14 Mar 2023 14:08:49 +0800 Subject: [PATCH 041/210] Refactor to be more OOP and link commands to main function --- src/main/java/seedu/moneymind/{ => Command}/ByeCommand.java | 0 .../java/seedu/moneymind/{ => Command}/CategoryCommand.java | 0 src/main/java/seedu/moneymind/{ => Command}/Command.java | 1 - src/main/java/seedu/moneymind/{ => Command}/DeleteCommand.java | 0 src/main/java/seedu/moneymind/{ => Command}/EventCommand.java | 0 .../seedu/moneymind/{ => Command}/InvalidCommandException.java | 0 src/main/java/seedu/moneymind/{ => Command}/Parser.java | 0 src/main/java/seedu/moneymind/{ => Command}/ViewCommand.java | 0 src/main/java/seedu/moneymind/Strings.java | 2 ++ 9 files changed, 2 insertions(+), 1 deletion(-) rename src/main/java/seedu/moneymind/{ => Command}/ByeCommand.java (100%) rename src/main/java/seedu/moneymind/{ => Command}/CategoryCommand.java (100%) rename src/main/java/seedu/moneymind/{ => Command}/Command.java (99%) rename src/main/java/seedu/moneymind/{ => Command}/DeleteCommand.java (100%) rename src/main/java/seedu/moneymind/{ => Command}/EventCommand.java (100%) rename src/main/java/seedu/moneymind/{ => Command}/InvalidCommandException.java (100%) rename src/main/java/seedu/moneymind/{ => Command}/Parser.java (100%) rename src/main/java/seedu/moneymind/{ => Command}/ViewCommand.java (100%) create mode 100644 src/main/java/seedu/moneymind/Strings.java diff --git a/src/main/java/seedu/moneymind/ByeCommand.java b/src/main/java/seedu/moneymind/Command/ByeCommand.java similarity index 100% rename from src/main/java/seedu/moneymind/ByeCommand.java rename to src/main/java/seedu/moneymind/Command/ByeCommand.java diff --git a/src/main/java/seedu/moneymind/CategoryCommand.java b/src/main/java/seedu/moneymind/Command/CategoryCommand.java similarity index 100% rename from src/main/java/seedu/moneymind/CategoryCommand.java rename to src/main/java/seedu/moneymind/Command/CategoryCommand.java diff --git a/src/main/java/seedu/moneymind/Command.java b/src/main/java/seedu/moneymind/Command/Command.java similarity index 99% rename from src/main/java/seedu/moneymind/Command.java rename to src/main/java/seedu/moneymind/Command/Command.java index fa32f68bab..f31c5ba27c 100644 --- a/src/main/java/seedu/moneymind/Command.java +++ b/src/main/java/seedu/moneymind/Command/Command.java @@ -49,4 +49,3 @@ public boolean isExit() { enum CommandType { ECHO, EXIT } - diff --git a/src/main/java/seedu/moneymind/DeleteCommand.java b/src/main/java/seedu/moneymind/Command/DeleteCommand.java similarity index 100% rename from src/main/java/seedu/moneymind/DeleteCommand.java rename to src/main/java/seedu/moneymind/Command/DeleteCommand.java diff --git a/src/main/java/seedu/moneymind/EventCommand.java b/src/main/java/seedu/moneymind/Command/EventCommand.java similarity index 100% rename from src/main/java/seedu/moneymind/EventCommand.java rename to src/main/java/seedu/moneymind/Command/EventCommand.java diff --git a/src/main/java/seedu/moneymind/InvalidCommandException.java b/src/main/java/seedu/moneymind/Command/InvalidCommandException.java similarity index 100% rename from src/main/java/seedu/moneymind/InvalidCommandException.java rename to src/main/java/seedu/moneymind/Command/InvalidCommandException.java diff --git a/src/main/java/seedu/moneymind/Parser.java b/src/main/java/seedu/moneymind/Command/Parser.java similarity index 100% rename from src/main/java/seedu/moneymind/Parser.java rename to src/main/java/seedu/moneymind/Command/Parser.java diff --git a/src/main/java/seedu/moneymind/ViewCommand.java b/src/main/java/seedu/moneymind/Command/ViewCommand.java similarity index 100% rename from src/main/java/seedu/moneymind/ViewCommand.java rename to src/main/java/seedu/moneymind/Command/ViewCommand.java diff --git a/src/main/java/seedu/moneymind/Strings.java b/src/main/java/seedu/moneymind/Strings.java new file mode 100644 index 0000000000..2d0c77cada --- /dev/null +++ b/src/main/java/seedu/moneymind/Strings.java @@ -0,0 +1,2 @@ +package seedu.moneymind;public class Strings { +} From 3f713e49748ff223bdea3f7d218d7fcbbf7ce9cf Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 14 Mar 2023 14:10:22 +0800 Subject: [PATCH 042/210] Actual refactor, forgot to stage changes for previous commit --- text-ui-test/EXPECTED.TXT | 2 +- text-ui-test/input.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index d1e320a6f0..67d7a36f6c 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,5 +1,5 @@ Hello from [LOGO_PLACEHOLDER] How may I help you? -test Bye. Hope to see you again soon! +____________________________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 8e24493055..b023018cab 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1,2 +1 @@ -echo test bye From 4969aa83e4670554679cfc5dd0c90d45e1132fe8 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 14 Mar 2023 14:13:38 +0800 Subject: [PATCH 043/210] Revert "Actual refactor, forgot to stage changes for previous commit" This reverts commit 3f713e49748ff223bdea3f7d218d7fcbbf7ce9cf. --- text-ui-test/EXPECTED.TXT | 2 +- text-ui-test/input.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 67d7a36f6c..d1e320a6f0 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,5 +1,5 @@ Hello from [LOGO_PLACEHOLDER] How may I help you? +test Bye. Hope to see you again soon! -____________________________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index b023018cab..8e24493055 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -1 +1,2 @@ +echo test bye From 51baf31be081a3a09d185fd7489b21608c5a25b6 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 14 Mar 2023 14:15:14 +0800 Subject: [PATCH 044/210] Actual commit --- src/main/java/seedu/moneymind/Category.java | 4 + .../seedu/moneymind/Command/ByeCommand.java | 25 ++-- .../moneymind/Command/CategoryCommand.java | 20 +++- .../java/seedu/moneymind/Command/Command.java | 53 +-------- .../moneymind/Command/DeleteCommand.java | 33 ++++-- .../seedu/moneymind/Command/EventCommand.java | 45 ++++---- .../Command/InvalidCommandException.java | 10 +- .../java/seedu/moneymind/Command/Parser.java | 107 ++++++------------ .../seedu/moneymind/Command/ViewCommand.java | 35 +++++- src/main/java/seedu/moneymind/Moneymind.java | 18 ++- src/main/java/seedu/moneymind/Strings.java | 29 ++++- src/main/java/seedu/moneymind/Ui.java | 17 +-- .../java/seedu/moneymind/CommandTest.java | 54 +++++---- 13 files changed, 241 insertions(+), 209 deletions(-) diff --git a/src/main/java/seedu/moneymind/Category.java b/src/main/java/seedu/moneymind/Category.java index 1de5b96300..8be14ffc9d 100644 --- a/src/main/java/seedu/moneymind/Category.java +++ b/src/main/java/seedu/moneymind/Category.java @@ -23,6 +23,10 @@ public String getName() { return name; } + public ArrayList getEvents() { + return events; + } + /** * Add the event to the list. */ diff --git a/src/main/java/seedu/moneymind/Command/ByeCommand.java b/src/main/java/seedu/moneymind/Command/ByeCommand.java index 8d4b580766..b3bca0019e 100644 --- a/src/main/java/seedu/moneymind/Command/ByeCommand.java +++ b/src/main/java/seedu/moneymind/Command/ByeCommand.java @@ -1,23 +1,18 @@ -package seedu.moneymind; +package seedu.moneymind.Command; + +import seedu.moneymind.Ui; /** * Represents the command to exit the program. */ -public class ByeCommand { - - private static final String BYE_MESSAGE = "Bye. Hope to see you again soon!"; - private static final String HORIZONTAL_LINE = "____________________________________________________________"; - /** - * Constructs a new ByeCommand object and exits the program. - */ - public ByeCommand() { - doByeCommand(); +public class ByeCommand implements Command { + @Override + public void execute(Ui ui) { + ui.goodbye(); } - private void doByeCommand() { - System.out.println(BYE_MESSAGE); - System.out.println(HORIZONTAL_LINE); - System.exit(0); + @Override + public boolean isExit() { + return true; } - } diff --git a/src/main/java/seedu/moneymind/Command/CategoryCommand.java b/src/main/java/seedu/moneymind/Command/CategoryCommand.java index e4b7d63ec7..bb55a165f7 100644 --- a/src/main/java/seedu/moneymind/Command/CategoryCommand.java +++ b/src/main/java/seedu/moneymind/Command/CategoryCommand.java @@ -1,19 +1,29 @@ -package seedu.moneymind; +package seedu.moneymind.Command; + +import seedu.moneymind.Category; +import seedu.moneymind.CategoryList; +import seedu.moneymind.Ui; import java.util.HashMap; -public class CategoryCommand { +public class CategoryCommand implements Command { public static HashMap categoryMap = new HashMap(); - private String name; + private final String name; public CategoryCommand(String name) { this.name = name; - addCategory(); } - private void addCategory() { + + @Override + public void execute(Ui ui) { Category category = new Category(name); CategoryList.categories.add(category); categoryMap.put(name, CategoryList.categories.size() - 1); System.out.println("New category added: " + name); } + + @Override + public boolean isExit() { + return false; + } } diff --git a/src/main/java/seedu/moneymind/Command/Command.java b/src/main/java/seedu/moneymind/Command/Command.java index f31c5ba27c..2cd73e14ac 100644 --- a/src/main/java/seedu/moneymind/Command/Command.java +++ b/src/main/java/seedu/moneymind/Command/Command.java @@ -1,51 +1,8 @@ -package seedu.moneymind; +package seedu.moneymind.Command; -public class Command { - private CommandType type; - private String value; +import seedu.moneymind.Ui; - public Command(String input) throws InvalidCommandException { - String[] tokens = input.split(" ", 2); - - String command = tokens[0]; - - // assign command type only - switch (command) { - case "bye": - this.type = CommandType.EXIT; - break; - case "echo": - this.type = CommandType.ECHO; - break; - default: - throw new InvalidCommandException(); - } - - // process value based on command type, only for commands with parameters - switch (type) { - case ECHO: - this.value = tokens[1]; - break; - default: - break; - } - } - - public void execute(Ui ui) { - switch (type) { - case ECHO: - ui.echo(value); - break; - default: - break; - } - } - - public boolean isExit() { - return type == CommandType.EXIT; - } -} - -enum CommandType { - ECHO, EXIT +public interface Command { + void execute(Ui ui); + boolean isExit(); } diff --git a/src/main/java/seedu/moneymind/Command/DeleteCommand.java b/src/main/java/seedu/moneymind/Command/DeleteCommand.java index a40da1ee3a..288adafce1 100644 --- a/src/main/java/seedu/moneymind/Command/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/Command/DeleteCommand.java @@ -1,14 +1,19 @@ -package seedu.moneymind; +package seedu.moneymind.Command; + +import seedu.moneymind.Category; +import seedu.moneymind.CategoryList; +import seedu.moneymind.Ui; /** * Represents the command to delete an event or a category. */ -public class DeleteCommand { +public class DeleteCommand implements Command { public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; public static final String EVENT_DELETION_MESSAGE = "Event deleted: "; public static final String CATEGORY_DELETION_MESSAGE = "Category deleted: "; private String categoryName; private String eventName; + private boolean isEvent; /** * Constructs a new DeleteCommand object and deletes the event. @@ -19,7 +24,7 @@ public class DeleteCommand { public DeleteCommand(String categoryName, String eventName) { this.categoryName = categoryName; this.eventName = eventName; - deleteEvent(); + this.isEvent = true; } /** @@ -29,7 +34,7 @@ public DeleteCommand(String categoryName, String eventName) { */ public DeleteCommand(String categoryName) { this.categoryName = categoryName; - deleteCategory(); + this.isEvent = false; } /** @@ -42,9 +47,9 @@ private void deleteEvent() { } int categoryIndex = CategoryCommand.categoryMap.get(categoryName); Category category = CategoryList.categories.get(categoryIndex); - for (int i = 0; i < category.events.size(); i++) { - if (category.events.get(i).getDescription().equals(eventName)) { - category.events.remove(i); + for (int i = 0; i < category.getEvents().size(); i++) { + if (category.getEvents().get(i).getDescription().equals(eventName)) { + category.getEvents().remove(i); System.out.println(EVENT_DELETION_MESSAGE + eventName); } } @@ -63,4 +68,18 @@ private void deleteCategory() { CategoryCommand.categoryMap.remove(categoryName); System.out.println(CATEGORY_DELETION_MESSAGE + categoryName); } + + @Override + public void execute(Ui ui) { + if (isEvent) { + deleteEvent(); + } else { + deleteCategory(); + } + } + + @Override + public boolean isExit() { + return false; + } } diff --git a/src/main/java/seedu/moneymind/Command/EventCommand.java b/src/main/java/seedu/moneymind/Command/EventCommand.java index 1df1b3722b..d356bf87c4 100644 --- a/src/main/java/seedu/moneymind/Command/EventCommand.java +++ b/src/main/java/seedu/moneymind/Command/EventCommand.java @@ -1,11 +1,13 @@ -package seedu.moneymind; +package seedu.moneymind.Command; + +import seedu.moneymind.*; import java.util.Scanner; /** * A class to add an event */ -public class EventCommand { +public class EventCommand implements Command { public static final String SELECTING_CATEGORY_MESSAGE = "Please select the category you want to add the event to: "; public static final String GO_BACK_MESSAGE = "Please enter back to go back to the main program"; public static final String BACK = "back"; @@ -28,23 +30,6 @@ public EventCommand(String eventName, int budget, int expense) { this.eventName = eventName; this.budget = budget; this.expense = expense; - addEvent(); - } - - private void addEvent() { - Event event = new Event(eventName, budget, expense); - System.out.println(SELECTING_CATEGORY_MESSAGE); - String userInput; - Scanner in; - in = new Scanner(System.in); - userInput = in.nextLine(); - while (!isChooseCategorySuccessful(userInput)) { - System.out.println(GO_BACK_MESSAGE); - userInput = in.nextLine(); - if (userInput.equals(BACK)) { - break; - } - } } /** @@ -89,4 +74,26 @@ private void testCategoryNumber(int categoryPosition) throws InvalidCategoryNumb throw new InvalidCategoryNumberException(); } } + + @Override + public void execute(Ui ui) { + Event event = new Event(eventName, budget, expense); + System.out.println(SELECTING_CATEGORY_MESSAGE); + String userInput; + Scanner in; + in = new Scanner(System.in); + userInput = in.nextLine(); + while (!isChooseCategorySuccessful(userInput)) { + System.out.println(GO_BACK_MESSAGE); + userInput = in.nextLine(); + if (userInput.equals(BACK)) { + break; + } + } + } + + @Override + public boolean isExit() { + return false; + } } diff --git a/src/main/java/seedu/moneymind/Command/InvalidCommandException.java b/src/main/java/seedu/moneymind/Command/InvalidCommandException.java index 90b831ebcd..eb540e06ab 100644 --- a/src/main/java/seedu/moneymind/Command/InvalidCommandException.java +++ b/src/main/java/seedu/moneymind/Command/InvalidCommandException.java @@ -1,5 +1,13 @@ -package seedu.moneymind; +package seedu.moneymind.Command; public class InvalidCommandException extends Exception { + private String errorMessage; + public InvalidCommandException(String errorMessage) { + this.errorMessage = errorMessage; + } + + public void showErrorMessage() { + System.out.println(errorMessage); + } } diff --git a/src/main/java/seedu/moneymind/Command/Parser.java b/src/main/java/seedu/moneymind/Command/Parser.java index 6d5cf8600a..25d12216f2 100644 --- a/src/main/java/seedu/moneymind/Command/Parser.java +++ b/src/main/java/seedu/moneymind/Command/Parser.java @@ -1,84 +1,51 @@ -package seedu.moneymind; +package seedu.moneymind.Command; + +import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static seedu.moneymind.Strings.*; + /** * A class to parse the user input. */ public class Parser { - public static final String WHITE_SPACE = " "; - public static final String BYE = "bye"; - public static final String VIEW = "view"; - public static final String DELETE = "delete"; - public static final String EVENT = "event"; - public static final String CATEGORY = "category"; - public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; - public static final String DELETE_REGEX = "c/(.+) e/(.+)?"; - public static final String CATEGORY_ADDED_MESSAGE = "Category name: "; - public static final String EVENT_ADDED_MESSAGE = "Event name: "; - public static final String DELETE_FORMAT = "Please following the correct format: " + - "delete c/ e/"; - public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + - "inside the brackets empty!"; - public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; - public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; - public static final String EVENT_REGEX = "(.+) b/(\\d+) e/(\\d+)?"; - public static final String EVENT_FORMAT = "Please following the correct format: " + - "event b/ e/"; - public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; - public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = - "☹ OOPS!!! The budget and expense must be a number."; - public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; - private String[] separatedKeywordAndDescription; - private String keyword; - /** - * Splits the user input into keyword and description. + * Parses the next line and returns a command object, or throws. */ - public void splitKeywordAndDescription(String input) { - separatedKeywordAndDescription = input.split(WHITE_SPACE, 2); - keyword = separatedKeywordAndDescription[0]; - } + public Command parseNextCommand(String input) throws Exception { + String[] separatedKeywordAndDescription = input.split(WHITE_SPACE, 2); + String keyword = separatedKeywordAndDescription[0]; - /** - * Executes the user input. - */ - public void executeUserInput() { switch (keyword) { case BYE: - executeByeCommand(); - break; + return createByeCommand(); case VIEW: - executeViewCommand(); - break; + return createViewCommand(separatedKeywordAndDescription); case DELETE: - executeDeleteCommand(); - break; + return createDeleteCommand(separatedKeywordAndDescription); case EVENT: - executeEventCommand(); - break; + return createEventCommand(separatedKeywordAndDescription); case CATEGORY: - executeCategoryCommand(); - break; + return createCategoryCommand(separatedKeywordAndDescription); default: - System.out.println(INVALID_INPUT); - break; + throw new InvalidCommandException(INVALID_INPUT); } } - private void executeByeCommand() { - ByeCommand byeCommand = new ByeCommand(); + private Command createByeCommand() { + return new ByeCommand(); } - private void executeViewCommand() { + private Command createViewCommand(String[] separatedKeywordAndDescription) { if (separatedKeywordAndDescription.length == 1) { - new ViewCommand(); + return new ViewCommand(); } else { - new ViewCommand(separatedKeywordAndDescription[1]); + return new ViewCommand(separatedKeywordAndDescription[1]); } } - private void executeDeleteCommand() { + private Command createDeleteCommand(String[] separatedKeywordAndDescription) throws Exception { if (separatedKeywordAndDescription[1].startsWith("c/")) { try { String afterCategorySpecifier = separatedKeywordAndDescription[1].substring(2); @@ -87,24 +54,22 @@ private void executeDeleteCommand() { if (matcher.find()) { String categoryName = matcher.group(1); String eventName = matcher.group(2); - new DeleteCommand(categoryName, eventName); + return new DeleteCommand(categoryName, eventName); } else { System.out.println(afterCategorySpecifier); - new DeleteCommand(afterCategorySpecifier); + return new DeleteCommand(afterCategorySpecifier); } } catch (IndexOutOfBoundsException e) { - System.out.println(DELETE_FORMAT); - System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + throw new InvalidCommandException(DELETE_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } catch (Exception e) { - System.out.println(SUBTLE_BUG_MESSAGE); + throw new InvalidCommandException(SUBTLE_BUG_MESSAGE); } } else { - System.out.println(DELETE_FORMAT); - System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + throw new InvalidCommandException(DELETE_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } } - private void executeEventCommand() { + private Command createEventCommand(String[] separatedKeywordAndDescription) throws InvalidCommandException { Pattern pattern = Pattern.compile(EVENT_REGEX); try { Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); @@ -112,26 +77,24 @@ private void executeEventCommand() { String eventName = matcher.group(1); String budgetNumber = matcher.group(2); String expenseNumber = matcher.group(3); - new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); + return new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); } else { - System.out.println(EVENT_FORMAT); - System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + throw new InvalidCommandException(EVENT_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } } catch (IndexOutOfBoundsException e) { - System.out.println(EVENT_EMPTY); + throw new InvalidCommandException(EVENT_EMPTY); } catch (NumberFormatException e) { - System.out.println(REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER); + throw new InvalidCommandException(REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER); } catch (Exception e) { - System.out.println(SUBTLE_BUG_MESSAGE); + throw new InvalidCommandException(SUBTLE_BUG_MESSAGE); } } - private void executeCategoryCommand() { + private Command createCategoryCommand(String[] separatedKeywordAndDescription) throws InvalidCommandException { try { - new CategoryCommand(separatedKeywordAndDescription[1]); + return new CategoryCommand(separatedKeywordAndDescription[1]); } catch (IndexOutOfBoundsException e) { - System.out.println(CATEGORY_EMPTY); + throw new InvalidCommandException(CATEGORY_EMPTY); } } - } diff --git a/src/main/java/seedu/moneymind/Command/ViewCommand.java b/src/main/java/seedu/moneymind/Command/ViewCommand.java index f717bcb82b..1ee29c66f5 100644 --- a/src/main/java/seedu/moneymind/Command/ViewCommand.java +++ b/src/main/java/seedu/moneymind/Command/ViewCommand.java @@ -1,13 +1,20 @@ -package seedu.moneymind; +package seedu.moneymind.Command; + +import seedu.moneymind.Category; +import seedu.moneymind.CategoryList; +import seedu.moneymind.Event; +import seedu.moneymind.Ui; /** * ViewCommand class to view the categories and events. */ -public class ViewCommand { +public class ViewCommand implements Command { public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; public static final String DOT = "."; private String categoryName; + private final boolean isCategorySpecified; + /** * Constructs a new ViewCommand object and views the category. * @@ -15,17 +22,20 @@ public class ViewCommand { */ public ViewCommand(String categoryName) { this.categoryName = categoryName; - viewCategory(); + this.isCategorySpecified = true; } /** * Constructs a new ViewCommand object and views all the categories. */ public ViewCommand() { - viewAll(); + this.isCategorySpecified = false; } - private void viewCategory() { + /** + * Views a single category. + */ + private void viewOne() { if (CategoryCommand.categoryMap.get(categoryName) == null) { System.out.println(NO_CATEGORY_MESSAGE); return; @@ -44,10 +54,23 @@ private void viewAll() { System.out.println(count + DOT + category.getName()); count++; // print all the events in the category - for (Event event : category.events) { + for (Event event : category.getEvents()) { System.out.println(event.toString()); } } } + @Override + public void execute(Ui ui) { + if (isCategorySpecified) { + viewOne(); + } else { + viewAll(); + } + } + + @Override + public boolean isExit() { + return false; + } } diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index 99e0cbc482..d23f5b4dc2 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -1,13 +1,23 @@ package seedu.moneymind; +import seedu.moneymind.Command.Command; +import seedu.moneymind.Command.InvalidCommandException; +import seedu.moneymind.Command.Parser; + +import java.util.Scanner; + public class Moneymind { - private Ui ui; + private Parser parser; private Storage storage; + private Ui ui; + private Scanner in; public Moneymind() { - this.ui = new Ui(); + this.parser = new Parser(); // this line crashes the app currently, so it is commented out // this.storage = new Storage(); + this.ui = new Ui(); + this.in = new Scanner(System.in); } public void run() { @@ -15,13 +25,15 @@ public void run() { boolean isExit = false; while (!isExit) { try { - Command command = ui.processNextCommand(); + Command command = parser.parseNextCommand(in.nextLine()); if (command.isExit()) { ui.goodbye(); isExit = true; } else { command.execute(ui); // should also accept storage object as parameter } + } catch (InvalidCommandException e) { + e.showErrorMessage(); } catch (Exception e) { ui.error(e); } diff --git a/src/main/java/seedu/moneymind/Strings.java b/src/main/java/seedu/moneymind/Strings.java index 2d0c77cada..91b1517dae 100644 --- a/src/main/java/seedu/moneymind/Strings.java +++ b/src/main/java/seedu/moneymind/Strings.java @@ -1,2 +1,29 @@ -package seedu.moneymind;public class Strings { +package seedu.moneymind; + +public class Strings { + public static final String BYE_MESSAGE = "Bye. Hope to see you again soon!"; + public static final String HORIZONTAL_LINE = "____________________________________________________________"; + public static final String WHITE_SPACE = " "; + public static final String BYE = "bye"; + public static final String VIEW = "view"; + public static final String DELETE = "delete"; + public static final String EVENT = "event"; + public static final String CATEGORY = "category"; + public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; + public static final String DELETE_REGEX = "c/(.+) e/(.+)?"; + public static final String CATEGORY_ADDED_MESSAGE = "Category name: "; + public static final String EVENT_ADDED_MESSAGE = "Event name: "; + public static final String DELETE_FORMAT = "Please following the correct format: " + + "delete c/ e/"; + public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + + "inside the brackets empty!"; + public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; + public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; + public static final String EVENT_REGEX = "(.+) b/(\\d+) e/(\\d+)?"; + public static final String EVENT_FORMAT = "Please following the correct format: " + + "event b/ e/"; + public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; + public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = + "☹ OOPS!!! The budget and expense must be a number."; + public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; } diff --git a/src/main/java/seedu/moneymind/Ui.java b/src/main/java/seedu/moneymind/Ui.java index 8c15145998..ee8635f24f 100644 --- a/src/main/java/seedu/moneymind/Ui.java +++ b/src/main/java/seedu/moneymind/Ui.java @@ -1,6 +1,7 @@ package seedu.moneymind; -import java.util.Scanner; +import static seedu.moneymind.Strings.BYE_MESSAGE; +import static seedu.moneymind.Strings.HORIZONTAL_LINE; public class Ui { private static final String LINE = "____________________________________________________________\n"; @@ -11,17 +12,6 @@ public class Ui { private static final String ERROR = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; private static final String LIST = "Here are the events in your list:"; - Scanner in; - - public Ui() { - this.in = new Scanner(System.in); - } - - public Command processNextCommand() throws InvalidCommandException { - String input = in.nextLine(); - return new Command(input); - } - public void greet() { System.out.println(GREETING); } @@ -31,7 +21,8 @@ public void requestName() { } public void goodbye() { - System.out.println(GOODBYE); + System.out.println(BYE_MESSAGE); + System.out.println(HORIZONTAL_LINE); } public void error(Exception e) { diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index f92cfae180..b17cde64dc 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -1,10 +1,10 @@ package seedu.moneymind; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintStream; +import java.io.*; import org.junit.jupiter.api.Test; +import seedu.moneymind.Command.CategoryCommand; +import seedu.moneymind.Command.Command; +import seedu.moneymind.Command.Parser; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -33,8 +33,8 @@ void addCategory_oneCategory_expectThreeCategoryInCategoryList() { setup(); String input = "category travel"; executeInput(input); - assertTrue(CategoryList.categories.size() == 3); - assertTrue(CategoryList.categories.get(2).getName().equals("travel")); + assertEquals(3, CategoryList.categories.size()); + assertEquals("travel", CategoryList.categories.get(2).getName()); clear(); } @@ -46,9 +46,9 @@ void addEvent_oneFoodEvent_expectThreeEventsInFoodCategory() { InputStream in = new ByteArrayInputStream(categoryIndex.getBytes()); System.setIn(in); executeInput(input); - assertTrue(food.events.get(2).getDescription().equals("banana")); - assertTrue(food.events.get(2).getBudget() == 20); - assertTrue(food.events.get(2).getExpense() == 10); + assertEquals("banana", food.events.get(2).getDescription()); + assertEquals(20, food.events.get(2).getBudget()); + assertEquals(10, food.events.get(2).getExpense()); clear(); } @@ -57,8 +57,8 @@ void deleteWholeCategory_oneCategory_expectOneCategoryInList() { setup(); String input = "delete c/food"; executeInput(input); - assertTrue(CategoryList.categories.size() == 1); - assertTrue(CategoryList.categories.get(0).getName().equals("book")); + assertEquals(1, CategoryList.categories.size()); + assertEquals("book", CategoryList.categories.get(0).getName()); clear(); } @@ -67,8 +67,8 @@ void deleteEvent_oneBookEvent_expectOneEventInBookCategory() { setup(); String input = "delete c/book e/Harry Potter"; executeInput(input); - assertTrue(book.events.size() == 1); - assertTrue(book.events.get(0).getDescription().equals("Lord of the Rings")); + assertEquals(1, book.events.size()); + assertEquals("Lord of the Rings", book.events.get(0).getDescription()); clear(); } @@ -80,8 +80,14 @@ void viewAll_expectEverythingToBePrintedOut() { // Get help from chatGPT for the next 2 lines ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); System.setOut(new PrintStream(outputStream)); - parser.splitKeywordAndDescription(input); - parser.executeUserInput(); + + try { + Command command = parser.parseNextCommand(input); + command.execute(new Ui()); + } catch (Exception e) { + System.exit(-1); + } + String actual = outputStream.toString(); String expected = "1.food" + System.lineSeparator() + "salad [budget]100 [expense]50" + System.lineSeparator() @@ -101,8 +107,14 @@ void viewCategory_expectCategoryToBePrintedOut() { // Get help from chatGPT for the next 2 lines ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); System.setOut(new PrintStream(outputStream)); - parser.splitKeywordAndDescription(input); - parser.executeUserInput(); + + try { + Command command = parser.parseNextCommand(input); + command.execute(new Ui()); + } catch (Exception e) { + System.exit(-1); + } + String actual = outputStream.toString(); String expected = "1. salad [budget]100 [expense]50" + System.lineSeparator() + "2. pizza [budget]200 [expense]100" + System.lineSeparator(); @@ -115,8 +127,12 @@ private static void executeInput(String input) { // Get help from chatGPT for the next 2 lines ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); System.setOut(new PrintStream(outputStream)); - parser.splitKeywordAndDescription(input); - parser.executeUserInput(); + try { + Command command = parser.parseNextCommand(input); + command.execute(new Ui()); + } catch (Exception e) { + System.exit(-1); + } } /** From 6abf3dd96b89470ec0b394b234ba5f799ecc64ae Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 14 Mar 2023 14:27:35 +0800 Subject: [PATCH 045/210] Fix imports --- .../seedu/moneymind/Command/EventCommand.java | 6 +++++- .../java/seedu/moneymind/Command/Parser.java | 18 ++++++++++++++++-- text-ui-test/EXPECTED.TXT | 3 ++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/moneymind/Command/EventCommand.java b/src/main/java/seedu/moneymind/Command/EventCommand.java index d356bf87c4..29fa9d3e82 100644 --- a/src/main/java/seedu/moneymind/Command/EventCommand.java +++ b/src/main/java/seedu/moneymind/Command/EventCommand.java @@ -1,6 +1,10 @@ package seedu.moneymind.Command; -import seedu.moneymind.*; +import seedu.moneymind.Category; +import seedu.moneymind.CategoryList; +import seedu.moneymind.Event; +import seedu.moneymind.Ui; +import seedu.moneymind.InvalidCategoryNumberException; import java.util.Scanner; diff --git a/src/main/java/seedu/moneymind/Command/Parser.java b/src/main/java/seedu/moneymind/Command/Parser.java index 25d12216f2..a02820dae2 100644 --- a/src/main/java/seedu/moneymind/Command/Parser.java +++ b/src/main/java/seedu/moneymind/Command/Parser.java @@ -1,10 +1,24 @@ package seedu.moneymind.Command; -import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static seedu.moneymind.Strings.*; + +import static seedu.moneymind.Strings.WHITE_SPACE; +import static seedu.moneymind.Strings.BYE; +import static seedu.moneymind.Strings.VIEW; +import static seedu.moneymind.Strings.DELETE; +import static seedu.moneymind.Strings.EVENT; +import static seedu.moneymind.Strings.CATEGORY; +import static seedu.moneymind.Strings.INVALID_INPUT; +import static seedu.moneymind.Strings.DELETE_FORMAT; +import static seedu.moneymind.Strings.REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY; +import static seedu.moneymind.Strings.SUBTLE_BUG_MESSAGE; +import static seedu.moneymind.Strings.EVENT_REGEX; +import static seedu.moneymind.Strings.EVENT_FORMAT; +import static seedu.moneymind.Strings.EVENT_EMPTY; +import static seedu.moneymind.Strings.REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER; +import static seedu.moneymind.Strings.CATEGORY_EMPTY; /** * A class to parse the user input. diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index d1e320a6f0..9c2a722a2c 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,5 +1,6 @@ Hello from [LOGO_PLACEHOLDER] How may I help you? -test +☹ OOPS!!! I'm sorry, but I don't know what that means :-( Bye. Hope to see you again soon! +____________________________________________________________ From c5c4994799c786f0e558989596705eb9d91882a5 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 14 Mar 2023 14:30:49 +0800 Subject: [PATCH 046/210] Fix imports for CommandTest --- src/test/java/seedu/moneymind/CommandTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index b17cde64dc..ae2fbc9525 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -1,13 +1,16 @@ package seedu.moneymind; -import java.io.*; import org.junit.jupiter.api.Test; import seedu.moneymind.Command.CategoryCommand; import seedu.moneymind.Command.Command; import seedu.moneymind.Command.Parser; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; public class CommandTest { Category food = new Category("food"); From 1cdd0c76bde16ce25b197f906698733317f41371 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 14:45:24 +0800 Subject: [PATCH 047/210] add save and load features to main run class --- EventList.txt | 6 ++++ src/main/java/seedu/moneymind/Moneymind.java | 6 ++-- .../java/seedu/moneymind/storage/Storage.java | 15 ++++++++++ .../java/seedu/moneymind/StorageTest.java | 29 +++++++++++++++---- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/EventList.txt b/EventList.txt index e69de29bb2..41c132a3ea 100644 --- a/EventList.txt +++ b/EventList.txt @@ -0,0 +1,6 @@ +&&new_category&&test cat +&&next_detail&&test1&&next_detail&&1234&&next_detail&&5678 +&&next_detail&&test2&&next_detail&&9876&&next_detail&&5432 +&&new_category&&test dog +&&next_detail&&test3&&next_detail&&1234&&next_detail&&5678 +&&next_detail&&test4&&next_detail&&9876&&next_detail&&5432 diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index 4d76669c4e..4f942adc21 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -8,13 +8,14 @@ public class Moneymind { public Moneymind() { this.ui = new Ui(); - // this line crashes the app currently, so it is commented out - // this.storage = new Storage(); + // TODO: verify storage is working + this.storage = new Storage(); } public void run() { ui.greet(); boolean isExit = false; + storage.load(); while (!isExit) { try { Command command = ui.processNextCommand(); @@ -28,6 +29,7 @@ public void run() { ui.error(e); } } + storage.save(); } public static void main(String[] args) { diff --git a/src/main/java/seedu/moneymind/storage/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java index c1c0a32d06..97d78ac76e 100644 --- a/src/main/java/seedu/moneymind/storage/Storage.java +++ b/src/main/java/seedu/moneymind/storage/Storage.java @@ -6,6 +6,7 @@ import java.util.Scanner; import seedu.moneymind.Category; +import seedu.moneymind.CategoryList; import seedu.moneymind.StringToCategory; import java.io.FileWriter; @@ -80,4 +81,18 @@ public ArrayList loadFromFile() { ArrayList savedList = StringToCategory.stringToCategory(fileString); return savedList; } + + /** + * Saves the current list of Category to EventList.txt file + */ + public void save() { + saveToFile(CategoryList.categories); + } + + /** + * Loads the list of Category from EventList.txt file + */ + public void load() { + CategoryList.categories = loadFromFile(); + } } diff --git a/src/test/java/seedu/moneymind/StorageTest.java b/src/test/java/seedu/moneymind/StorageTest.java index 28f5818351..500d9bf079 100644 --- a/src/test/java/seedu/moneymind/StorageTest.java +++ b/src/test/java/seedu/moneymind/StorageTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test; +import seedu.moneymind.storage.FormatToTxt; import seedu.moneymind.storage.Storage; public class StorageTest { @@ -31,8 +32,15 @@ public void setupFile_null_noExceptionThrown() { public void saveToFile_descInput_exptOutcome() { Storage storage = new Storage(); ArrayList list = new ArrayList<>(); - // TODO: Add a test case for saving a list of events - // list.add(new Event("test", 1234, 5678)); + + // add test data + list.add(new Category("test cat")); + list.get(0).addEvent(new Event("test1", 1234, 5678)); + list.get(0).addEvent(new Event("test2", 9876, 5432)); + list.add(new Category("test dog")); + list.get(1).addEvent(new Event("test3", 1234, 5678)); + list.get(1).addEvent(new Event("test4", 9876, 5432)); + assertDoesNotThrow(() -> { storage.saveToFile(list); }); @@ -63,12 +71,21 @@ public void saveAndLoadFromFile_descInput_exptOutcome() { try { Storage storage = new Storage(); ArrayList list = new ArrayList<>(); - // TODO: Add a test case for saving a list of events - // list.add(new Event("test", 1234, 5678)); - // list.add(new Event("test2", 9876, 5432)); + + // add test data + list.add(new Category("test_cat")); + list.get(0).addEvent(new Event("test1", 1234, 5678)); + list.get(0).addEvent(new Event("test2", 9876, 5432)); + list.add(new Category("test_dog")); + list.get(1).addEvent(new Event("test3", 1122, 3344)); + list.get(1).addEvent(new Event("test4", 5566, 7788)); + storage.saveToFile(list); ArrayList list2 = storage.loadFromFile(); - System.out.println(list2); + + + // check if data is the same + assertTrue(FormatToTxt.formatToTxt(list).equals(FormatToTxt.formatToTxt(list2))); } catch (Exception e) { assertTrue(false, e.getMessage()); } From c33380170a961e0915b2431d0ab3e31b29535fab Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 14:48:58 +0800 Subject: [PATCH 048/210] add EventList.txt to .gitignore --- .gitignore | 1 + EventList.txt | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 EventList.txt diff --git a/.gitignore b/.gitignore index 2873e189e1..deda43cc32 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ bin/ /text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT +EventList.txt \ No newline at end of file diff --git a/EventList.txt b/EventList.txt deleted file mode 100644 index 41c132a3ea..0000000000 --- a/EventList.txt +++ /dev/null @@ -1,6 +0,0 @@ -&&new_category&&test cat -&&next_detail&&test1&&next_detail&&1234&&next_detail&&5678 -&&next_detail&&test2&&next_detail&&9876&&next_detail&&5432 -&&new_category&&test dog -&&next_detail&&test3&&next_detail&&1234&&next_detail&&5678 -&&next_detail&&test4&&next_detail&&9876&&next_detail&&5432 From 2921a4c31b43f9bbe11a23a119a5e649a6b17347 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 16:54:49 +0800 Subject: [PATCH 049/210] resolve merge conflicts --- src/main/java/seedu/moneymind/Parser.java | 145 ---------------------- 1 file changed, 145 deletions(-) delete mode 100644 src/main/java/seedu/moneymind/Parser.java diff --git a/src/main/java/seedu/moneymind/Parser.java b/src/main/java/seedu/moneymind/Parser.java deleted file mode 100644 index 9e44d18825..0000000000 --- a/src/main/java/seedu/moneymind/Parser.java +++ /dev/null @@ -1,145 +0,0 @@ -package seedu.moneymind; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A class to parse the user input. - */ -public class Parser { - public static final String WHITE_SPACE = " "; - public static final String BYE = "bye"; - public static final String VIEW = "view"; - public static final String DELETE = "delete"; - public static final String EVENT = "event"; - public static final String CATEGORY = "category"; - public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; - public static final String DELETE_FORMAT = "Please following the correct format: " + - "delete c/ e/"; - public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + - "inside the brackets empty!"; - public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; - public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; - public static final String EVENT_REGEX = "(.+) b/(-?\\d+) e/(-?\\d+)"; - public static final String EVENT_FORMAT = "Please following the correct format: " + - "event b/ e/"; - public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; - public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = - "☹ OOPS!!! The budget and expense must be a number."; - public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; - public static final String DELETE_REGEX = "^c/(?=\\S)(.*?)(?:\\s+e/(.*))?\\s*$"; - public static final String NULL_INPUT_ASSERTION = "Input cannot be null"; - public static final String NULL_DESCRIPTION = "Separated keyword and description cannot be null"; - public static final String REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER = - "Please enter a positive number for budget and expense"; - private String[] separatedKeywordAndDescription; - private String keyword; - - /** - * Splits the user input into keyword and description. - */ - public void splitKeywordAndDescription(String input) { - assert input != null : NULL_INPUT_ASSERTION; - separatedKeywordAndDescription = input.split(WHITE_SPACE, 2); - keyword = separatedKeywordAndDescription[0]; - } - - /** - * Executes the user input. - */ - public void executeUserInput() { - assert separatedKeywordAndDescription != null : NULL_DESCRIPTION; - switch (keyword) { - case BYE: - executeByeCommand(); - break; - case VIEW: - executeViewCommand(); - break; - case DELETE: - executeDeleteCommand(); - break; - case EVENT: - executeEventCommand(); - break; - case CATEGORY: - executeCategoryCommand(); - break; - default: - System.out.println(INVALID_INPUT); - break; - } - } - - private void executeByeCommand() { - new ByeCommand(); - } - - private void executeViewCommand() { - if (separatedKeywordAndDescription.length == 1) { - new ViewCommand(); - } else { - new ViewCommand(separatedKeywordAndDescription[1]); - } - } - - private void executeDeleteCommand() { - Pattern pattern = Pattern.compile(DELETE_REGEX); - if (separatedKeywordAndDescription.length == 1) { - System.out.println(EMPTY_DELETION); - return; - } - Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); - if (matcher.find()) { - String categoryName = matcher.group(1); - String eventName = matcher.group(2); - if (eventName == null) { - new DeleteCommand(categoryName); - return; - } - new DeleteCommand(categoryName, eventName); - } else { - System.out.println(DELETE_FORMAT); - System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); - } - } - - private void executeEventCommand() { - Pattern pattern = Pattern.compile(EVENT_REGEX); - try { - Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); - if (matcher.find()) { - String eventName = matcher.group(1); - String budgetNumber = matcher.group(2); - String expenseNumber = matcher.group(3); - checkNegativeBudgetAndExpense(Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); - new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); - } else { - System.out.println(EVENT_FORMAT); - System.out.println(REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); - } - } catch (IndexOutOfBoundsException error) { - System.out.println(EVENT_EMPTY); - } catch (NumberFormatException error) { - System.out.println(REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER); - } catch (NegativeNumberException error) { - System.out.println(REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER); - } catch (Exception error) { - System.out.println(SUBTLE_BUG_MESSAGE); - } - } - - private void checkNegativeBudgetAndExpense(int budget, int expense) throws NegativeNumberException { - if (budget < 0 || expense < 0) { - throw new NegativeNumberException(); - } - } - - private void executeCategoryCommand() { - try { - new CategoryCommand(separatedKeywordAndDescription[1]); - } catch (IndexOutOfBoundsException error) { - System.out.println(CATEGORY_EMPTY); - } - } - -} From 594bb2de18af4d3c2c607bec207b7f0d31fba868 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 17:03:58 +0800 Subject: [PATCH 050/210] improve code quality for stylesCheck --- src/main/java/seedu/moneymind/Command/ByeCommand.java | 2 +- .../java/seedu/moneymind/Command/CategoryCommand.java | 2 +- src/main/java/seedu/moneymind/Command/Command.java | 2 +- src/main/java/seedu/moneymind/Command/DeleteCommand.java | 2 +- src/main/java/seedu/moneymind/Command/EventCommand.java | 2 +- .../seedu/moneymind/Command/InvalidCommandException.java | 2 +- src/main/java/seedu/moneymind/Command/Parser.java | 2 +- src/main/java/seedu/moneymind/Command/ViewCommand.java | 2 +- src/main/java/seedu/moneymind/Moneymind.java | 8 ++++---- src/test/java/seedu/moneymind/CommandTest.java | 7 ++++--- 10 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/java/seedu/moneymind/Command/ByeCommand.java b/src/main/java/seedu/moneymind/Command/ByeCommand.java index b3bca0019e..48dbeec6a6 100644 --- a/src/main/java/seedu/moneymind/Command/ByeCommand.java +++ b/src/main/java/seedu/moneymind/Command/ByeCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; import seedu.moneymind.Ui; diff --git a/src/main/java/seedu/moneymind/Command/CategoryCommand.java b/src/main/java/seedu/moneymind/Command/CategoryCommand.java index bb55a165f7..5e0d8aef2b 100644 --- a/src/main/java/seedu/moneymind/Command/CategoryCommand.java +++ b/src/main/java/seedu/moneymind/Command/CategoryCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/Command/Command.java b/src/main/java/seedu/moneymind/Command/Command.java index 2cd73e14ac..cb089e0dc1 100644 --- a/src/main/java/seedu/moneymind/Command/Command.java +++ b/src/main/java/seedu/moneymind/Command/Command.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; import seedu.moneymind.Ui; diff --git a/src/main/java/seedu/moneymind/Command/DeleteCommand.java b/src/main/java/seedu/moneymind/Command/DeleteCommand.java index 9cd8de16d3..f3a2dbdf68 100644 --- a/src/main/java/seedu/moneymind/Command/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/Command/DeleteCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/Command/EventCommand.java b/src/main/java/seedu/moneymind/Command/EventCommand.java index 702284db8e..fbe983edc2 100644 --- a/src/main/java/seedu/moneymind/Command/EventCommand.java +++ b/src/main/java/seedu/moneymind/Command/EventCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/Command/InvalidCommandException.java b/src/main/java/seedu/moneymind/Command/InvalidCommandException.java index eb540e06ab..874445d74f 100644 --- a/src/main/java/seedu/moneymind/Command/InvalidCommandException.java +++ b/src/main/java/seedu/moneymind/Command/InvalidCommandException.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; public class InvalidCommandException extends Exception { private String errorMessage; diff --git a/src/main/java/seedu/moneymind/Command/Parser.java b/src/main/java/seedu/moneymind/Command/Parser.java index 501abaf04e..d3f8907d3e 100644 --- a/src/main/java/seedu/moneymind/Command/Parser.java +++ b/src/main/java/seedu/moneymind/Command/Parser.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/seedu/moneymind/Command/ViewCommand.java b/src/main/java/seedu/moneymind/Command/ViewCommand.java index 08b6951358..6403834f25 100644 --- a/src/main/java/seedu/moneymind/Command/ViewCommand.java +++ b/src/main/java/seedu/moneymind/Command/ViewCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.Command; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index d23f5b4dc2..4a8e8a44e8 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -1,11 +1,11 @@ package seedu.moneymind; -import seedu.moneymind.Command.Command; -import seedu.moneymind.Command.InvalidCommandException; -import seedu.moneymind.Command.Parser; - import java.util.Scanner; +import seedu.moneymind.command.Command; +import seedu.moneymind.command.InvalidCommandException; +import seedu.moneymind.command.Parser; + public class Moneymind { private Parser parser; private Storage storage; diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index ae2fbc9525..55dfd61a24 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -1,9 +1,10 @@ package seedu.moneymind; import org.junit.jupiter.api.Test; -import seedu.moneymind.Command.CategoryCommand; -import seedu.moneymind.Command.Command; -import seedu.moneymind.Command.Parser; + +import seedu.moneymind.command.CategoryCommand; +import seedu.moneymind.command.Command; +import seedu.moneymind.command.Parser; import java.io.ByteArrayInputStream; import java.io.InputStream; From e6f2a789de41bac2812e6d6cfb45a3275a5658a4 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 21:57:37 +0800 Subject: [PATCH 051/210] add classes to update CategoryCommand.categoryMap --- .../seedu/moneymind/CategoryToString.java | 17 +++---- .../seedu/moneymind/StringToCategory.java | 15 ++++--- src/main/java/seedu/moneymind/Strings.java | 4 ++ .../storage/CategoryMapToString.java | 24 ++++++++++ .../moneymind/storage/LoadToCategoryMap.java | 23 ++++++++++ .../java/seedu/moneymind/storage/Storage.java | 13 ++++-- .../java/seedu/moneymind/StorageTest.java | 45 +++++++++++-------- 7 files changed, 102 insertions(+), 39 deletions(-) create mode 100644 src/main/java/seedu/moneymind/storage/CategoryMapToString.java create mode 100644 src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java diff --git a/src/main/java/seedu/moneymind/CategoryToString.java b/src/main/java/seedu/moneymind/CategoryToString.java index baf80c4c8b..83267851a6 100644 --- a/src/main/java/seedu/moneymind/CategoryToString.java +++ b/src/main/java/seedu/moneymind/CategoryToString.java @@ -1,16 +1,13 @@ package seedu.moneymind; +import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; +import static seedu.moneymind.Strings.NEW_LINE; +import static seedu.moneymind.Strings.STORAGE_CATEGORY_NAME; + /** * Converts a Category object to a String. */ public class CategoryToString { - // String symbol separating each variable of an Event object - protected static final String NEXT_VARIABLE = "&&next_detail&&"; - // Creates a new line - protected static final String NEW_LINE = System.lineSeparator(); - // Save file symbol for a new category - protected static final String CATEGORY_NAME = "&&new_category&&"; - /** * Converts a Category object to a String. * @@ -22,10 +19,10 @@ public static String categoryToString(Category category) { String output = ""; // Adds the category name to the output - output += CATEGORY_NAME + category.getName() + NEW_LINE; + output += STORAGE_CATEGORY_NAME + category.getName() + NEW_LINE; for (Event event : category.events) { - output += NEXT_VARIABLE + event.getDescription() + NEXT_VARIABLE + event.getBudget() - + NEXT_VARIABLE + event.getExpense() + NEW_LINE; + output += STORAGE_NEXT_VARIABLE + event.getDescription() + STORAGE_NEXT_VARIABLE + event.getBudget() + + STORAGE_NEXT_VARIABLE + event.getExpense() + NEW_LINE; } return output; } diff --git a/src/main/java/seedu/moneymind/StringToCategory.java b/src/main/java/seedu/moneymind/StringToCategory.java index 651f4c5029..21d1996f73 100644 --- a/src/main/java/seedu/moneymind/StringToCategory.java +++ b/src/main/java/seedu/moneymind/StringToCategory.java @@ -2,10 +2,13 @@ import java.util.ArrayList; +import static seedu.moneymind.Strings.STORAGE_CATEGORY_NAME; +import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; + /** * Converts a String from file.txt to an ArrayList of Category objects. */ -public class StringToCategory extends CategoryToString{ +public class StringToCategory { /** * Converts a String from file.txt to an ArrayList of Category objects. * @@ -20,13 +23,13 @@ public static ArrayList stringToCategory(String inputFromFile) { String[] lines = inputFromFile.split(System.lineSeparator()); for (String string : lines) { // Creates a new Category object if the line is a new category, ignoring the save file symbol - if (string.startsWith(CATEGORY_NAME)) { - categories.add(new Category(string.substring(CATEGORY_NAME.length()))); - } else if (string.startsWith(NEXT_VARIABLE)) { + if (string.startsWith(STORAGE_CATEGORY_NAME)) { + categories.add(new Category(string.substring(STORAGE_CATEGORY_NAME.length()))); + } else if (string.startsWith(STORAGE_NEXT_VARIABLE)) { // Remove the first next variable symbol - string = string.substring(NEXT_VARIABLE.length()); + string = string.substring(STORAGE_NEXT_VARIABLE.length()); // Splits the line into 3 parts, each part being a variable of an Event object - String[] eventDetails = string.split(NEXT_VARIABLE); + String[] eventDetails = string.split(STORAGE_NEXT_VARIABLE); // Creates a new Event object Event event = new Event(eventDetails[0], Integer.parseInt(eventDetails[1]), Integer.parseInt(eventDetails[2])); diff --git a/src/main/java/seedu/moneymind/Strings.java b/src/main/java/seedu/moneymind/Strings.java index f71618db10..38d7127236 100644 --- a/src/main/java/seedu/moneymind/Strings.java +++ b/src/main/java/seedu/moneymind/Strings.java @@ -28,4 +28,8 @@ public class Strings { public static final String NULL_DESCRIPTION = "Separated keyword and description cannot be null"; public static final String REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER = "Please enter a positive number for budget and expense"; + public static final String STORAGE_NEXT_VARIABLE = "&&next_detail&&"; + public static final String NEW_LINE = System.lineSeparator(); + public static final String STORAGE_CATEGORY_NAME = "&&new_category&&"; + public static final String STORAGE_CATEGORY_MAP = "&&category_map&&"; } diff --git a/src/main/java/seedu/moneymind/storage/CategoryMapToString.java b/src/main/java/seedu/moneymind/storage/CategoryMapToString.java new file mode 100644 index 0000000000..903fff2af9 --- /dev/null +++ b/src/main/java/seedu/moneymind/storage/CategoryMapToString.java @@ -0,0 +1,24 @@ +package seedu.moneymind.storage; + +import static seedu.moneymind.Strings.STORAGE_CATEGORY_MAP; +import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; +import static seedu.moneymind.Strings.NEW_LINE; +import static seedu.moneymind.command.CategoryCommand.categoryMap; + +/** + * Converts categoryMap to a String. + */ +public class CategoryMapToString { + /** + * Converts categoryMap to a String. + * + * @return String of categoryMap + */ + public static String categoryMapToString() { + String output = STORAGE_CATEGORY_MAP + NEW_LINE; + for (String key : categoryMap.keySet()) { + output += STORAGE_NEXT_VARIABLE + key + STORAGE_NEXT_VARIABLE + categoryMap.get(key) + NEW_LINE; + } + return output; + } +} diff --git a/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java b/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java new file mode 100644 index 0000000000..7a1b4c91ed --- /dev/null +++ b/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java @@ -0,0 +1,23 @@ +package seedu.moneymind.storage; + +import java.util.HashMap; + +import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; +import static seedu.moneymind.Strings.NEW_LINE; +import static seedu.moneymind.command.CategoryCommand.categoryMap; + +/** + * Converts a String to a HashMap. + */ +public class LoadToCategoryMap { + public static void loadToCategoryMap(String input) { + // hashmap to store the category name and its index in the category list + HashMap loadedMap = new HashMap(); + String[] loadedMapEntries = input.split(NEW_LINE); + for (String entry : loadedMapEntries) { + String[] entryComponents = entry.split(STORAGE_NEXT_VARIABLE); + loadedMap.put(entryComponents[1], Integer.parseInt(entryComponents[2])); + } + categoryMap = loadedMap; + } +} diff --git a/src/main/java/seedu/moneymind/storage/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java index 97d78ac76e..9f506d15a5 100644 --- a/src/main/java/seedu/moneymind/storage/Storage.java +++ b/src/main/java/seedu/moneymind/storage/Storage.java @@ -4,13 +4,15 @@ import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Scanner; +import java.io.FileWriter; +import java.io.IOException; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; import seedu.moneymind.StringToCategory; -import java.io.FileWriter; -import java.io.IOException; +import static seedu.moneymind.Strings.STORAGE_CATEGORY_MAP; +import static seedu.moneymind.Strings.NEW_LINE; /** * Storage class to save and load data from a file @@ -46,7 +48,7 @@ private static void setupFile() { * @param list ArrayList of Category */ public void saveToFile(ArrayList list) { - String writeToFile = FormatToTxt.formatToTxt(list); + String writeToFile = FormatToTxt.formatToTxt(list) + CategoryMapToString.categoryMapToString(); // write task list to text file try { @@ -77,8 +79,11 @@ public ArrayList loadFromFile() { } catch (FileNotFoundException e) { System.out.println("I cannot seem to access the saved tasks. Did you perhaps lock it away?"); } + // split fileString into 2 parts using STORAGE_CATEGORY_MAP + String[] splitString = fileString.split(STORAGE_CATEGORY_MAP + NEW_LINE); // convert fileString to ArrayList of Category - ArrayList savedList = StringToCategory.stringToCategory(fileString); + ArrayList savedList = StringToCategory.stringToCategory(splitString[0]); + LoadToCategoryMap.loadToCategoryMap(splitString[1]); return savedList; } diff --git a/src/test/java/seedu/moneymind/StorageTest.java b/src/test/java/seedu/moneymind/StorageTest.java index 500d9bf079..010f1a695d 100644 --- a/src/test/java/seedu/moneymind/StorageTest.java +++ b/src/test/java/seedu/moneymind/StorageTest.java @@ -4,13 +4,34 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; +import java.util.HashMap; import org.junit.jupiter.api.Test; +import seedu.moneymind.command.CategoryCommand; import seedu.moneymind.storage.FormatToTxt; import seedu.moneymind.storage.Storage; public class StorageTest { + private HashMap testCaseHashMap() { + HashMap map = new HashMap<>(); + map.put("test1", 1); + map.put("test2", 2); + map.put("test3", 3); + return map; + } + private ArrayList testCaseArrayList() { + ArrayList list = new ArrayList<>(); + list.add(new Category("test1")); + list.get(0).addEvent(new Event("event1", 1234, 5678)); + list.get(0).addEvent(new Event("event2", 9876, 5432)); + list.add(new Category("test2")); + list.get(1).addEvent(new Event("event3", 1122, 3344)); + list.get(1).addEvent(new Event("event4", 5566, 7788)); + list.add(new Category("test3")); + return list; + } + /** * Tests setupFile() method

* Expected outcome: No exception thrown @@ -32,14 +53,7 @@ public void setupFile_null_noExceptionThrown() { public void saveToFile_descInput_exptOutcome() { Storage storage = new Storage(); ArrayList list = new ArrayList<>(); - - // add test data - list.add(new Category("test cat")); - list.get(0).addEvent(new Event("test1", 1234, 5678)); - list.get(0).addEvent(new Event("test2", 9876, 5432)); - list.add(new Category("test dog")); - list.get(1).addEvent(new Event("test3", 1234, 5678)); - list.get(1).addEvent(new Event("test4", 9876, 5432)); + CategoryCommand.categoryMap = testCaseHashMap(); assertDoesNotThrow(() -> { storage.saveToFile(list); @@ -64,21 +78,14 @@ public void loadFromFile_null_noExceptionThrown() { /** * Tests save and load from file sequence

* Input: ArrayList of Events

- * Expected outcome: No exception thrown + * Expected outcome: Similar ArrayList of Events */ @Test - public void saveAndLoadFromFile_descInput_exptOutcome() { + public void saveAndLoadFromFile_testCaseArrayList_testCaseArrayList() { try { Storage storage = new Storage(); - ArrayList list = new ArrayList<>(); - - // add test data - list.add(new Category("test_cat")); - list.get(0).addEvent(new Event("test1", 1234, 5678)); - list.get(0).addEvent(new Event("test2", 9876, 5432)); - list.add(new Category("test_dog")); - list.get(1).addEvent(new Event("test3", 1122, 3344)); - list.get(1).addEvent(new Event("test4", 5566, 7788)); + ArrayList list = testCaseArrayList(); + CategoryCommand.categoryMap = testCaseHashMap(); storage.saveToFile(list); ArrayList list2 = storage.loadFromFile(); From 675dffa06782559f4abb0e3f09416a6f7d254e36 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 22:19:10 +0800 Subject: [PATCH 052/210] fix minor bugs --- src/main/java/seedu/moneymind/storage/Storage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/moneymind/storage/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java index 9f506d15a5..99dc730030 100644 --- a/src/main/java/seedu/moneymind/storage/Storage.java +++ b/src/main/java/seedu/moneymind/storage/Storage.java @@ -83,7 +83,9 @@ public ArrayList loadFromFile() { String[] splitString = fileString.split(STORAGE_CATEGORY_MAP + NEW_LINE); // convert fileString to ArrayList of Category ArrayList savedList = StringToCategory.stringToCategory(splitString[0]); - LoadToCategoryMap.loadToCategoryMap(splitString[1]); + if (splitString.length == 2) { + LoadToCategoryMap.loadToCategoryMap(splitString[1]); + } return savedList; } From 8e5a110109a99b6b8cea9b80e377f3034bfefdee Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 22:36:48 +0800 Subject: [PATCH 053/210] fix package name --- .../seedu/moneymind/{Command => tempCommand}/ByeCommand.java | 2 +- .../moneymind/{Command => tempCommand}/CategoryCommand.java | 2 +- .../java/seedu/moneymind/{Command => tempCommand}/Command.java | 2 +- .../seedu/moneymind/{Command => tempCommand}/DeleteCommand.java | 2 +- .../seedu/moneymind/{Command => tempCommand}/EventCommand.java | 2 +- .../{Command => tempCommand}/InvalidCommandException.java | 2 +- .../java/seedu/moneymind/{Command => tempCommand}/Parser.java | 2 +- .../seedu/moneymind/{Command => tempCommand}/ViewCommand.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/seedu/moneymind/{Command => tempCommand}/ByeCommand.java (88%) rename src/main/java/seedu/moneymind/{Command => tempCommand}/CategoryCommand.java (95%) rename src/main/java/seedu/moneymind/{Command => tempCommand}/Command.java (73%) rename src/main/java/seedu/moneymind/{Command => tempCommand}/DeleteCommand.java (98%) rename src/main/java/seedu/moneymind/{Command => tempCommand}/EventCommand.java (99%) rename src/main/java/seedu/moneymind/{Command => tempCommand}/InvalidCommandException.java (88%) rename src/main/java/seedu/moneymind/{Command => tempCommand}/Parser.java (99%) rename src/main/java/seedu/moneymind/{Command => tempCommand}/ViewCommand.java (98%) diff --git a/src/main/java/seedu/moneymind/Command/ByeCommand.java b/src/main/java/seedu/moneymind/tempCommand/ByeCommand.java similarity index 88% rename from src/main/java/seedu/moneymind/Command/ByeCommand.java rename to src/main/java/seedu/moneymind/tempCommand/ByeCommand.java index 48dbeec6a6..72bcd474df 100644 --- a/src/main/java/seedu/moneymind/Command/ByeCommand.java +++ b/src/main/java/seedu/moneymind/tempCommand/ByeCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; import seedu.moneymind.Ui; diff --git a/src/main/java/seedu/moneymind/Command/CategoryCommand.java b/src/main/java/seedu/moneymind/tempCommand/CategoryCommand.java similarity index 95% rename from src/main/java/seedu/moneymind/Command/CategoryCommand.java rename to src/main/java/seedu/moneymind/tempCommand/CategoryCommand.java index 5e0d8aef2b..ee71a97d88 100644 --- a/src/main/java/seedu/moneymind/Command/CategoryCommand.java +++ b/src/main/java/seedu/moneymind/tempCommand/CategoryCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/Command/Command.java b/src/main/java/seedu/moneymind/tempCommand/Command.java similarity index 73% rename from src/main/java/seedu/moneymind/Command/Command.java rename to src/main/java/seedu/moneymind/tempCommand/Command.java index cb089e0dc1..cf283ad46a 100644 --- a/src/main/java/seedu/moneymind/Command/Command.java +++ b/src/main/java/seedu/moneymind/tempCommand/Command.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; import seedu.moneymind.Ui; diff --git a/src/main/java/seedu/moneymind/Command/DeleteCommand.java b/src/main/java/seedu/moneymind/tempCommand/DeleteCommand.java similarity index 98% rename from src/main/java/seedu/moneymind/Command/DeleteCommand.java rename to src/main/java/seedu/moneymind/tempCommand/DeleteCommand.java index f3a2dbdf68..fcfae50c9d 100644 --- a/src/main/java/seedu/moneymind/Command/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/tempCommand/DeleteCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/Command/EventCommand.java b/src/main/java/seedu/moneymind/tempCommand/EventCommand.java similarity index 99% rename from src/main/java/seedu/moneymind/Command/EventCommand.java rename to src/main/java/seedu/moneymind/tempCommand/EventCommand.java index fbe983edc2..81d022fee1 100644 --- a/src/main/java/seedu/moneymind/Command/EventCommand.java +++ b/src/main/java/seedu/moneymind/tempCommand/EventCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/Command/InvalidCommandException.java b/src/main/java/seedu/moneymind/tempCommand/InvalidCommandException.java similarity index 88% rename from src/main/java/seedu/moneymind/Command/InvalidCommandException.java rename to src/main/java/seedu/moneymind/tempCommand/InvalidCommandException.java index 874445d74f..79ea90a464 100644 --- a/src/main/java/seedu/moneymind/Command/InvalidCommandException.java +++ b/src/main/java/seedu/moneymind/tempCommand/InvalidCommandException.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; public class InvalidCommandException extends Exception { private String errorMessage; diff --git a/src/main/java/seedu/moneymind/Command/Parser.java b/src/main/java/seedu/moneymind/tempCommand/Parser.java similarity index 99% rename from src/main/java/seedu/moneymind/Command/Parser.java rename to src/main/java/seedu/moneymind/tempCommand/Parser.java index d3f8907d3e..3ed7aebf81 100644 --- a/src/main/java/seedu/moneymind/Command/Parser.java +++ b/src/main/java/seedu/moneymind/tempCommand/Parser.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/seedu/moneymind/Command/ViewCommand.java b/src/main/java/seedu/moneymind/tempCommand/ViewCommand.java similarity index 98% rename from src/main/java/seedu/moneymind/Command/ViewCommand.java rename to src/main/java/seedu/moneymind/tempCommand/ViewCommand.java index 6403834f25..a6339f7212 100644 --- a/src/main/java/seedu/moneymind/Command/ViewCommand.java +++ b/src/main/java/seedu/moneymind/tempCommand/ViewCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.tempCommand; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; From b37565d7f08e7a5b3ad7856b06c9fdb16292bf1b Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Tue, 14 Mar 2023 22:38:35 +0800 Subject: [PATCH 054/210] fix package name --- .../seedu/moneymind/{tempCommand => command}/ByeCommand.java | 2 +- .../moneymind/{tempCommand => command}/CategoryCommand.java | 2 +- .../java/seedu/moneymind/{tempCommand => command}/Command.java | 2 +- .../seedu/moneymind/{tempCommand => command}/DeleteCommand.java | 2 +- .../seedu/moneymind/{tempCommand => command}/EventCommand.java | 2 +- .../{tempCommand => command}/InvalidCommandException.java | 2 +- .../java/seedu/moneymind/{tempCommand => command}/Parser.java | 2 +- .../seedu/moneymind/{tempCommand => command}/ViewCommand.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/seedu/moneymind/{tempCommand => command}/ByeCommand.java (88%) rename src/main/java/seedu/moneymind/{tempCommand => command}/CategoryCommand.java (95%) rename src/main/java/seedu/moneymind/{tempCommand => command}/Command.java (73%) rename src/main/java/seedu/moneymind/{tempCommand => command}/DeleteCommand.java (98%) rename src/main/java/seedu/moneymind/{tempCommand => command}/EventCommand.java (99%) rename src/main/java/seedu/moneymind/{tempCommand => command}/InvalidCommandException.java (88%) rename src/main/java/seedu/moneymind/{tempCommand => command}/Parser.java (99%) rename src/main/java/seedu/moneymind/{tempCommand => command}/ViewCommand.java (98%) diff --git a/src/main/java/seedu/moneymind/tempCommand/ByeCommand.java b/src/main/java/seedu/moneymind/command/ByeCommand.java similarity index 88% rename from src/main/java/seedu/moneymind/tempCommand/ByeCommand.java rename to src/main/java/seedu/moneymind/command/ByeCommand.java index 72bcd474df..48dbeec6a6 100644 --- a/src/main/java/seedu/moneymind/tempCommand/ByeCommand.java +++ b/src/main/java/seedu/moneymind/command/ByeCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; import seedu.moneymind.Ui; diff --git a/src/main/java/seedu/moneymind/tempCommand/CategoryCommand.java b/src/main/java/seedu/moneymind/command/CategoryCommand.java similarity index 95% rename from src/main/java/seedu/moneymind/tempCommand/CategoryCommand.java rename to src/main/java/seedu/moneymind/command/CategoryCommand.java index ee71a97d88..5e0d8aef2b 100644 --- a/src/main/java/seedu/moneymind/tempCommand/CategoryCommand.java +++ b/src/main/java/seedu/moneymind/command/CategoryCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/tempCommand/Command.java b/src/main/java/seedu/moneymind/command/Command.java similarity index 73% rename from src/main/java/seedu/moneymind/tempCommand/Command.java rename to src/main/java/seedu/moneymind/command/Command.java index cf283ad46a..cb089e0dc1 100644 --- a/src/main/java/seedu/moneymind/tempCommand/Command.java +++ b/src/main/java/seedu/moneymind/command/Command.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; import seedu.moneymind.Ui; diff --git a/src/main/java/seedu/moneymind/tempCommand/DeleteCommand.java b/src/main/java/seedu/moneymind/command/DeleteCommand.java similarity index 98% rename from src/main/java/seedu/moneymind/tempCommand/DeleteCommand.java rename to src/main/java/seedu/moneymind/command/DeleteCommand.java index fcfae50c9d..f3a2dbdf68 100644 --- a/src/main/java/seedu/moneymind/tempCommand/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/command/DeleteCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/tempCommand/EventCommand.java b/src/main/java/seedu/moneymind/command/EventCommand.java similarity index 99% rename from src/main/java/seedu/moneymind/tempCommand/EventCommand.java rename to src/main/java/seedu/moneymind/command/EventCommand.java index 81d022fee1..fbe983edc2 100644 --- a/src/main/java/seedu/moneymind/tempCommand/EventCommand.java +++ b/src/main/java/seedu/moneymind/command/EventCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; diff --git a/src/main/java/seedu/moneymind/tempCommand/InvalidCommandException.java b/src/main/java/seedu/moneymind/command/InvalidCommandException.java similarity index 88% rename from src/main/java/seedu/moneymind/tempCommand/InvalidCommandException.java rename to src/main/java/seedu/moneymind/command/InvalidCommandException.java index 79ea90a464..874445d74f 100644 --- a/src/main/java/seedu/moneymind/tempCommand/InvalidCommandException.java +++ b/src/main/java/seedu/moneymind/command/InvalidCommandException.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; public class InvalidCommandException extends Exception { private String errorMessage; diff --git a/src/main/java/seedu/moneymind/tempCommand/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java similarity index 99% rename from src/main/java/seedu/moneymind/tempCommand/Parser.java rename to src/main/java/seedu/moneymind/command/Parser.java index 3ed7aebf81..d3f8907d3e 100644 --- a/src/main/java/seedu/moneymind/tempCommand/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/seedu/moneymind/tempCommand/ViewCommand.java b/src/main/java/seedu/moneymind/command/ViewCommand.java similarity index 98% rename from src/main/java/seedu/moneymind/tempCommand/ViewCommand.java rename to src/main/java/seedu/moneymind/command/ViewCommand.java index a6339f7212..6403834f25 100644 --- a/src/main/java/seedu/moneymind/tempCommand/ViewCommand.java +++ b/src/main/java/seedu/moneymind/command/ViewCommand.java @@ -1,4 +1,4 @@ -package seedu.moneymind.tempCommand; +package seedu.moneymind.command; import seedu.moneymind.Category; import seedu.moneymind.CategoryList; From 79e07657ef371d1521d7cf0a48326bbffbb3ff1c Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Wed, 15 Mar 2023 22:54:00 +0800 Subject: [PATCH 055/210] Fix bugs and improve different commands --- src/main/java/seedu/moneymind/Category.java | 5 +++++ src/main/java/seedu/moneymind/Moneymind.java | 14 ++++++++++++-- src/main/java/seedu/moneymind/Strings.java | 2 ++ src/main/java/seedu/moneymind/Ui.java | 12 +----------- .../{Command => command}/ByeCommand.java | 0 .../{Command => command}/CategoryCommand.java | 5 +++++ .../moneymind/{Command => command}/Command.java | 0 .../{Command => command}/DeleteCommand.java | 15 ++++++++++++--- .../{Command => command}/EventCommand.java | 13 +++---------- .../InvalidCommandException.java | 0 .../moneymind/{Command => command}/Parser.java | 4 +++- .../{Command => command}/ViewCommand.java | 0 12 files changed, 43 insertions(+), 27 deletions(-) rename src/main/java/seedu/moneymind/{Command => command}/ByeCommand.java (100%) rename src/main/java/seedu/moneymind/{Command => command}/CategoryCommand.java (82%) rename src/main/java/seedu/moneymind/{Command => command}/Command.java (100%) rename src/main/java/seedu/moneymind/{Command => command}/DeleteCommand.java (82%) rename src/main/java/seedu/moneymind/{Command => command}/EventCommand.java (92%) rename src/main/java/seedu/moneymind/{Command => command}/InvalidCommandException.java (100%) rename src/main/java/seedu/moneymind/{Command => command}/Parser.java (96%) rename src/main/java/seedu/moneymind/{Command => command}/ViewCommand.java (100%) diff --git a/src/main/java/seedu/moneymind/Category.java b/src/main/java/seedu/moneymind/Category.java index 8be14ffc9d..bb742cb4ee 100644 --- a/src/main/java/seedu/moneymind/Category.java +++ b/src/main/java/seedu/moneymind/Category.java @@ -3,6 +3,7 @@ import java.util.ArrayList; public class Category { + public static final String NO_EVENTS_IN_THIS_CATEGORY_MESSAGE = "Opps! You have no events in this category."; ArrayList events = new ArrayList<>(); private String name; @@ -45,6 +46,10 @@ public void deleteEvent(int index) { * Gets the list of events. */ public void viewEventList() { + if (events.size() == 0) { + System.out.println(NO_EVENTS_IN_THIS_CATEGORY_MESSAGE); + return; + } for (int i = 0; i < events.size(); i++) { System.out.println(i + 1 + ". " + events.get(i).toString()); } diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index 05b562bfb6..3bb121e2e6 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -11,7 +11,8 @@ public class Moneymind { private Parser parser; private Storage storage; private Ui ui; - private Scanner in; + private String userInput; + public static Scanner in; public Moneymind() { this.parser = new Parser(); @@ -26,7 +27,9 @@ public void run() { storage.load(); while (!isExit) { try { - Command command = parser.parseNextCommand(in.nextLine()); + getInput(); + String refinedUserInput = userInput.trim().replaceAll(Strings.EXTRA_SPACE_REGEX_FORMAT, " "); + Command command = parser.parseNextCommand(refinedUserInput); if (command.isExit()) { ui.goodbye(); isExit = true; @@ -42,6 +45,13 @@ public void run() { storage.save(); } + private void getInput() { + System.out.println(Strings.HORIZONTAL_LINE); + System.out.println(); + userInput = in.nextLine(); + System.out.println(Strings.HORIZONTAL_LINE); + } + public static void main(String[] args) { new Moneymind().run(); } diff --git a/src/main/java/seedu/moneymind/Strings.java b/src/main/java/seedu/moneymind/Strings.java index 38d7127236..0fcd8c29fe 100644 --- a/src/main/java/seedu/moneymind/Strings.java +++ b/src/main/java/seedu/moneymind/Strings.java @@ -32,4 +32,6 @@ public class Strings { public static final String NEW_LINE = System.lineSeparator(); public static final String STORAGE_CATEGORY_NAME = "&&new_category&&"; public static final String STORAGE_CATEGORY_MAP = "&&category_map&&"; + public static final String EXISTED_CATEGORY = "Category already exists"; + public static final String EXTRA_SPACE_REGEX_FORMAT = "\\s+"; } diff --git a/src/main/java/seedu/moneymind/Ui.java b/src/main/java/seedu/moneymind/Ui.java index ee8635f24f..5fc1d9541c 100644 --- a/src/main/java/seedu/moneymind/Ui.java +++ b/src/main/java/seedu/moneymind/Ui.java @@ -4,11 +4,8 @@ import static seedu.moneymind.Strings.HORIZONTAL_LINE; public class Ui { - private static final String LINE = "____________________________________________________________\n"; private static final String LOGO = "[LOGO_PLACEHOLDER]\n"; - private static final String GREETING = "Hello from\n" + LOGO + "How may I help you?"; - private static final String NAME_REQUEST = "What is your name?"; - private static final String GOODBYE = "Bye. Hope to see you again soon!"; + private static final String GREETING = "Welcome to Moneymind\n" + LOGO + "How may I help you?"; private static final String ERROR = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; private static final String LIST = "Here are the events in your list:"; @@ -16,10 +13,6 @@ public void greet() { System.out.println(GREETING); } - public void requestName() { - System.out.println(NAME_REQUEST); - } - public void goodbye() { System.out.println(BYE_MESSAGE); System.out.println(HORIZONTAL_LINE); @@ -33,7 +26,4 @@ public void list() { System.out.println(LIST); } - public void echo(String value) { - System.out.println(value); - } } diff --git a/src/main/java/seedu/moneymind/Command/ByeCommand.java b/src/main/java/seedu/moneymind/command/ByeCommand.java similarity index 100% rename from src/main/java/seedu/moneymind/Command/ByeCommand.java rename to src/main/java/seedu/moneymind/command/ByeCommand.java diff --git a/src/main/java/seedu/moneymind/Command/CategoryCommand.java b/src/main/java/seedu/moneymind/command/CategoryCommand.java similarity index 82% rename from src/main/java/seedu/moneymind/Command/CategoryCommand.java rename to src/main/java/seedu/moneymind/command/CategoryCommand.java index 5e0d8aef2b..3a737f3398 100644 --- a/src/main/java/seedu/moneymind/Command/CategoryCommand.java +++ b/src/main/java/seedu/moneymind/command/CategoryCommand.java @@ -3,6 +3,7 @@ import seedu.moneymind.Category; import seedu.moneymind.CategoryList; import seedu.moneymind.Ui; +import seedu.moneymind.Strings; import java.util.HashMap; @@ -16,6 +17,10 @@ public CategoryCommand(String name) { @Override public void execute(Ui ui) { + if (categoryMap.get(name) != null) { + System.out.println(Strings.EXISTED_CATEGORY); + return; + } Category category = new Category(name); CategoryList.categories.add(category); categoryMap.put(name, CategoryList.categories.size() - 1); diff --git a/src/main/java/seedu/moneymind/Command/Command.java b/src/main/java/seedu/moneymind/command/Command.java similarity index 100% rename from src/main/java/seedu/moneymind/Command/Command.java rename to src/main/java/seedu/moneymind/command/Command.java diff --git a/src/main/java/seedu/moneymind/Command/DeleteCommand.java b/src/main/java/seedu/moneymind/command/DeleteCommand.java similarity index 82% rename from src/main/java/seedu/moneymind/Command/DeleteCommand.java rename to src/main/java/seedu/moneymind/command/DeleteCommand.java index f3a2dbdf68..6f57cc6d20 100644 --- a/src/main/java/seedu/moneymind/Command/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/command/DeleteCommand.java @@ -54,12 +54,15 @@ private void deleteEvent() { } int categoryIndex = CategoryCommand.categoryMap.get(categoryName); Category category = CategoryList.categories.get(categoryIndex); - for (int i = 0; i < category.getEvents().size(); i++) { - if (category.getEvents().get(i).getDescription().equals(eventName)) { - category.getEvents().remove(i); + int eventIndex = 0; + while (eventIndex < category.getEvents().size()) { + if (category.getEvents().get(eventIndex).getDescription().equals(eventName)) { + category.getEvents().remove(eventIndex); System.out.println(EVENT_DELETION_MESSAGE + eventName); isEventDeleted = true; + --eventIndex; } + ++eventIndex; } if (!isEventDeleted) { System.out.println(NON_EXISTENT_EVENT); @@ -77,6 +80,12 @@ private void deleteCategory() { int categoryIndex = CategoryCommand.categoryMap.get(categoryName); CategoryList.categories.remove(categoryIndex); CategoryCommand.categoryMap.remove(categoryName); + // loop through the hashmap and update the index of the categories + for (String key : CategoryCommand.categoryMap.keySet()) { + if (CategoryCommand.categoryMap.get(key) > categoryIndex) { + CategoryCommand.categoryMap.put(key, CategoryCommand.categoryMap.get(key) - 1); + } + } System.out.println(CATEGORY_DELETION_MESSAGE + categoryName); } diff --git a/src/main/java/seedu/moneymind/Command/EventCommand.java b/src/main/java/seedu/moneymind/command/EventCommand.java similarity index 92% rename from src/main/java/seedu/moneymind/Command/EventCommand.java rename to src/main/java/seedu/moneymind/command/EventCommand.java index fbe983edc2..2b3af36f6c 100644 --- a/src/main/java/seedu/moneymind/Command/EventCommand.java +++ b/src/main/java/seedu/moneymind/command/EventCommand.java @@ -1,10 +1,6 @@ package seedu.moneymind.command; -import seedu.moneymind.Category; -import seedu.moneymind.CategoryList; -import seedu.moneymind.Event; -import seedu.moneymind.Ui; -import seedu.moneymind.InvalidCategoryNumberException; +import seedu.moneymind.*; import java.util.Scanner; @@ -92,17 +88,14 @@ public void execute(Ui ui) { Event event = new Event(eventName, budget, expense); System.out.println(SELECTING_CATEGORY_MESSAGE); String userInput; - Scanner in; - in = new Scanner(System.in); - userInput = in.nextLine(); + userInput = Moneymind.in.nextLine(); while (!isChooseCategorySuccessful(userInput)) { System.out.println(GO_BACK_MESSAGE); - userInput = in.nextLine(); + userInput = Moneymind.in.nextLine(); if (userInput.equals(BACK)) { break; } } - in.close(); } @Override diff --git a/src/main/java/seedu/moneymind/Command/InvalidCommandException.java b/src/main/java/seedu/moneymind/command/InvalidCommandException.java similarity index 100% rename from src/main/java/seedu/moneymind/Command/InvalidCommandException.java rename to src/main/java/seedu/moneymind/command/InvalidCommandException.java diff --git a/src/main/java/seedu/moneymind/Command/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java similarity index 96% rename from src/main/java/seedu/moneymind/Command/Parser.java rename to src/main/java/seedu/moneymind/command/Parser.java index d3f8907d3e..757d1217c8 100644 --- a/src/main/java/seedu/moneymind/Command/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -96,7 +96,7 @@ private Command createEventCommand(String[] separatedKeywordAndDescription) thro checkNegativeBudgetAndExpense(Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); return new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); } else { - throw new InvalidCommandException(EVENT_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + throw new InvalidCommandException(""); } } catch (IndexOutOfBoundsException error) { throw new InvalidCommandException(EVENT_EMPTY); @@ -104,6 +104,8 @@ private Command createEventCommand(String[] separatedKeywordAndDescription) thro throw new InvalidCommandException(REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER); } catch (NegativeNumberException error) { throw new InvalidCommandException(REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER); + } catch (InvalidCommandException error) { + throw new InvalidCommandException(EVENT_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } catch (Exception error) { throw new InvalidCommandException(SUBTLE_BUG_MESSAGE); } diff --git a/src/main/java/seedu/moneymind/Command/ViewCommand.java b/src/main/java/seedu/moneymind/command/ViewCommand.java similarity index 100% rename from src/main/java/seedu/moneymind/Command/ViewCommand.java rename to src/main/java/seedu/moneymind/command/ViewCommand.java From b2300a38775efb8ef70ab537c085df3f8f7b3307 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Wed, 15 Mar 2023 23:49:35 +0800 Subject: [PATCH 056/210] Add help command --- src/main/java/seedu/moneymind/Strings.java | 8 ++--- .../seedu/moneymind/command/HelpCommand.java | 36 +++++++++++++++++++ .../java/seedu/moneymind/command/Parser.java | 34 ++++++++++++++---- 3 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 src/main/java/seedu/moneymind/command/HelpCommand.java diff --git a/src/main/java/seedu/moneymind/Strings.java b/src/main/java/seedu/moneymind/Strings.java index 0fcd8c29fe..f15c3382ce 100644 --- a/src/main/java/seedu/moneymind/Strings.java +++ b/src/main/java/seedu/moneymind/Strings.java @@ -11,17 +11,16 @@ public class Strings { public static final String CATEGORY = "category"; public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; public static final String DELETE_FORMAT = "Please following the correct format: " + - "delete c/ e/"; + "delete c/ e/" + + " or delete c/"; public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + "inside the brackets empty!"; public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; public static final String EVENT_REGEX = "(.+) b/(-?\\d+) e/(-?\\d+)"; public static final String EVENT_FORMAT = "Please following the correct format: " + - "event b/ e/"; + "event b/ e/"; public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; - public static final String REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER = - "☹ OOPS!!! The budget and expense must be a number."; public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; public static final String DELETE_REGEX = "^c/(?=\\S)(.*?)(?:\\s+e/(.*))?\\s*$"; public static final String NULL_INPUT_ASSERTION = "Input cannot be null"; @@ -34,4 +33,5 @@ public class Strings { public static final String STORAGE_CATEGORY_MAP = "&&category_map&&"; public static final String EXISTED_CATEGORY = "Category already exists"; public static final String EXTRA_SPACE_REGEX_FORMAT = "\\s+"; + public static final String HELP = "help"; } diff --git a/src/main/java/seedu/moneymind/command/HelpCommand.java b/src/main/java/seedu/moneymind/command/HelpCommand.java new file mode 100644 index 0000000000..5505377daa --- /dev/null +++ b/src/main/java/seedu/moneymind/command/HelpCommand.java @@ -0,0 +1,36 @@ +package seedu.moneymind.command; + +import seedu.moneymind.Ui; + +public class HelpCommand implements Command { + @Override + public void execute(Ui ui) { + System.out.println("Here are the commands you can use:"); + System.out.println("1. help - show instructions on how to use the app"); + System.out.println("Format: help"); + System.out.println("Example: help\n"); + System.out.println("2. category - add a category to your list"); + System.out.println("Format: category "); + System.out.println("Example: category food\n"); + System.out.println("3. event - add an event to a category"); + System.out.println("Format: event b/ e/"); + System.out.println("Example: event lunch b/10 e/5\n"); + System.out.println("4. view - view all the events in a category or all the categories"); + System.out.println("Format: view "); + System.out.println("If you want to view all the categories, just type view"); + System.out.println("Example: view food\n"); + System.out.println("5. delete - delete an event from a category or a whole category"); + System.out.println("Format: delete c/ e/"); + System.out.println("If you want to delete a whole category, you can remove e/"); + System.out.println("Example: delete c/food e/lunch"); + System.out.println("Example: delete c/food\n"); + System.out.println("6. bye - exit the app"); + System.out.println("Format: bye"); + System.out.println("Example: bye\n"); + } + + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/seedu/moneymind/command/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java index 757d1217c8..a1e2bbeca1 100644 --- a/src/main/java/seedu/moneymind/command/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -7,6 +7,7 @@ import static seedu.moneymind.Strings.WHITE_SPACE; import static seedu.moneymind.Strings.BYE; +import static seedu.moneymind.Strings.HELP; import static seedu.moneymind.Strings.VIEW; import static seedu.moneymind.Strings.DELETE; import static seedu.moneymind.Strings.EVENT; @@ -18,7 +19,6 @@ import static seedu.moneymind.Strings.EVENT_REGEX; import static seedu.moneymind.Strings.EVENT_FORMAT; import static seedu.moneymind.Strings.EVENT_EMPTY; -import static seedu.moneymind.Strings.REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER; import static seedu.moneymind.Strings.CATEGORY_EMPTY; import static seedu.moneymind.Strings.NULL_INPUT_ASSERTION; import static seedu.moneymind.Strings.NULL_DESCRIPTION; @@ -41,7 +41,9 @@ public Command parseNextCommand(String input) throws Exception { assert separatedKeywordAndDescription != null : NULL_DESCRIPTION; switch (keyword) { case BYE: - return createByeCommand(); + return createByeCommand(separatedKeywordAndDescription); + case HELP: + return createHelpCommand(separatedKeywordAndDescription); case VIEW: return createViewCommand(separatedKeywordAndDescription); case DELETE: @@ -55,8 +57,26 @@ public Command parseNextCommand(String input) throws Exception { } } - private Command createByeCommand() { - return new ByeCommand(); + private Command createByeCommand(String[] separatedKeywordAndDescription) throws InvalidCommandException { + try { + if (separatedKeywordAndDescription.length > 1) { + throw new InvalidCommandException(""); + } + return new ByeCommand(); + } catch (InvalidCommandException error) { + throw new InvalidCommandException("Bye command should not have any description"); + } + } + + private Command createHelpCommand(String[] separatedKeywordAndDescription) throws InvalidCommandException { + try { + if (separatedKeywordAndDescription.length > 1) { + throw new InvalidCommandException(""); + } + return new HelpCommand(); + } catch (InvalidCommandException error) { + throw new InvalidCommandException("Help command should not have any description"); + } } private Command createViewCommand(String[] separatedKeywordAndDescription) { @@ -78,6 +98,8 @@ private Command createDeleteCommand(String[] separatedKeywordAndDescription) thr String eventName = matcher.group(2); if (eventName == null) { return new DeleteCommand(categoryName); + } else if (eventName.isEmpty()) { + throw new InvalidCommandException(DELETE_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } return new DeleteCommand(categoryName, eventName); } else { @@ -100,9 +122,7 @@ private Command createEventCommand(String[] separatedKeywordAndDescription) thro } } catch (IndexOutOfBoundsException error) { throw new InvalidCommandException(EVENT_EMPTY); - } catch (NumberFormatException error) { - throw new InvalidCommandException(REMINDING_MESSAGE_ABOUT_GIVING_BUDGET_A_NUMBER); - } catch (NegativeNumberException error) { + } catch (NegativeNumberException error) { throw new InvalidCommandException(REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER); } catch (InvalidCommandException error) { throw new InvalidCommandException(EVENT_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); From ef00a533486143f54d602f19cfab9c45a5ce3230 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Thu, 16 Mar 2023 01:02:38 +0800 Subject: [PATCH 057/210] Divide packages and refactor code --- src/main/java/seedu/moneymind/Moneymind.java | 6 +- src/main/java/seedu/moneymind/Strings.java | 37 ---------- .../moneymind/{ => category}/Category.java | 8 ++- .../{ => category}/CategoryList.java | 2 +- .../seedu/moneymind/command/ByeCommand.java | 6 +- .../moneymind/command/CategoryCommand.java | 19 +++-- .../java/seedu/moneymind/command/Command.java | 2 +- .../moneymind/command/DeleteCommand.java | 6 +- .../seedu/moneymind/command/EventCommand.java | 32 +++++---- .../seedu/moneymind/command/HelpCommand.java | 43 ++++++----- .../java/seedu/moneymind/command/Parser.java | 44 ++++++------ .../seedu/moneymind/command/ViewCommand.java | 21 +++--- .../seedu/moneymind/{ => event}/Event.java | 2 +- .../InvalidCategoryNumberException.java | 2 +- .../InvalidCommandException.java | 2 +- .../NegativeNumberException.java | 2 +- .../storage/CategoryMapToString.java | 6 +- .../{ => storage}/CategoryToString.java | 11 +-- .../seedu/moneymind/storage/FormatToTxt.java | 3 +- .../moneymind/storage/LoadToCategoryMap.java | 4 +- .../java/seedu/moneymind/storage/Storage.java | 9 ++- .../{ => storage}/StringToCategory.java | 9 ++- .../java/seedu/moneymind/string/Strings.java | 72 +++++++++++++++++++ .../java/seedu/moneymind/{ => ui}/Ui.java | 6 +- .../seedu/moneymind/CategoryListTest.java | 1 + .../java/seedu/moneymind/CommandTest.java | 20 ++---- src/test/java/seedu/moneymind/EventTest.java | 1 + .../java/seedu/moneymind/StorageTest.java | 2 + 28 files changed, 216 insertions(+), 162 deletions(-) delete mode 100644 src/main/java/seedu/moneymind/Strings.java rename src/main/java/seedu/moneymind/{ => category}/Category.java (93%) rename src/main/java/seedu/moneymind/{ => category}/CategoryList.java (98%) rename src/main/java/seedu/moneymind/{ => event}/Event.java (98%) rename src/main/java/seedu/moneymind/{ => exceptions}/InvalidCategoryNumberException.java (82%) rename src/main/java/seedu/moneymind/{command => exceptions}/InvalidCommandException.java (88%) rename src/main/java/seedu/moneymind/{ => exceptions}/NegativeNumberException.java (85%) rename src/main/java/seedu/moneymind/{ => storage}/CategoryToString.java (72%) rename src/main/java/seedu/moneymind/{ => storage}/StringToCategory.java (87%) create mode 100644 src/main/java/seedu/moneymind/string/Strings.java rename src/main/java/seedu/moneymind/{ => ui}/Ui.java (82%) diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index 3bb121e2e6..e0ece3fcfc 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -3,16 +3,18 @@ import java.util.Scanner; import seedu.moneymind.command.Command; -import seedu.moneymind.command.InvalidCommandException; +import seedu.moneymind.exceptions.InvalidCommandException; import seedu.moneymind.command.Parser; import seedu.moneymind.storage.Storage; +import seedu.moneymind.string.Strings; +import seedu.moneymind.ui.Ui; public class Moneymind { + public static Scanner in; private Parser parser; private Storage storage; private Ui ui; private String userInput; - public static Scanner in; public Moneymind() { this.parser = new Parser(); diff --git a/src/main/java/seedu/moneymind/Strings.java b/src/main/java/seedu/moneymind/Strings.java deleted file mode 100644 index f15c3382ce..0000000000 --- a/src/main/java/seedu/moneymind/Strings.java +++ /dev/null @@ -1,37 +0,0 @@ -package seedu.moneymind; - -public class Strings { - public static final String BYE_MESSAGE = "Bye. Hope to see you again soon!"; - public static final String HORIZONTAL_LINE = "____________________________________________________________"; - public static final String WHITE_SPACE = " "; - public static final String BYE = "bye"; - public static final String VIEW = "view"; - public static final String DELETE = "delete"; - public static final String EVENT = "event"; - public static final String CATEGORY = "category"; - public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; - public static final String DELETE_FORMAT = "Please following the correct format: " + - "delete c/ e/" + - " or delete c/"; - public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + - "inside the brackets empty!"; - public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; - public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; - public static final String EVENT_REGEX = "(.+) b/(-?\\d+) e/(-?\\d+)"; - public static final String EVENT_FORMAT = "Please following the correct format: " + - "event b/ e/"; - public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; - public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; - public static final String DELETE_REGEX = "^c/(?=\\S)(.*?)(?:\\s+e/(.*))?\\s*$"; - public static final String NULL_INPUT_ASSERTION = "Input cannot be null"; - public static final String NULL_DESCRIPTION = "Separated keyword and description cannot be null"; - public static final String REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER = - "Please enter a positive number for budget and expense"; - public static final String STORAGE_NEXT_VARIABLE = "&&next_detail&&"; - public static final String NEW_LINE = System.lineSeparator(); - public static final String STORAGE_CATEGORY_NAME = "&&new_category&&"; - public static final String STORAGE_CATEGORY_MAP = "&&category_map&&"; - public static final String EXISTED_CATEGORY = "Category already exists"; - public static final String EXTRA_SPACE_REGEX_FORMAT = "\\s+"; - public static final String HELP = "help"; -} diff --git a/src/main/java/seedu/moneymind/Category.java b/src/main/java/seedu/moneymind/category/Category.java similarity index 93% rename from src/main/java/seedu/moneymind/Category.java rename to src/main/java/seedu/moneymind/category/Category.java index bb742cb4ee..4a7bcdb6f2 100644 --- a/src/main/java/seedu/moneymind/Category.java +++ b/src/main/java/seedu/moneymind/category/Category.java @@ -1,10 +1,12 @@ -package seedu.moneymind; +package seedu.moneymind.category; + +import seedu.moneymind.event.Event; import java.util.ArrayList; +import static seedu.moneymind.string.Strings.NO_EVENTS_IN_THIS_CATEGORY_MESSAGE; public class Category { - public static final String NO_EVENTS_IN_THIS_CATEGORY_MESSAGE = "Opps! You have no events in this category."; - ArrayList events = new ArrayList<>(); + public ArrayList events = new ArrayList<>(); private String name; diff --git a/src/main/java/seedu/moneymind/CategoryList.java b/src/main/java/seedu/moneymind/category/CategoryList.java similarity index 98% rename from src/main/java/seedu/moneymind/CategoryList.java rename to src/main/java/seedu/moneymind/category/CategoryList.java index 08fd46b2ba..7527e21819 100644 --- a/src/main/java/seedu/moneymind/CategoryList.java +++ b/src/main/java/seedu/moneymind/category/CategoryList.java @@ -1,4 +1,4 @@ -package seedu.moneymind; +package seedu.moneymind.category; import java.util.ArrayList; diff --git a/src/main/java/seedu/moneymind/command/ByeCommand.java b/src/main/java/seedu/moneymind/command/ByeCommand.java index 48dbeec6a6..5e904f112e 100644 --- a/src/main/java/seedu/moneymind/command/ByeCommand.java +++ b/src/main/java/seedu/moneymind/command/ByeCommand.java @@ -1,11 +1,15 @@ package seedu.moneymind.command; -import seedu.moneymind.Ui; +import seedu.moneymind.ui.Ui; /** * Represents the command to exit the program. */ public class ByeCommand implements Command { + + /** + * Exits the program. + */ @Override public void execute(Ui ui) { ui.goodbye(); diff --git a/src/main/java/seedu/moneymind/command/CategoryCommand.java b/src/main/java/seedu/moneymind/command/CategoryCommand.java index 3a737f3398..d28e193f7a 100644 --- a/src/main/java/seedu/moneymind/command/CategoryCommand.java +++ b/src/main/java/seedu/moneymind/command/CategoryCommand.java @@ -1,20 +1,31 @@ package seedu.moneymind.command; -import seedu.moneymind.Category; -import seedu.moneymind.CategoryList; -import seedu.moneymind.Ui; -import seedu.moneymind.Strings; +import seedu.moneymind.category.Category; +import seedu.moneymind.category.CategoryList; +import seedu.moneymind.ui.Ui; +import seedu.moneymind.string.Strings; import java.util.HashMap; +/** + * Represents the command to add a new category. + */ public class CategoryCommand implements Command { public static HashMap categoryMap = new HashMap(); private final String name; + /** + * Constructs a new CategoryCommand object and adds the category. + * + * @param name the name of the category + */ public CategoryCommand(String name) { this.name = name; } + /** + * Adds the category. + */ @Override public void execute(Ui ui) { if (categoryMap.get(name) != null) { diff --git a/src/main/java/seedu/moneymind/command/Command.java b/src/main/java/seedu/moneymind/command/Command.java index cb089e0dc1..23a1883d48 100644 --- a/src/main/java/seedu/moneymind/command/Command.java +++ b/src/main/java/seedu/moneymind/command/Command.java @@ -1,6 +1,6 @@ package seedu.moneymind.command; -import seedu.moneymind.Ui; +import seedu.moneymind.ui.Ui; public interface Command { void execute(Ui ui); diff --git a/src/main/java/seedu/moneymind/command/DeleteCommand.java b/src/main/java/seedu/moneymind/command/DeleteCommand.java index 6f57cc6d20..2847f44749 100644 --- a/src/main/java/seedu/moneymind/command/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/command/DeleteCommand.java @@ -1,8 +1,8 @@ package seedu.moneymind.command; -import seedu.moneymind.Category; -import seedu.moneymind.CategoryList; -import seedu.moneymind.Ui; +import seedu.moneymind.category.Category; +import seedu.moneymind.category.CategoryList; +import seedu.moneymind.ui.Ui; /** * Represents the command to delete an event or a category. diff --git a/src/main/java/seedu/moneymind/command/EventCommand.java b/src/main/java/seedu/moneymind/command/EventCommand.java index 2b3af36f6c..08554c7d47 100644 --- a/src/main/java/seedu/moneymind/command/EventCommand.java +++ b/src/main/java/seedu/moneymind/command/EventCommand.java @@ -1,24 +1,28 @@ package seedu.moneymind.command; -import seedu.moneymind.*; - -import java.util.Scanner; +import seedu.moneymind.Moneymind; +import seedu.moneymind.category.Category; +import seedu.moneymind.category.CategoryList; +import seedu.moneymind.event.Event; +import seedu.moneymind.exceptions.InvalidCategoryNumberException; +import seedu.moneymind.ui.Ui; +import static seedu.moneymind.string.Strings.NULL_EVENT_ASSERTION; +import static seedu.moneymind.string.Strings.NON_NEGATIVE_BUDGET_ASSERTION; +import static seedu.moneymind.string.Strings.NON_NEGATIVE_EXPENSE_ASSERTION; +import static seedu.moneymind.string.Strings.NON_NEGATIVE_POSITION_ASSERTION; +import static seedu.moneymind.string.Strings.EVENT_ADDED_MESSAGE; +import static seedu.moneymind.string.Strings.REMINDING_MESSAGE_TO_GIVE_A_NUMBER; +import static seedu.moneymind.string.Strings.CATEGORY_OUT_OF_RANGE; +import static seedu.moneymind.string.Strings.SUBTLE_BUG_MESSAGE; +import static seedu.moneymind.string.Strings.SELECTING_CATEGORY_MESSAGE; +import static seedu.moneymind.string.Strings.GO_BACK_MESSAGE; +import static seedu.moneymind.string.Strings.BACK; /** * A class to add an event */ public class EventCommand implements Command { - public static final String SELECTING_CATEGORY_MESSAGE = "Please select the category you want to add the event to: "; - public static final String GO_BACK_MESSAGE = "Please enter back to go back to the main program"; - public static final String BACK = "back"; - public static final String EVENT_ADDED_MESSAGE = "New event added: "; - public static final String REMINDING_MESSAGE_TO_GIVE_A_NUMBER = "Please enter a number."; - public static final String CATEGORY_OUT_OF_RANGE = "The category number you entered is out of range"; - public static final String SUBTLE_BUG_MESSAGE = "Something went wrong, please report to the developer"; - public static final String NON_NEGATIVE_POSITION_ASSERTION = "Category position cannot be negative"; - public static final String NULL_EVENT_ASSERTION = "Event name cannot be null"; - public static final String NON_NEGATIVE_BUDGET_ASSERTION = "Budget cannot be negative"; - public static final String NON_NEGATIVE_EXPENSE_ASSERTION = "Expense cannot be negative"; + private String eventName; private int budget; private int expense; diff --git a/src/main/java/seedu/moneymind/command/HelpCommand.java b/src/main/java/seedu/moneymind/command/HelpCommand.java index 5505377daa..ed9ac438cb 100644 --- a/src/main/java/seedu/moneymind/command/HelpCommand.java +++ b/src/main/java/seedu/moneymind/command/HelpCommand.java @@ -1,32 +1,29 @@ package seedu.moneymind.command; -import seedu.moneymind.Ui; +import seedu.moneymind.ui.Ui; +import static seedu.moneymind.string.Strings.INTRODUCTION_HELP_COMMAND; +import static seedu.moneymind.string.Strings.HELP_INSTRUCTION; +import static seedu.moneymind.string.Strings.CATEGORY_INSTRUCTION; +import static seedu.moneymind.string.Strings.EVENT_INSTRUCTION; +import static seedu.moneymind.string.Strings.VIEW_INSTRUCTION; +import static seedu.moneymind.string.Strings.DELETE_INSTRUCTION; +import static seedu.moneymind.string.Strings.BYE_INSTRUCTION; + +/** + * Represents the help command. + */ public class HelpCommand implements Command { + @Override public void execute(Ui ui) { - System.out.println("Here are the commands you can use:"); - System.out.println("1. help - show instructions on how to use the app"); - System.out.println("Format: help"); - System.out.println("Example: help\n"); - System.out.println("2. category - add a category to your list"); - System.out.println("Format: category "); - System.out.println("Example: category food\n"); - System.out.println("3. event - add an event to a category"); - System.out.println("Format: event b/ e/"); - System.out.println("Example: event lunch b/10 e/5\n"); - System.out.println("4. view - view all the events in a category or all the categories"); - System.out.println("Format: view "); - System.out.println("If you want to view all the categories, just type view"); - System.out.println("Example: view food\n"); - System.out.println("5. delete - delete an event from a category or a whole category"); - System.out.println("Format: delete c/ e/"); - System.out.println("If you want to delete a whole category, you can remove e/"); - System.out.println("Example: delete c/food e/lunch"); - System.out.println("Example: delete c/food\n"); - System.out.println("6. bye - exit the app"); - System.out.println("Format: bye"); - System.out.println("Example: bye\n"); + System.out.println(INTRODUCTION_HELP_COMMAND); + System.out.println(HELP_INSTRUCTION); + System.out.println(CATEGORY_INSTRUCTION); + System.out.println(EVENT_INSTRUCTION); + System.out.println(VIEW_INSTRUCTION); + System.out.println(DELETE_INSTRUCTION); + System.out.println(BYE_INSTRUCTION); } @Override diff --git a/src/main/java/seedu/moneymind/command/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java index a1e2bbeca1..94e52e7f8b 100644 --- a/src/main/java/seedu/moneymind/command/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -2,29 +2,31 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import seedu.moneymind.NegativeNumberException; +import seedu.moneymind.exceptions.InvalidCommandException; +import seedu.moneymind.exceptions.NegativeNumberException; -import static seedu.moneymind.Strings.WHITE_SPACE; -import static seedu.moneymind.Strings.BYE; -import static seedu.moneymind.Strings.HELP; -import static seedu.moneymind.Strings.VIEW; -import static seedu.moneymind.Strings.DELETE; -import static seedu.moneymind.Strings.EVENT; -import static seedu.moneymind.Strings.CATEGORY; -import static seedu.moneymind.Strings.INVALID_INPUT; -import static seedu.moneymind.Strings.DELETE_FORMAT; -import static seedu.moneymind.Strings.REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY; -import static seedu.moneymind.Strings.SUBTLE_BUG_MESSAGE; -import static seedu.moneymind.Strings.EVENT_REGEX; -import static seedu.moneymind.Strings.EVENT_FORMAT; -import static seedu.moneymind.Strings.EVENT_EMPTY; -import static seedu.moneymind.Strings.CATEGORY_EMPTY; -import static seedu.moneymind.Strings.NULL_INPUT_ASSERTION; -import static seedu.moneymind.Strings.NULL_DESCRIPTION; -import static seedu.moneymind.Strings.DELETE_REGEX; -import static seedu.moneymind.Strings.EMPTY_DELETION; -import static seedu.moneymind.Strings.REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER; + +import static seedu.moneymind.string.Strings.WHITE_SPACE; +import static seedu.moneymind.string.Strings.BYE; +import static seedu.moneymind.string.Strings.HELP; +import static seedu.moneymind.string.Strings.VIEW; +import static seedu.moneymind.string.Strings.DELETE; +import static seedu.moneymind.string.Strings.EVENT; +import static seedu.moneymind.string.Strings.CATEGORY; +import static seedu.moneymind.string.Strings.INVALID_INPUT; +import static seedu.moneymind.string.Strings.DELETE_FORMAT; +import static seedu.moneymind.string.Strings.REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY; +import static seedu.moneymind.string.Strings.SUBTLE_BUG_MESSAGE; +import static seedu.moneymind.string.Strings.EVENT_REGEX; +import static seedu.moneymind.string.Strings.EVENT_FORMAT; +import static seedu.moneymind.string.Strings.EVENT_EMPTY; +import static seedu.moneymind.string.Strings.CATEGORY_EMPTY; +import static seedu.moneymind.string.Strings.NULL_INPUT_ASSERTION; +import static seedu.moneymind.string.Strings.NULL_DESCRIPTION; +import static seedu.moneymind.string.Strings.DELETE_REGEX; +import static seedu.moneymind.string.Strings.EMPTY_DELETION; +import static seedu.moneymind.string.Strings.REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER; /** * A class to parse the user input. diff --git a/src/main/java/seedu/moneymind/command/ViewCommand.java b/src/main/java/seedu/moneymind/command/ViewCommand.java index 6403834f25..d4202ed767 100644 --- a/src/main/java/seedu/moneymind/command/ViewCommand.java +++ b/src/main/java/seedu/moneymind/command/ViewCommand.java @@ -1,20 +1,21 @@ package seedu.moneymind.command; -import seedu.moneymind.Category; -import seedu.moneymind.CategoryList; -import seedu.moneymind.Event; -import seedu.moneymind.Ui; +import seedu.moneymind.category.Category; +import seedu.moneymind.category.CategoryList; +import seedu.moneymind.event.Event; +import seedu.moneymind.ui.Ui; + +import static seedu.moneymind.string.Strings.NULL_CATEGORY_ASSERTION; +import static seedu.moneymind.string.Strings.NO_CATEGORY_MESSAGE; +import static seedu.moneymind.string.Strings.NULL_CATEGORY_LIST_ASSERTION; +import static seedu.moneymind.string.Strings.NO_CATEGORIES_TO_VIEW; +import static seedu.moneymind.string.Strings.DOT; +import static seedu.moneymind.string.Strings.COUNT_ASSERTION; /** * ViewCommand class to view the categories and events. */ public class ViewCommand implements Command { - public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; - public static final String DOT = "."; - public static final String NO_CATEGORIES_TO_VIEW = "There are no categories to view"; - public static final String COUNT_ASSERTION = "Count should be greater than 1"; - public static final String NULL_CATEGORY_ASSERTION = "Category name should not be null"; - public static final String NULL_CATEGORY_LIST_ASSERTION = "Category list should not be null"; private String categoryName; private final boolean isCategorySpecified; diff --git a/src/main/java/seedu/moneymind/Event.java b/src/main/java/seedu/moneymind/event/Event.java similarity index 98% rename from src/main/java/seedu/moneymind/Event.java rename to src/main/java/seedu/moneymind/event/Event.java index 405e1ffa9d..74a9921fa2 100644 --- a/src/main/java/seedu/moneymind/Event.java +++ b/src/main/java/seedu/moneymind/event/Event.java @@ -1,4 +1,4 @@ -package seedu.moneymind; +package seedu.moneymind.event; public class Event { private static final int DEFAULT_EXPENSE = 0; diff --git a/src/main/java/seedu/moneymind/InvalidCategoryNumberException.java b/src/main/java/seedu/moneymind/exceptions/InvalidCategoryNumberException.java similarity index 82% rename from src/main/java/seedu/moneymind/InvalidCategoryNumberException.java rename to src/main/java/seedu/moneymind/exceptions/InvalidCategoryNumberException.java index bfc13298dd..e12e353fc7 100644 --- a/src/main/java/seedu/moneymind/InvalidCategoryNumberException.java +++ b/src/main/java/seedu/moneymind/exceptions/InvalidCategoryNumberException.java @@ -1,4 +1,4 @@ -package seedu.moneymind; +package seedu.moneymind.exceptions; /** * Throws exception when the user input an invalid category number. diff --git a/src/main/java/seedu/moneymind/command/InvalidCommandException.java b/src/main/java/seedu/moneymind/exceptions/InvalidCommandException.java similarity index 88% rename from src/main/java/seedu/moneymind/command/InvalidCommandException.java rename to src/main/java/seedu/moneymind/exceptions/InvalidCommandException.java index 874445d74f..7894195863 100644 --- a/src/main/java/seedu/moneymind/command/InvalidCommandException.java +++ b/src/main/java/seedu/moneymind/exceptions/InvalidCommandException.java @@ -1,4 +1,4 @@ -package seedu.moneymind.command; +package seedu.moneymind.exceptions; public class InvalidCommandException extends Exception { private String errorMessage; diff --git a/src/main/java/seedu/moneymind/NegativeNumberException.java b/src/main/java/seedu/moneymind/exceptions/NegativeNumberException.java similarity index 85% rename from src/main/java/seedu/moneymind/NegativeNumberException.java rename to src/main/java/seedu/moneymind/exceptions/NegativeNumberException.java index 61cfe791f3..d4426fe8c4 100644 --- a/src/main/java/seedu/moneymind/NegativeNumberException.java +++ b/src/main/java/seedu/moneymind/exceptions/NegativeNumberException.java @@ -1,4 +1,4 @@ -package seedu.moneymind; +package seedu.moneymind.exceptions; /** * Throws exception when the user input a negative number. diff --git a/src/main/java/seedu/moneymind/storage/CategoryMapToString.java b/src/main/java/seedu/moneymind/storage/CategoryMapToString.java index 903fff2af9..34126aafb1 100644 --- a/src/main/java/seedu/moneymind/storage/CategoryMapToString.java +++ b/src/main/java/seedu/moneymind/storage/CategoryMapToString.java @@ -1,8 +1,8 @@ package seedu.moneymind.storage; -import static seedu.moneymind.Strings.STORAGE_CATEGORY_MAP; -import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; -import static seedu.moneymind.Strings.NEW_LINE; +import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_MAP; +import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; +import static seedu.moneymind.string.Strings.NEW_LINE; import static seedu.moneymind.command.CategoryCommand.categoryMap; /** diff --git a/src/main/java/seedu/moneymind/CategoryToString.java b/src/main/java/seedu/moneymind/storage/CategoryToString.java similarity index 72% rename from src/main/java/seedu/moneymind/CategoryToString.java rename to src/main/java/seedu/moneymind/storage/CategoryToString.java index 83267851a6..6ea1934f93 100644 --- a/src/main/java/seedu/moneymind/CategoryToString.java +++ b/src/main/java/seedu/moneymind/storage/CategoryToString.java @@ -1,8 +1,11 @@ -package seedu.moneymind; +package seedu.moneymind.storage; -import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; -import static seedu.moneymind.Strings.NEW_LINE; -import static seedu.moneymind.Strings.STORAGE_CATEGORY_NAME; +import seedu.moneymind.event.Event; +import seedu.moneymind.category.Category; + +import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; +import static seedu.moneymind.string.Strings.NEW_LINE; +import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_NAME; /** * Converts a Category object to a String. diff --git a/src/main/java/seedu/moneymind/storage/FormatToTxt.java b/src/main/java/seedu/moneymind/storage/FormatToTxt.java index e082af00da..b04fcbc65a 100644 --- a/src/main/java/seedu/moneymind/storage/FormatToTxt.java +++ b/src/main/java/seedu/moneymind/storage/FormatToTxt.java @@ -2,8 +2,7 @@ import java.util.ArrayList; -import seedu.moneymind.Category; -import seedu.moneymind.CategoryToString; +import seedu.moneymind.category.Category; /** * Converts an ArrayList of Category objects to a String. diff --git a/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java b/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java index 7a1b4c91ed..0fe1d02bf6 100644 --- a/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java +++ b/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java @@ -2,8 +2,8 @@ import java.util.HashMap; -import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; -import static seedu.moneymind.Strings.NEW_LINE; +import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; +import static seedu.moneymind.string.Strings.NEW_LINE; import static seedu.moneymind.command.CategoryCommand.categoryMap; /** diff --git a/src/main/java/seedu/moneymind/storage/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java index 99dc730030..dcc96c10ac 100644 --- a/src/main/java/seedu/moneymind/storage/Storage.java +++ b/src/main/java/seedu/moneymind/storage/Storage.java @@ -7,12 +7,11 @@ import java.io.FileWriter; import java.io.IOException; -import seedu.moneymind.Category; -import seedu.moneymind.CategoryList; -import seedu.moneymind.StringToCategory; +import seedu.moneymind.category.Category; +import seedu.moneymind.category.CategoryList; -import static seedu.moneymind.Strings.STORAGE_CATEGORY_MAP; -import static seedu.moneymind.Strings.NEW_LINE; +import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_MAP; +import static seedu.moneymind.string.Strings.NEW_LINE; /** * Storage class to save and load data from a file diff --git a/src/main/java/seedu/moneymind/StringToCategory.java b/src/main/java/seedu/moneymind/storage/StringToCategory.java similarity index 87% rename from src/main/java/seedu/moneymind/StringToCategory.java rename to src/main/java/seedu/moneymind/storage/StringToCategory.java index 21d1996f73..0a058247fa 100644 --- a/src/main/java/seedu/moneymind/StringToCategory.java +++ b/src/main/java/seedu/moneymind/storage/StringToCategory.java @@ -1,9 +1,12 @@ -package seedu.moneymind; +package seedu.moneymind.storage; + +import seedu.moneymind.event.Event; +import seedu.moneymind.category.Category; import java.util.ArrayList; -import static seedu.moneymind.Strings.STORAGE_CATEGORY_NAME; -import static seedu.moneymind.Strings.STORAGE_NEXT_VARIABLE; +import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_NAME; +import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; /** * Converts a String from file.txt to an ArrayList of Category objects. diff --git a/src/main/java/seedu/moneymind/string/Strings.java b/src/main/java/seedu/moneymind/string/Strings.java new file mode 100644 index 0000000000..2d1736f2f5 --- /dev/null +++ b/src/main/java/seedu/moneymind/string/Strings.java @@ -0,0 +1,72 @@ +package seedu.moneymind.string; + +public class Strings { + public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; + public static final String DOT = "."; + public static final String NO_CATEGORIES_TO_VIEW = "There are no categories to view"; + public static final String COUNT_ASSERTION = "Count should be greater than 1"; + public static final String NULL_CATEGORY_ASSERTION = "Category name should not be null"; + public static final String NULL_CATEGORY_LIST_ASSERTION = "Category list should not be null"; + + public static final String INTRODUCTION_HELP_COMMAND = "Here are the commands you can use:"; + public static final String HELP_INSTRUCTION = "1. help - show instructions on how to use the app\n" + + "Format: help\n" + "Example: help\n"; + public static final String CATEGORY_INSTRUCTION = "2. category - add a category to your list\n" + + "Format: category \n" + "Example: category food\n"; + public static final String EVENT_INSTRUCTION = "3. event - add an event to a category\n" + + "Format: event b/ e/\n" + + "Example: event lunch b/10 e/5\n"; + public static final String VIEW_INSTRUCTION = + "4. view - view all the events in a category or all the categories\n" + + "You can view all the categories by entering view without any category name\n" + + "Format: view \n" + "Example: view food\n"; + public static final String DELETE_INSTRUCTION = "5. delete - delete an event or a category\n" + + "Format: delete c/ e/\n" + + "You can delete a category by entering delete c/ without e/\n" + + "Example: delete c/food e/lunch\n" + "Example: delete c/food\n"; + public static final String BYE_INSTRUCTION = "6. bye - exit the app\n" + "Format: bye\n" + "Example: bye\n"; + public static final String SELECTING_CATEGORY_MESSAGE = "Please select the category you want to add the event to: "; + public static final String GO_BACK_MESSAGE = "Please enter back to go back to the main program"; + public static final String BACK = "back"; + public static final String EVENT_ADDED_MESSAGE = "New event added: "; + public static final String REMINDING_MESSAGE_TO_GIVE_A_NUMBER = "Please enter a number."; + public static final String CATEGORY_OUT_OF_RANGE = "The category number you entered is out of range"; + public static final String NON_NEGATIVE_POSITION_ASSERTION = "Category position cannot be negative"; + public static final String NULL_EVENT_ASSERTION = "Event name cannot be null"; + public static final String NON_NEGATIVE_BUDGET_ASSERTION = "Budget cannot be negative"; + public static final String NON_NEGATIVE_EXPENSE_ASSERTION = "Expense cannot be negative"; + public static final String NO_EVENTS_IN_THIS_CATEGORY_MESSAGE = "Opps! You have no events in this category."; + public static final String BYE_MESSAGE = "Bye. Hope to see you again soon!"; + public static final String HORIZONTAL_LINE = "____________________________________________________________"; + public static final String WHITE_SPACE = " "; + public static final String BYE = "bye"; + public static final String VIEW = "view"; + public static final String DELETE = "delete"; + public static final String EVENT = "event"; + public static final String CATEGORY = "category"; + public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; + public static final String DELETE_FORMAT = "Please following the correct format: " + + "delete c/ e/" + + " or delete c/"; + public static final String REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY = "Remember do not leave any things " + + "inside the brackets empty!"; + public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; + public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; + public static final String EVENT_REGEX = "(.+) b/(-?\\d+) e/(-?\\d+)"; + public static final String EVENT_FORMAT = "Please following the correct format: " + + "event b/ e/"; + public static final String EVENT_EMPTY = "☹ OOPS!!! The description of an event cannot be empty."; + public static final String CATEGORY_EMPTY = "☹ OOPS!!! The description of a category cannot be empty."; + public static final String DELETE_REGEX = "^c/(?=\\S)(.*?)(?:\\s+e/(.*))?\\s*$"; + public static final String NULL_INPUT_ASSERTION = "Input cannot be null"; + public static final String NULL_DESCRIPTION = "Separated keyword and description cannot be null"; + public static final String REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER = + "Please enter a positive number for budget and expense"; + public static final String STORAGE_NEXT_VARIABLE = "&&next_detail&&"; + public static final String NEW_LINE = System.lineSeparator(); + public static final String STORAGE_CATEGORY_NAME = "&&new_category&&"; + public static final String STORAGE_CATEGORY_MAP = "&&category_map&&"; + public static final String EXISTED_CATEGORY = "Category already exists"; + public static final String EXTRA_SPACE_REGEX_FORMAT = "\\s+"; + public static final String HELP = "help"; +} diff --git a/src/main/java/seedu/moneymind/Ui.java b/src/main/java/seedu/moneymind/ui/Ui.java similarity index 82% rename from src/main/java/seedu/moneymind/Ui.java rename to src/main/java/seedu/moneymind/ui/Ui.java index 5fc1d9541c..50e7b18f05 100644 --- a/src/main/java/seedu/moneymind/Ui.java +++ b/src/main/java/seedu/moneymind/ui/Ui.java @@ -1,7 +1,7 @@ -package seedu.moneymind; +package seedu.moneymind.ui; -import static seedu.moneymind.Strings.BYE_MESSAGE; -import static seedu.moneymind.Strings.HORIZONTAL_LINE; +import static seedu.moneymind.string.Strings.BYE_MESSAGE; +import static seedu.moneymind.string.Strings.HORIZONTAL_LINE; public class Ui { private static final String LOGO = "[LOGO_PLACEHOLDER]\n"; diff --git a/src/test/java/seedu/moneymind/CategoryListTest.java b/src/test/java/seedu/moneymind/CategoryListTest.java index f87299f6ca..0cd90239ab 100644 --- a/src/test/java/seedu/moneymind/CategoryListTest.java +++ b/src/test/java/seedu/moneymind/CategoryListTest.java @@ -1,6 +1,7 @@ package seedu.moneymind; import org.junit.jupiter.api.Test; +import seedu.moneymind.category.CategoryList; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index 55dfd61a24..b97f2584a3 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -2,12 +2,14 @@ import org.junit.jupiter.api.Test; +import seedu.moneymind.category.Category; +import seedu.moneymind.category.CategoryList; import seedu.moneymind.command.CategoryCommand; import seedu.moneymind.command.Command; import seedu.moneymind.command.Parser; +import seedu.moneymind.event.Event; +import seedu.moneymind.ui.Ui; -import java.io.ByteArrayInputStream; -import java.io.InputStream; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -42,20 +44,6 @@ void addCategory_oneCategory_expectThreeCategoryInCategoryList() { clear(); } - @Test - void addEvent_oneFoodEvent_expectThreeEventsInFoodCategory() { - setup(); - String input = "event banana b/20 e/10"; - String categoryIndex = "1\n"; // replace with the correct input string - InputStream in = new ByteArrayInputStream(categoryIndex.getBytes()); - System.setIn(in); - executeInput(input); - assertEquals("banana", food.events.get(2).getDescription()); - assertEquals(20, food.events.get(2).getBudget()); - assertEquals(10, food.events.get(2).getExpense()); - clear(); - } - @Test void deleteWholeCategory_oneCategory_expectOneCategoryInList() { setup(); diff --git a/src/test/java/seedu/moneymind/EventTest.java b/src/test/java/seedu/moneymind/EventTest.java index 034c2a907a..129c3b7377 100644 --- a/src/test/java/seedu/moneymind/EventTest.java +++ b/src/test/java/seedu/moneymind/EventTest.java @@ -1,6 +1,7 @@ package seedu.moneymind; import org.junit.jupiter.api.Test; +import seedu.moneymind.event.Event; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/seedu/moneymind/StorageTest.java b/src/test/java/seedu/moneymind/StorageTest.java index 010f1a695d..0a18f63086 100644 --- a/src/test/java/seedu/moneymind/StorageTest.java +++ b/src/test/java/seedu/moneymind/StorageTest.java @@ -8,7 +8,9 @@ import org.junit.jupiter.api.Test; +import seedu.moneymind.category.Category; import seedu.moneymind.command.CategoryCommand; +import seedu.moneymind.event.Event; import seedu.moneymind.storage.FormatToTxt; import seedu.moneymind.storage.Storage; From 1f1246b5c865a53557c460a1297a6c28d405b4ac Mon Sep 17 00:00:00 2001 From: Toh-HongFeng <88129105+Toh-HongFeng@users.noreply.github.com> Date: Thu, 16 Mar 2023 01:23:23 +0800 Subject: [PATCH 058/210] Update Parser.java --- src/main/java/seedu/moneymind/command/Parser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/seedu/moneymind/command/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java index e30b98e391..94e52e7f8b 100644 --- a/src/main/java/seedu/moneymind/command/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -78,6 +78,7 @@ private Command createHelpCommand(String[] separatedKeywordAndDescription) throw return new HelpCommand(); } catch (InvalidCommandException error) { throw new InvalidCommandException("Help command should not have any description"); + } } private Command createViewCommand(String[] separatedKeywordAndDescription) { From 90cbf14c1556d2349f5b991b795b0fe92b3951dc Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Thu, 16 Mar 2023 09:25:58 +0800 Subject: [PATCH 059/210] Update regression test --- text-ui-test/EXPECTED.TXT | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 9c2a722a2c..94519e6ec1 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,6 +1,12 @@ -Hello from +Welcome to Moneymind [LOGO_PLACEHOLDER] How may I help you? +____________________________________________________________ + +____________________________________________________________ ☹ OOPS!!! I'm sorry, but I don't know what that means :-( +____________________________________________________________ + +____________________________________________________________ Bye. Hope to see you again soon! ____________________________________________________________ From d7de1d8afa489546f258172f549e73bf96f3a9a5 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Thu, 16 Mar 2023 09:51:04 +0800 Subject: [PATCH 060/210] update EXPECTED.txt and debug 2nd test of CommandTest.java --- .../java/seedu/moneymind/CommandTest.java | 19 +++++++++++++++++++ text-ui-test/EXPECTED.TXT | 8 +++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/moneymind/CommandTest.java b/src/test/java/seedu/moneymind/CommandTest.java index b97f2584a3..86c7446d28 100644 --- a/src/test/java/seedu/moneymind/CommandTest.java +++ b/src/test/java/seedu/moneymind/CommandTest.java @@ -8,10 +8,12 @@ import seedu.moneymind.command.Command; import seedu.moneymind.command.Parser; import seedu.moneymind.event.Event; +import seedu.moneymind.string.Strings; import seedu.moneymind.ui.Ui; import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.util.Scanner; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -44,6 +46,23 @@ void addCategory_oneCategory_expectThreeCategoryInCategoryList() { clear(); } + @Test + void addEvent_oneFoodEvent_expectThreeEventsInFoodCategory() { + setup(); + String input = "event banana b/20 e/10"; + String categoryIndex = "1" + Strings.NEW_LINE; // replace with the correct input string + Moneymind.in = new Scanner(categoryIndex); + executeInput(input); + Moneymind.in = new Scanner(System.in); + assertEquals("banana", food.events.get(2).getDescription(), + "expected: banana, actual: " + food.events.get(2).getDescription()); + assertEquals(20, food.events.get(2).getBudget(), + "expected: 20, actual: " + food.events.get(2).getBudget()); + assertEquals(10, food.events.get(2).getExpense(), + "expected: 10, actual: " + food.events.get(2).getExpense()); + clear(); + } + @Test void deleteWholeCategory_oneCategory_expectOneCategoryInList() { setup(); diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 9c2a722a2c..94519e6ec1 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,6 +1,12 @@ -Hello from +Welcome to Moneymind [LOGO_PLACEHOLDER] How may I help you? +____________________________________________________________ + +____________________________________________________________ ☹ OOPS!!! I'm sorry, but I don't know what that means :-( +____________________________________________________________ + +____________________________________________________________ Bye. Hope to see you again soon! ____________________________________________________________ From f8ba7740a95b8b8854ccefe28bfa59ae780ec385 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Thu, 16 Mar 2023 10:23:09 +0800 Subject: [PATCH 061/210] fix save function for empty category map --- .../seedu/moneymind/storage/CategoryMapToString.java | 9 ++++++--- src/test/java/seedu/moneymind/StorageTest.java | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/moneymind/storage/CategoryMapToString.java b/src/main/java/seedu/moneymind/storage/CategoryMapToString.java index 34126aafb1..26dbd54b1e 100644 --- a/src/main/java/seedu/moneymind/storage/CategoryMapToString.java +++ b/src/main/java/seedu/moneymind/storage/CategoryMapToString.java @@ -15,9 +15,12 @@ public class CategoryMapToString { * @return String of categoryMap */ public static String categoryMapToString() { - String output = STORAGE_CATEGORY_MAP + NEW_LINE; - for (String key : categoryMap.keySet()) { - output += STORAGE_NEXT_VARIABLE + key + STORAGE_NEXT_VARIABLE + categoryMap.get(key) + NEW_LINE; + String output = ""; + if (!categoryMap.isEmpty()) { + output = STORAGE_CATEGORY_MAP + NEW_LINE; + for (String key : categoryMap.keySet()) { + output += STORAGE_NEXT_VARIABLE + key + STORAGE_NEXT_VARIABLE + categoryMap.get(key) + NEW_LINE; + } } return output; } diff --git a/src/test/java/seedu/moneymind/StorageTest.java b/src/test/java/seedu/moneymind/StorageTest.java index 0a18f63086..6160ff71df 100644 --- a/src/test/java/seedu/moneymind/StorageTest.java +++ b/src/test/java/seedu/moneymind/StorageTest.java @@ -71,7 +71,9 @@ public void loadFromFile_null_noExceptionThrown() { try { Storage storage = new Storage(); ArrayList list = storage.loadFromFile(); - System.out.println(list); + if (!list.isEmpty()) { + System.out.println(list); + } } catch (Exception e) { assertTrue(false, e.getMessage()); } From 9611736e3fa9670ba6c1760530dda1e383682c33 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Thu, 16 Mar 2023 15:49:10 +0800 Subject: [PATCH 062/210] add logger to Storage.java --- src/main/java/seedu/moneymind/storage/Storage.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/seedu/moneymind/storage/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java index 99dc730030..80558f51fe 100644 --- a/src/main/java/seedu/moneymind/storage/Storage.java +++ b/src/main/java/seedu/moneymind/storage/Storage.java @@ -4,6 +4,7 @@ import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Scanner; +import java.util.logging.Logger; import java.io.FileWriter; import java.io.IOException; @@ -20,6 +21,7 @@ public class Storage { private static File textFile; private static String filePath = "EventList.txt"; + private static Logger logger = Logger.getLogger("Storage"); /** * Constructor for Storage class @@ -32,12 +34,15 @@ public Storage() { * Sets up the file to be read and written to */ private static void setupFile() { + logger.info("Setting up file"); + // create file object textFile = new File(filePath); // create file if it does not exist try { textFile.createNewFile(); } catch (IOException e) { + logger.warning("File already exists"); System.out.println("The file already exists."); } } @@ -56,6 +61,7 @@ public void saveToFile(ArrayList list) { dukeWriter.write(writeToFile); dukeWriter.close(); } catch (IOException e) { + logger.warning("File cannot be accessed"); System.out.println("I cannot seem to access the saved file. Did you perhaps delete it?"); } } @@ -77,6 +83,7 @@ public ArrayList loadFromFile() { fileString += textFileScanner.nextLine() + System.lineSeparator(); } } catch (FileNotFoundException e) { + logger.warning("File cannot be accessed"); System.out.println("I cannot seem to access the saved tasks. Did you perhaps lock it away?"); } // split fileString into 2 parts using STORAGE_CATEGORY_MAP @@ -84,6 +91,7 @@ public ArrayList loadFromFile() { // convert fileString to ArrayList of Category ArrayList savedList = StringToCategory.stringToCategory(splitString[0]); if (splitString.length == 2) { + logger.info("Loading category map"); LoadToCategoryMap.loadToCategoryMap(splitString[1]); } return savedList; @@ -93,6 +101,7 @@ public ArrayList loadFromFile() { * Saves the current list of Category to EventList.txt file */ public void save() { + logger.info("Saving to file"); saveToFile(CategoryList.categories); } @@ -100,6 +109,7 @@ public void save() { * Loads the list of Category from EventList.txt file */ public void load() { + logger.info("Loading from file"); CategoryList.categories = loadFromFile(); } } From 284b95ae7814698df33b573a36dccdcaaec4cb50 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Fri, 17 Mar 2023 14:50:43 +0800 Subject: [PATCH 063/210] Remove extra InvalidCommandException --- src/main/java/seedu/moneymind/Moneymind.java | 1 + .../moneymind/command/InvalidCommandException.java | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 src/main/java/seedu/moneymind/command/InvalidCommandException.java diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index e0ece3fcfc..795604f9f9 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -36,6 +36,7 @@ public void run() { ui.goodbye(); isExit = true; } else { + assert !command.isExit() : "Command must exist"; command.execute(ui); // should also accept storage object as parameter } } catch (InvalidCommandException e) { diff --git a/src/main/java/seedu/moneymind/command/InvalidCommandException.java b/src/main/java/seedu/moneymind/command/InvalidCommandException.java deleted file mode 100644 index 874445d74f..0000000000 --- a/src/main/java/seedu/moneymind/command/InvalidCommandException.java +++ /dev/null @@ -1,13 +0,0 @@ -package seedu.moneymind.command; - -public class InvalidCommandException extends Exception { - private String errorMessage; - - public InvalidCommandException(String errorMessage) { - this.errorMessage = errorMessage; - } - - public void showErrorMessage() { - System.out.println(errorMessage); - } -} From 16172c90b2a1ed68e5eedfdfbb4547ce4ec5d783 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Fri, 17 Mar 2023 14:56:30 +0800 Subject: [PATCH 064/210] Update assertion message --- src/main/java/seedu/moneymind/Moneymind.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index 795604f9f9..c1ef40e06c 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -36,7 +36,7 @@ public void run() { ui.goodbye(); isExit = true; } else { - assert !command.isExit() : "Command must exist"; + assert !command.isExit() : "Command must have a valid execute method"; command.execute(ui); // should also accept storage object as parameter } } catch (InvalidCommandException e) { From f75f9bbbf0f23274b6d40b45d854b0afa109b2fe Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Sat, 18 Mar 2023 17:24:01 +0800 Subject: [PATCH 065/210] Enable the assertion in build.gradle --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 4ffd7f5e7d..eb15d4f52b 100644 --- a/build.gradle +++ b/build.gradle @@ -44,3 +44,7 @@ checkstyle { run{ standardInput = System.in } + +run{ + enableAssertions = true +} From 5f7b7be6be05c3acacddc8b550eed7611cd64f93 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Mon, 20 Mar 2023 22:38:07 +0800 Subject: [PATCH 066/210] Add the user guide to moneymind --- docs/UserGuide.md | 142 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 17 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..ea6b8c96f0 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,41 +2,149 @@ ## Introduction -{Give a product intro} +Moneymind is a Command Line Interface (CLI) application that +helps you manage your personal finances. +With Moneymind, you can keep track of your budgets, +expenses, and categorize them for better organization. ## Quick Start -{Give steps to get started quickly} +1. Download and install Moneymind on your computer and ensure that you have Java 11 or above installed. -1. Ensure that you have Java 11 or above installed. -1. Down the latest version of `Duke` from [here](http://link.to/duke). +2. Ensure you have Java11 or above installed on your computer. + +3. Open the terminal and navigate to the directory where Moneymind is installed. + +4. Run the following command to start the Moneymind app. + +5. Type the command in the command box and press Enter to execute. ## Features {Give detailed description of each feature} -### Adding a todo: `todo` -Adds a new item to the list of todo items. +### Add an Event: `event` +Add an event which is to be recorded by Moneymind. + +Format: `event NAME e/ [(opetional) t/

+

MoneyMind Developer Guide

+

"Mind your Money"

+
+ +
## Acknowledgements @@ -8,6 +13,9 @@ {Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +:smiley: You can use PlantUML to create UML diagrams like what we did in this documentation. See [Using PlantUML](https://se-education.org/guides/tutorials/plantUml.html) for more information. + + ## Product scope ### Target user profile @@ -20,10 +28,13 @@ ## 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** an one time expense | keep track of how much I spend | +| | user | **delete** a one time expense | ammend the record in case I add the wrong expense | +| | user | **categorize** my expenses into different categories such as food, transportation, entertainment, etc. | better understand where my money is going | +| v2.0 | user | **edit** one time expenses | change when I type wrongly | +| | user | **search** for specific expenses by keyword or date range | easily find and review my past spending | ## Non-Functional Requirements @@ -36,3 +47,5 @@ ## 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} + +
diff --git a/docs/diagrams/UML1.puml b/docs/diagrams/UML1.puml new file mode 100644 index 0000000000..56c2d2f0e5 --- /dev/null +++ b/docs/diagrams/UML1.puml @@ -0,0 +1,9 @@ +@startuml +!include Style.puml + +box Logic LOGIC_COLOR_T2 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":UndoCommand" as UndoCommand LOGIC_COLOR +end box +@enduml diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml new file mode 100644 index 0000000000..a08bc22c02 --- /dev/null +++ b/docs/diagrams/style.puml @@ -0,0 +1,5 @@ +!define LOGIC_COLOR #3333C4 +!define LOGIC_COLOR_T1 #7777DB +!define LOGIC_COLOR_T2 #5252CE +!define LOGIC_COLOR_T3 #1616B0 +!define LOGIC_COLOR_T4 #101086 From 079d5cbeba0fc50c0ac277e7e44cec1ef2457e4a Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Tue, 21 Mar 2023 12:28:33 +0800 Subject: [PATCH 068/210] Update the DG --- docs/DeveloperGuide.md | 16 ++++++++++++++++ docs/diagrams/Architecture.puml | 22 ++++++++++++++++++++++ docs/diagrams/UML1.puml | 9 --------- docs/diagrams/style.puml | 1 + docs/images/Architecture.png | Bin 0 -> 18671 bytes 5 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 docs/diagrams/Architecture.puml delete mode 100644 docs/diagrams/UML1.puml create mode 100644 docs/images/Architecture.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0c9bd80783..b22a31ee44 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -15,6 +15,22 @@ :smiley: You can use PlantUML to create UML diagrams like what we did in this documentation. See [Using PlantUML](https://se-education.org/guides/tutorials/plantUml.html) for more information. +### Architecture + + + +The ***Architecture Diagram*** given above explains the high-level design of the App. + +Given below is a quick overview of how each component interact with each other. + +The main components in the architecture are: + +* `MoneyMind`: The main program of the application, +it initializes the other components in the correct sequence and is responsible for shut down the application. +* `UI`: The user interface of the application. +* `Storage`: The storage of data of the application. +* `Data`: The data classes used in the application, including Event, Category and CategoryList. +* `Command`: The command of the application, including AddCommand, DeleteCommand, ListCommand, etc. ## Product scope diff --git a/docs/diagrams/Architecture.puml b/docs/diagrams/Architecture.puml new file mode 100644 index 0000000000..2182d9992e --- /dev/null +++ b/docs/diagrams/Architecture.puml @@ -0,0 +1,22 @@ +@startuml +!include Style.puml +!include +!include +!theme cerulean + +package " "<> { + class MoneyMind + class UI + class Storage + class Command + class Data +} + +MoneyMind --> UI +Storage ..> MoneyMind +Storage --> Data +Data --> Storage +MoneyMind --> Command +Command --> Data + +@enduml diff --git a/docs/diagrams/UML1.puml b/docs/diagrams/UML1.puml deleted file mode 100644 index 56c2d2f0e5..0000000000 --- a/docs/diagrams/UML1.puml +++ /dev/null @@ -1,9 +0,0 @@ -@startuml -!include Style.puml - -box Logic LOGIC_COLOR_T2 -participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR -participant ":UndoCommand" as UndoCommand LOGIC_COLOR -end box -@enduml diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml index a08bc22c02..9ba64e89fb 100644 --- a/docs/diagrams/style.puml +++ b/docs/diagrams/style.puml @@ -3,3 +3,4 @@ !define LOGIC_COLOR_T2 #5252CE !define LOGIC_COLOR_T3 #1616B0 !define LOGIC_COLOR_T4 #101086 + diff --git a/docs/images/Architecture.png b/docs/images/Architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..27f8e75dd0feb3b93e65743995b11878133729ca GIT binary patch literal 18671 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 e-+x$quQAVrK8+2d&8*z4k`R#Mk1q literal 0 HcmV?d00001 From dee2f1dd634c4c00e89c17114a976e5d2bd5825b Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Tue, 21 Mar 2023 12:34:45 +0800 Subject: [PATCH 069/210] Ammend the Architecture diagram and update the README.md --- docs/README.md | 6 +++--- docs/images/Architecture.png | Bin 18671 -> 23046 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index bbcc99c1e7..c8a9238d1b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,8 @@ -# Duke +# MoneyMind -{Give product intro here} +MoneyMind is a desktop application for managing your finances, 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, MoneyMind can get your finance management tasks done faster than traditional GUI apps. -Useful links: +To get to know more about MoneyMind, here are the useful links: * [User Guide](UserGuide.md) * [Developer Guide](DeveloperGuide.md) * [About Us](AboutUs.md) diff --git a/docs/images/Architecture.png b/docs/images/Architecture.png index 27f8e75dd0feb3b93e65743995b11878133729ca..63af3ed35dea52390103181b0962bd1ff7c7acaf 100644 GIT binary patch literal 23046 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 G{op?c;&ZV8 literal 18671 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 e-+x$quQAVrK8+2d&8*z4k`R#Mk1q From 7c449b354e2266d47d34835d027dc53fb0ccb1d5 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Tue, 21 Mar 2023 12:36:34 +0800 Subject: [PATCH 070/210] Update the Architecture diagram --- docs/DeveloperGuide.md | 2 +- .../{Architecture.png => ArchitectureDiagram.png} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/images/{Architecture.png => ArchitectureDiagram.png} (100%) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index b22a31ee44..0cea082434 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -17,7 +17,7 @@ ### Architecture - + The ***Architecture Diagram*** given above explains the high-level design of the App. diff --git a/docs/images/Architecture.png b/docs/images/ArchitectureDiagram.png similarity index 100% rename from docs/images/Architecture.png rename to docs/images/ArchitectureDiagram.png From cdb7d6930d300f1896e42f3514d2cfe817bcdfba Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 21 Mar 2023 17:15:23 +0800 Subject: [PATCH 071/210] Add search command --- .../java/seedu/moneymind/command/Parser.java | 8 +++ .../moneymind/command/SearchCommand.java | 53 +++++++++++++++++++ .../java/seedu/moneymind/string/Strings.java | 2 + 3 files changed, 63 insertions(+) create mode 100644 src/main/java/seedu/moneymind/command/SearchCommand.java diff --git a/src/main/java/seedu/moneymind/command/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java index 94e52e7f8b..5be7096a2b 100644 --- a/src/main/java/seedu/moneymind/command/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -1,5 +1,6 @@ package seedu.moneymind.command; +import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -14,6 +15,7 @@ import static seedu.moneymind.string.Strings.DELETE; import static seedu.moneymind.string.Strings.EVENT; import static seedu.moneymind.string.Strings.CATEGORY; +import static seedu.moneymind.string.Strings.SEARCH; import static seedu.moneymind.string.Strings.INVALID_INPUT; import static seedu.moneymind.string.Strings.DELETE_FORMAT; import static seedu.moneymind.string.Strings.REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY; @@ -54,6 +56,8 @@ public Command parseNextCommand(String input) throws Exception { return createEventCommand(separatedKeywordAndDescription); case CATEGORY: return createCategoryCommand(separatedKeywordAndDescription); + case SEARCH: + return createSearchCommand(separatedKeywordAndDescription); default: throw new InvalidCommandException(INVALID_INPUT); } @@ -146,4 +150,8 @@ private Command createCategoryCommand(String[] separatedKeywordAndDescription) t throw new InvalidCommandException(CATEGORY_EMPTY); } } + + private Command createSearchCommand(String[] separatedKeywordAndDescription) throws InvalidCommandException { + return new SearchCommand(separatedKeywordAndDescription[1]); + } } diff --git a/src/main/java/seedu/moneymind/command/SearchCommand.java b/src/main/java/seedu/moneymind/command/SearchCommand.java new file mode 100644 index 0000000000..01ec4fcf64 --- /dev/null +++ b/src/main/java/seedu/moneymind/command/SearchCommand.java @@ -0,0 +1,53 @@ +package seedu.moneymind.command; + +import seedu.moneymind.category.Category; +import seedu.moneymind.event.Event; +import seedu.moneymind.ui.Ui; + +import java.util.ArrayList; + +import static seedu.moneymind.category.CategoryList.categories; +import static seedu.moneymind.string.Strings.DOT; +import static seedu.moneymind.string.Strings.NO_SEARCH_RESULTS; + +public class SearchCommand implements Command{ + private final String word; + + public SearchCommand(String word) { + this.word = word; + } + + @Override + public void execute(Ui ui) { + boolean hasMatch = false; + for (Category category : categories) { + boolean isMatch = false; + ArrayList matchedEvents = new ArrayList<>(); + if (category.getName().contains(word)) { + isMatch = true; + hasMatch = true; + } + for (Event event : category.events) { + if (event.getDescription().contains(word)) { + matchedEvents.add(event); + hasMatch = true; + } + } + if (isMatch || matchedEvents.size() != 0) { + int categoryIndex = CategoryCommand.categoryMap.get(category.getName()); + System.out.println((categoryIndex + 1) + DOT + category.getName()); + for (Event event : matchedEvents) { + System.out.println(event.toString()); + } + } + } + if (!hasMatch) { + System.out.println(NO_SEARCH_RESULTS); + } + } + + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/seedu/moneymind/string/Strings.java b/src/main/java/seedu/moneymind/string/Strings.java index 2d1736f2f5..f5a3538a13 100644 --- a/src/main/java/seedu/moneymind/string/Strings.java +++ b/src/main/java/seedu/moneymind/string/Strings.java @@ -4,6 +4,7 @@ public class Strings { public static final String NO_CATEGORY_MESSAGE = "Category does not exist"; public static final String DOT = "."; public static final String NO_CATEGORIES_TO_VIEW = "There are no categories to view"; + public static final String NO_SEARCH_RESULTS = "No matching search results."; public static final String COUNT_ASSERTION = "Count should be greater than 1"; public static final String NULL_CATEGORY_ASSERTION = "Category name should not be null"; public static final String NULL_CATEGORY_LIST_ASSERTION = "Category list should not be null"; @@ -44,6 +45,7 @@ public class Strings { public static final String DELETE = "delete"; public static final String EVENT = "event"; public static final String CATEGORY = "category"; + public static final String SEARCH = "search"; public static final String INVALID_INPUT = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; public static final String DELETE_FORMAT = "Please following the correct format: " + "delete c/ e/" + From e69696ac678d9409635b0ac3171f4e8497ff2dd6 Mon Sep 17 00:00:00 2001 From: Li Mingyuan Date: Tue, 21 Mar 2023 17:16:35 +0800 Subject: [PATCH 072/210] Remove redundant import --- src/main/java/seedu/moneymind/command/Parser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/moneymind/command/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java index 5be7096a2b..b9abc7a0b5 100644 --- a/src/main/java/seedu/moneymind/command/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -1,6 +1,5 @@ package seedu.moneymind.command; -import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; From d8c626bdf614f2e3a70709a64814307a2c0e6786 Mon Sep 17 00:00:00 2001 From: alexgoexercise Date: Wed, 22 Mar 2023 00:27:56 +0800 Subject: [PATCH 073/210] Add budget to category --- .../java/seedu/moneymind/category/Category.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/moneymind/category/Category.java b/src/main/java/seedu/moneymind/category/Category.java index 4a7bcdb6f2..1dad403bad 100644 --- a/src/main/java/seedu/moneymind/category/Category.java +++ b/src/main/java/seedu/moneymind/category/Category.java @@ -10,6 +10,8 @@ public class Category { private String name; + private int budget; + /** * A constructor with name. */ @@ -17,6 +19,14 @@ public Category(String name) { this.name = name; } + /** + * A constructor with name and budget. + */ + public Category(String name, int budget) { + this.name = name; + this.budget = budget; + } + /** * Gets the name of the category. * @@ -91,8 +101,9 @@ public void editEvent(int index, String description, int budget, int expense) { public int getTotalBudget() { int totalBudget = 0; for (int i = 0; i < events.size(); i++) { - totalBudget += events.get(i).getBudget(); + totalBudget += events.get(i).getBudget(); // add the budget of each event, which is 0 by default } + totalBudget += budget; // add the budget of the category return totalBudget; } From 4e0115874a8f0c7efe79afa2b7380a08acc6f5e3 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Wed, 22 Mar 2023 16:54:45 +0800 Subject: [PATCH 074/210] update DG for storage --- docs/DeveloperGuide.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0cea082434..4a4199c0d5 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -32,6 +32,18 @@ it initializes the other components in the correct sequence and is responsible f * `Data`: The data classes used in the application, including Event, Category and CategoryList. * `Command`: The command of the application, including AddCommand, DeleteCommand, ListCommand, etc. +The following sections will explain the architecture in more detail. + +## Storage component + +**API**: `Storage.java` + +{UML class diagram} + +The `Storage` component, +* can save category and event data in txt format, and read it back. (txt format is chosen because it is human readable) +* depends on `CategoryList.java` and `CategoryCommand.java` to save and load data from ArrayList and HashMap. + ## Product scope ### Target user profile From da1fdbcbdd62a7fd83daa8259a064f605475da91 Mon Sep 17 00:00:00 2001 From: Toh-HongFeng Date: Wed, 22 Mar 2023 20:06:42 +0800 Subject: [PATCH 075/210] add getSystemDate method --- src/main/java/seedu/moneymind/UserDate.java | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/seedu/moneymind/UserDate.java diff --git a/src/main/java/seedu/moneymind/UserDate.java b/src/main/java/seedu/moneymind/UserDate.java new file mode 100644 index 0000000000..bb8229afd1 --- /dev/null +++ b/src/main/java/seedu/moneymind/UserDate.java @@ -0,0 +1,22 @@ +package seedu.moneymind; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +// import java.time.temporal.ChronoUnit; + +/** + * Retrieves the current system date and time. + */ +public class UserDate { + // TODO: Clean up and test code + // private int day; + // private int month; + // private int year; + + public static String getSystemDate() { + LocalDate now = LocalDate.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + String formattedDate = now.format(formatter); + return formattedDate; + } +} From 1d185f8caaeac6a9f46a42542ec2246bc795f348 Mon Sep 17 00:00:00 2001 From: Mnsd05 Date: Thu, 23 Mar 2023 01:05:37 +0800 Subject: [PATCH 076/210] Update different commands for version 2 --- docs/DeveloperGuide.md | 31 +++++ src/main/java/seedu/moneymind/Moneymind.java | 10 +- .../seedu/moneymind/category/Category.java | 97 ++++++++------- .../moneymind/command/CategoryCommand.java | 11 +- .../moneymind/command/DeleteCommand.java | 24 ++-- .../seedu/moneymind/command/EditCommand.java | 91 ++++++++++++++ .../seedu/moneymind/command/EventCommand.java | 24 ++-- .../java/seedu/moneymind/command/Parser.java | 116 ++++++++++++------ .../seedu/moneymind/command/ViewCommand.java | 2 +- .../java/seedu/moneymind/event/Event.java | 80 ++++++------ .../storage/CategoryMapToString.java | 27 ---- .../moneymind/storage/CategoryToString.java | 32 ----- .../seedu/moneymind/storage/FormatToTxt.java | 24 ---- .../moneymind/storage/LoadToCategoryMap.java | 23 ---- .../java/seedu/moneymind/storage/Storage.java | 114 ----------------- .../moneymind/storage/StringToCategory.java | 45 ------- .../java/seedu/moneymind/string/Strings.java | 8 +- 17 files changed, 338 insertions(+), 421 deletions(-) create mode 100644 src/main/java/seedu/moneymind/command/EditCommand.java delete mode 100644 src/main/java/seedu/moneymind/storage/CategoryMapToString.java delete mode 100644 src/main/java/seedu/moneymind/storage/CategoryToString.java delete mode 100644 src/main/java/seedu/moneymind/storage/FormatToTxt.java delete mode 100644 src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java delete mode 100644 src/main/java/seedu/moneymind/storage/Storage.java delete mode 100644 src/main/java/seedu/moneymind/storage/StringToCategory.java diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0cea082434..6f7e7757db 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -32,6 +32,37 @@ it initializes the other components in the correct sequence and is responsible f * `Data`: The data classes used in the application, including Event, Category and CategoryList. * `Command`: The command of the application, including AddCommand, DeleteCommand, ListCommand, etc. +The following sections will explain the architecture in more detail. + +## Storage component + +**API**: `Storage.java` + +{UML class diagram} + +The `Storage` component, +* can save category and event data in txt format, and read it back. (txt format is chosen because it is human readable) +* depends on `CategoryList.java` and `CategoryCommand.java` to save and load data from ArrayList and HashMap. + +## Commands component + +**API**: `Command.java` + +{UML class diagram} + +The `Command` component, +* can execute different commands, such as adding category, adding event, deleting category, deleting event, viewing category, viewing event +* depends on `CategoryList.java`, `CategoryCommand.java`, `Event.java`, `Parser.java` to execute the commands. + +## Parser component + +**API**: `Parser.java` + +{UML class diagram} + +The `Parser` component, +* can parse the user input and process it to the correct format +* depends on `CategoryList.java`, `CategoryCommand.java`, `Event.java`, `Command.java` to execute the commands. ## Product scope ### Target user profile diff --git a/src/main/java/seedu/moneymind/Moneymind.java b/src/main/java/seedu/moneymind/Moneymind.java index c1ef40e06c..f257301ae1 100644 --- a/src/main/java/seedu/moneymind/Moneymind.java +++ b/src/main/java/seedu/moneymind/Moneymind.java @@ -5,20 +5,20 @@ import seedu.moneymind.command.Command; import seedu.moneymind.exceptions.InvalidCommandException; import seedu.moneymind.command.Parser; -import seedu.moneymind.storage.Storage; +//import seedu.moneymind.storage.Storage; import seedu.moneymind.string.Strings; import seedu.moneymind.ui.Ui; public class Moneymind { public static Scanner in; private Parser parser; - private Storage storage; +// private Storage storage; private Ui ui; private String userInput; public Moneymind() { this.parser = new Parser(); - this.storage = new Storage(); +// this.storage = new Storage(); this.ui = new Ui(); this.in = new Scanner(System.in); } @@ -26,7 +26,7 @@ public Moneymind() { public void run() { ui.greet(); boolean isExit = false; - storage.load(); +// storage.load(); while (!isExit) { try { getInput(); @@ -45,7 +45,7 @@ public void run() { ui.error(e); } } - storage.save(); +// storage.save(); } private void getInput() { diff --git a/src/main/java/seedu/moneymind/category/Category.java b/src/main/java/seedu/moneymind/category/Category.java index 1dad403bad..34aaa82555 100644 --- a/src/main/java/seedu/moneymind/category/Category.java +++ b/src/main/java/seedu/moneymind/category/Category.java @@ -67,46 +67,49 @@ public void viewEventList() { } } - /** - * to edit the parameters of the event. - * - * @param index the index of the event in the list - * @param description the description of the event - * @param budget the budget of the event - */ - public void editEvent(int index, String description, int budget) { - events.get(index).setDescription(description); - events.get(index).setBudget(budget); - } - - /** - * to edit the parameters of the event. - * - * @param index the index of the event in the list - * @param description the description of the event - * @param budget the budget of the event - * @param expense the expense of the event - */ - public void editEvent(int index, String description, int budget, int expense) { - events.get(index).setDescription(description); - events.get(index).setBudget(budget); - events.get(index).setExpense(expense); - } - - /** - * Gets the total expense of the category. - * - * @return the total expense of the category - */ - public int getTotalBudget() { - int totalBudget = 0; - for (int i = 0; i < events.size(); i++) { - totalBudget += events.get(i).getBudget(); // add the budget of each event, which is 0 by default - } - totalBudget += budget; // add the budget of the category - return totalBudget; +// /** +// * to edit the parameters of the event. +// * +// * @param index the index of the event in the list +// * @param description the description of the event +// * @param budget the budget of the event +// */ +// public void editEvent(int index, String description, int budget) { +// events.get(index).setDescription(description); +// events.get(index).setBudget(budget); +// } +// +// /** +// * to edit the parameters of the event. +// * +// * @param index the index of the event in the list +// * @param description the description of the event +// * @param budget the budget of the event +// * @param expense the expense of the event +// */ +// public void editEvent(int index, String description, int budget, int expense) { +// events.get(index).setDescription(description); +// events.get(index).setBudget(budget); +// events.get(index).setExpense(expense); +// } +// +// /** +// * Gets the total expense of the category. +// * +// * @return the total expense of the category +// */ +// public int getTotalBudget() { +// int totalBudget = 0; +// for (int i = 0; i < events.size(); i++) { +// totalBudget += events.get(i).getBudget(); // add the budget of each event, which is 0 by default +// } +// totalBudget += budget; // add the budget of the category +// return totalBudget; +// } + + public int getBudget() { + return budget; } - /** * Gets the total expense of the category. * @@ -120,12 +123,12 @@ public int getTotalExpense() { return totalExpense; } - /** - * Gets the remaining budget of the category. - * - * @return the remaining budget of the category - */ - public int getRemainingBudget() { - return getTotalBudget() - getTotalExpense(); - } +// /** +// * Gets the remaining budget of the category. +// * +// * @return the remaining budget of the category +// */ +// public int getRemainingBudget() { +// return getTotalBudget() - getTotalExpense(); +// } } diff --git a/src/main/java/seedu/moneymind/command/CategoryCommand.java b/src/main/java/seedu/moneymind/command/CategoryCommand.java index b70bb65039..79c68db4a8 100644 --- a/src/main/java/seedu/moneymind/command/CategoryCommand.java +++ b/src/main/java/seedu/moneymind/command/CategoryCommand.java @@ -14,14 +14,16 @@ public class CategoryCommand implements Command { public static HashMap categoryMap = new HashMap(); private final String name; + private int budget; /** * Constructs a new CategoryCommand object and adds the category. * * @param name the name of the category */ - public CategoryCommand(String name) { + public CategoryCommand(String name, int budget) { this.name = name; + this.budget = budget; } /** @@ -33,7 +35,12 @@ public void execute(Ui ui) { System.out.println(Strings.EXISTED_CATEGORY); return; } - Category category = new Category(name); + Category category; + if (budget == 0) { + category = new Category(name); + } else { + category = new Category(name, budget); + } CategoryList.categories.add(category); categoryMap.put(name, CategoryList.categories.size() - 1); System.out.println("New category added: " + name); diff --git a/src/main/java/seedu/moneymind/command/DeleteCommand.java b/src/main/java/seedu/moneymind/command/DeleteCommand.java index 2847f44749..6290963bb1 100644 --- a/src/main/java/seedu/moneymind/command/DeleteCommand.java +++ b/src/main/java/seedu/moneymind/command/DeleteCommand.java @@ -15,7 +15,7 @@ public class DeleteCommand implements Command { public static final String NULL_CATEGORY_ASSERTION = "Category name should not be null"; public static final String NULL_EVENT_ASSERTION = "Event name should not be null"; private String categoryName; - private String eventName; + private int eventIndex; private boolean isEvent; /** @@ -24,11 +24,10 @@ public class DeleteCommand implements Command { * @param categoryName the name of the category * @param eventName the name of the event */ - public DeleteCommand(String categoryName, String eventName) { + public DeleteCommand(String categoryName, int eventIndex) { this.categoryName = categoryName; - this.eventName = eventName; + this.eventIndex = eventIndex; assert categoryName != null : NULL_CATEGORY_ASSERTION; - assert eventName != null : NULL_EVENT_ASSERTION; this.isEvent = true; } @@ -47,26 +46,19 @@ public DeleteCommand(String categoryName) { * Deletes the event. */ private void deleteEvent() { - boolean isEventDeleted = false; if (CategoryCommand.categoryMap.get(categoryName) == null) { System.out.println(NO_CATEGORY_MESSAGE); return; } int categoryIndex = CategoryCommand.categoryMap.get(categoryName); Category category = CategoryList.categories.get(categoryIndex); - int eventIndex = 0; - while (eventIndex < category.getEvents().size()) { - if (category.getEvents().get(eventIndex).getDescription().equals(eventName)) { - category.getEvents().remove(eventIndex); - System.out.println(EVENT_DELETION_MESSAGE + eventName); - isEventDeleted = true; - --eventIndex; - } - ++eventIndex; - } - if (!isEventDeleted) { + if (eventIndex >= category.getEvents().size()) { System.out.println(NON_EXISTENT_EVENT); + return; } + String eventName = category.getEvents().get(eventIndex).getDescription(); + category.getEvents().remove(eventIndex); + System.out.println(EVENT_DELETION_MESSAGE + eventName); } /** diff --git a/src/main/java/seedu/moneymind/command/EditCommand.java b/src/main/java/seedu/moneymind/command/EditCommand.java new file mode 100644 index 0000000000..398086cb3c --- /dev/null +++ b/src/main/java/seedu/moneymind/command/EditCommand.java @@ -0,0 +1,91 @@ +package seedu.moneymind.command; + +import seedu.moneymind.Moneymind; +import seedu.moneymind.category.Category; +import seedu.moneymind.category.CategoryList; +import seedu.moneymind.exceptions.NegativeNumberException; +import seedu.moneymind.ui.Ui; + +import static seedu.moneymind.command.DeleteCommand.NON_EXISTENT_EVENT; +import static seedu.moneymind.string.Strings.*; +import static seedu.moneymind.string.Strings.SUBTLE_BUG_MESSAGE; + +public class EditCommand implements Command { + private String categoryName; + private int eventIndex; + private boolean isReady = false; + private int categoryIndex; + public EditCommand (String categoryName, int eventIndex) { + this.categoryName = categoryName; + this.eventIndex = eventIndex; + } + + private void editEvent() { + if (CategoryCommand.categoryMap.get(categoryName) == null) { + System.out.println(NO_CATEGORY_MESSAGE); + return; + } + categoryIndex = CategoryCommand.categoryMap.get(categoryName); + Category category = CategoryList.categories.get(categoryIndex); + if (eventIndex >= category.getEvents().size()) { + System.out.println(NON_EXISTENT_EVENT); + return; + } + String eventName = category.getEvents().get(eventIndex).getDescription(); + System.out.println("The current event expense for " + eventName + " is: " + + category.getEvents().get(eventIndex).getExpense()); + System.out.println("Your new expense would be: "); + isReady = true; + } + + private void checkNegative(int newExpense) throws NegativeNumberException { + if (newExpense < 0) { + throw new NegativeNumberException(); + } + } + /** + * Check if the user input is valid. + * + * @param userInput The user input. + * @return True if the user input is valid. + */ + private boolean isEditSuccessful(String userInput) { + try { + int newExpense = Integer.parseInt(userInput); + checkNegative(newExpense); + return true; + } catch (NumberFormatException error) { + System.out.println(REMINDING_MESSAGE_TO_GIVE_A_NUMBER); + } catch (NegativeNumberException error) { + System.out.println("Please enter a non-negative number"); + } catch (Exception error) { + System.out.println(SUBTLE_BUG_MESSAGE); + } + return false; + } + + @Override + public void execute(Ui ui) { + editEvent(); + if (isReady) { + String userInput; + userInput = Moneymind.in.nextLine(); + while (!isEditSuccessful(userInput)) { + System.out.println(GO_BACK_MESSAGE); + userInput = Moneymind.in.nextLine(); + if (userInput.equals(BACK)) { + break; + } + } + System.out.println("Ok, the new expense is now changed to: " + userInput); + CategoryList.categories.get(categoryIndex).getEvents().get(eventIndex).setExpense(Integer.parseInt(userInput)); + } + + } + + @Override + public boolean isExit() { + return false; + } + +} diff --git a/src/main/java/seedu/moneymind/command/EventCommand.java b/src/main/java/seedu/moneymind/command/EventCommand.java index d76e0b0b93..f8e1175da5 100644 --- a/src/main/java/seedu/moneymind/command/EventCommand.java +++ b/src/main/java/seedu/moneymind/command/EventCommand.java @@ -23,22 +23,29 @@ */ public class EventCommand implements Command { private String eventName; - private int budget; + private String time; private int expense; /** * Constructor for EventCommand. * * @param eventName The name of the event. - * @param budget The budget of the event. * @param expense The expense of the event. + * @param time The time of the event. */ - public EventCommand(String eventName, int budget, int expense) { + public EventCommand(String eventName, int expense, String time) { this.eventName = eventName; - this.budget = budget; this.expense = expense; + this.time = time; + assert eventName != null : NULL_EVENT_ASSERTION; + assert expense >= 0 : NON_NEGATIVE_EXPENSE_ASSERTION; + } + + public EventCommand(String eventName, int expense) { + this.eventName = eventName; + this.expense = expense; + this.time = ""; assert eventName != null : NULL_EVENT_ASSERTION; - assert budget >= 0 : NON_NEGATIVE_BUDGET_ASSERTION; assert expense >= 0 : NON_NEGATIVE_EXPENSE_ASSERTION; } @@ -62,7 +69,11 @@ private boolean isChooseCategorySuccessful(String userInput) { try { int categoryPosition = Integer.parseInt(userInput); testCategoryNumber(categoryPosition); - addEventToCategory(categoryPosition, new Event(eventName, budget, expense)); + if (time == "") { + addEventToCategory(categoryPosition, new Event(eventName, expense)); + } else { + addEventToCategory(categoryPosition, new Event(eventName, expense, time)); + } return true; } catch (NumberFormatException e) { System.out.println(REMINDING_MESSAGE_TO_GIVE_A_NUMBER); @@ -88,7 +99,6 @@ private void testCategoryNumber(int categoryPosition) throws InvalidCategoryNumb @Override public void execute(Ui ui) { - Event event = new Event(eventName, budget, expense); System.out.println(SELECTING_CATEGORY_MESSAGE); String userInput; userInput = Moneymind.in.nextLine(); diff --git a/src/main/java/seedu/moneymind/command/Parser.java b/src/main/java/seedu/moneymind/command/Parser.java index b9abc7a0b5..217993f1f3 100644 --- a/src/main/java/seedu/moneymind/command/Parser.java +++ b/src/main/java/seedu/moneymind/command/Parser.java @@ -6,28 +6,7 @@ import seedu.moneymind.exceptions.InvalidCommandException; import seedu.moneymind.exceptions.NegativeNumberException; - -import static seedu.moneymind.string.Strings.WHITE_SPACE; -import static seedu.moneymind.string.Strings.BYE; -import static seedu.moneymind.string.Strings.HELP; -import static seedu.moneymind.string.Strings.VIEW; -import static seedu.moneymind.string.Strings.DELETE; -import static seedu.moneymind.string.Strings.EVENT; -import static seedu.moneymind.string.Strings.CATEGORY; -import static seedu.moneymind.string.Strings.SEARCH; -import static seedu.moneymind.string.Strings.INVALID_INPUT; -import static seedu.moneymind.string.Strings.DELETE_FORMAT; -import static seedu.moneymind.string.Strings.REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY; -import static seedu.moneymind.string.Strings.SUBTLE_BUG_MESSAGE; -import static seedu.moneymind.string.Strings.EVENT_REGEX; -import static seedu.moneymind.string.Strings.EVENT_FORMAT; -import static seedu.moneymind.string.Strings.EVENT_EMPTY; -import static seedu.moneymind.string.Strings.CATEGORY_EMPTY; -import static seedu.moneymind.string.Strings.NULL_INPUT_ASSERTION; -import static seedu.moneymind.string.Strings.NULL_DESCRIPTION; -import static seedu.moneymind.string.Strings.DELETE_REGEX; -import static seedu.moneymind.string.Strings.EMPTY_DELETION; -import static seedu.moneymind.string.Strings.REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER; +import static seedu.moneymind.string.Strings.*; /** * A class to parse the user input. @@ -57,6 +36,8 @@ public Command parseNextCommand(String input) throws Exception { return createCategoryCommand(separatedKeywordAndDescription); case SEARCH: return createSearchCommand(separatedKeywordAndDescription); + case "edit": + return createEditCommand(separatedKeywordAndDescription); default: throw new InvalidCommandException(INVALID_INPUT); } @@ -98,17 +79,26 @@ private Command createDeleteCommand(String[] separatedKeywordAndDescription) thr throw new InvalidCommandException(EMPTY_DELETION); } Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); - if (matcher.find()) { - String categoryName = matcher.group(1); - String eventName = matcher.group(2); - if (eventName == null) { - return new DeleteCommand(categoryName); - } else if (eventName.isEmpty()) { + try { + if (matcher.find()) { + String categoryName = matcher.group(1); + if (matcher.group(2) == null) { + return new DeleteCommand(categoryName); + } + int eventIndex = Integer.parseInt(matcher.group(2)); + checkNegative(eventIndex - 1); + return new DeleteCommand(categoryName, eventIndex - 1); + } else { throw new InvalidCommandException(DELETE_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } - return new DeleteCommand(categoryName, eventName); - } else { + } catch (NumberFormatException error) { + throw new InvalidCommandException("Please give a positive integer for event index"); + } catch (NegativeNumberException error) { + throw new InvalidCommandException("Please give a positive integer for event index"); + } catch (InvalidCommandException error) { throw new InvalidCommandException(DELETE_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + } catch (Exception error) { + throw new InvalidCommandException(SUBTLE_BUG_MESSAGE); } } @@ -118,17 +108,22 @@ private Command createEventCommand(String[] separatedKeywordAndDescription) thro Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); if (matcher.find()) { String eventName = matcher.group(1); - String budgetNumber = matcher.group(2); - String expenseNumber = matcher.group(3); - checkNegativeBudgetAndExpense(Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); - return new EventCommand(eventName, Integer.parseInt(budgetNumber), Integer.parseInt(expenseNumber)); + int expenseNumber = Integer.parseInt(matcher.group(2)); + String time = matcher.group(3); + checkNegative(expenseNumber); + if (matcher.group(3) == null) { + return new EventCommand(eventName, expenseNumber); + } + return new EventCommand(eventName, expenseNumber, time); } else { throw new InvalidCommandException(""); } } catch (IndexOutOfBoundsException error) { throw new InvalidCommandException(EVENT_EMPTY); } catch (NegativeNumberException error) { - throw new InvalidCommandException(REMINDING_MESSAGE_ABOUT_GIVING_POSITIVE_NUMBER); + throw new InvalidCommandException("Please give a positive integer for expense"); + } catch (NumberFormatException error) { + throw new InvalidCommandException("Please give a positive integer for expense"); } catch (InvalidCommandException error) { throw new InvalidCommandException(EVENT_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); } catch (Exception error) { @@ -136,17 +131,62 @@ private Command createEventCommand(String[] separatedKeywordAndDescription) thro } } - private void checkNegativeBudgetAndExpense(int budget, int expense) throws NegativeNumberException { - if (budget < 0 || expense < 0) { + private Command createEditCommand(String[] separatedKeywordAndDescription) throws InvalidCommandException { + Pattern pattern = Pattern.compile(EDIT_REGEX); + try { + Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + if (matcher.find()) { + String categoryName = matcher.group(1); + int eventIndex = Integer.parseInt(matcher.group(2)); + checkNegative(eventIndex - 1); + return new EditCommand(categoryName, eventIndex - 1); + } else { + throw new InvalidCommandException(""); + } + } catch (IndexOutOfBoundsException error) { + throw new InvalidCommandException("OOPS!!! The description of a edit cannot be empty."); + } catch (NegativeNumberException error) { + throw new InvalidCommandException("Please give a positive integer for expense"); + } catch (NumberFormatException error) { + throw new InvalidCommandException("Please give a positive integer for expense"); + } catch (InvalidCommandException error) { + throw new InvalidCommandException("wrong format for edit" + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + } catch (Exception error) { + throw new InvalidCommandException(SUBTLE_BUG_MESSAGE); + } + } + + private void checkNegative(int number) throws NegativeNumberException { + if (number < 0) { throw new NegativeNumberException(); } } private Command createCategoryCommand(String[] separatedKeywordAndDescription) throws InvalidCommandException { + Pattern pattern = Pattern.compile(CATEGORY_REGEX); try { - return new CategoryCommand(separatedKeywordAndDescription[1]); + Matcher matcher = pattern.matcher(separatedKeywordAndDescription[1]); + if (matcher.find()) { + String categoryName = matcher.group(1); + if (matcher.group(2) == null) { + return new CategoryCommand(categoryName, 0); + } + int budget = Integer.parseInt(matcher.group(2)); + checkNegative(budget); + return new CategoryCommand(categoryName, budget); + } else { + throw new InvalidCommandException(""); + } } catch (IndexOutOfBoundsException error) { throw new InvalidCommandException(CATEGORY_EMPTY); + } catch (NegativeNumberException error) { + throw new InvalidCommandException("Please give a positive integer for budget"); + } catch (NumberFormatException error) { + throw new InvalidCommandException("Please give a positive integer for budget"); + } catch (InvalidCommandException error) { + throw new InvalidCommandException(CATEGORY_FORMAT + "\n" + REMINDING_MESSAGE_ABOUT_NOT_LETTING_EMPTY); + } catch (Exception error) { + throw new InvalidCommandException(SUBTLE_BUG_MESSAGE); } } diff --git a/src/main/java/seedu/moneymind/command/ViewCommand.java b/src/main/java/seedu/moneymind/command/ViewCommand.java index d4202ed767..cfea7b197b 100644 --- a/src/main/java/seedu/moneymind/command/ViewCommand.java +++ b/src/main/java/seedu/moneymind/command/ViewCommand.java @@ -62,7 +62,7 @@ private void viewAll() { } int count = 1; for (Category category : CategoryList.categories) { - System.out.println(count + DOT + category.getName()); + System.out.println(count + DOT + category.getName() + " (budget: " + category.getBudget() + ")"); count++; // print all the events in the category for (Event event : category.getEvents()) { diff --git a/src/main/java/seedu/moneymind/event/Event.java b/src/main/java/seedu/moneymind/event/Event.java index 74a9921fa2..c8511a195c 100644 --- a/src/main/java/seedu/moneymind/event/Event.java +++ b/src/main/java/seedu/moneymind/event/Event.java @@ -3,24 +3,25 @@ public class Event { private static final int DEFAULT_EXPENSE = 0; private String description; - private int budget; + private String time; private int expense = DEFAULT_EXPENSE; + /** * A constructor with both description and budget. */ - public Event(String description, int budget) { + public Event(String description, int expense) { this.description = description; - this.budget = budget; + this.expense = expense; } /** * A constructor with all parameters. */ - public Event(String description, int budget, int expense) { + public Event(String description, int expense, String time) { this.description = description; - this.budget = budget; this.expense = expense; + this.time = time; } /** @@ -32,14 +33,14 @@ public String getDescription() { return description; } - /** - * Gets the budget of the event. - * - * @return the budget of the event - */ - public int getBudget() { - return budget; - } +// /** +// * Gets the budget of the event. +// * +// * @return the budget of the event +// */ +// public int getBudget() { +// return budget; +// } /** * Gets the expense of the event. @@ -59,14 +60,14 @@ public void setDescription(String description) { this.description = description; } - /** - * Sets the budget of the event. - * - * @param budget the budget of the event - */ - public void setBudget(int budget) { - this.budget = budget; - } +// /** +// * Sets the budget of the event. +// * +// * @param budget the budget of the event +// */ +// public void setBudget(int budget) { +// this.budget = budget; +// } /** * Sets the expense of the event. @@ -77,25 +78,28 @@ public void setExpense(int expense) { this.expense = expense; } - /** - * Checks if the event is over budget. - * - * @return true if the event is over budget, false otherwise - */ - public boolean isOverBudget() { - return expense > budget; - } +// /** +// * Checks if the event is over budget. +// * +// * @return true if the event is over budget, false otherwise +// */ +// public boolean isOverBudget() { +// return expense > budget; +// } - /** - * Gets the remaining budget of the event. - * - * @return the remaining budget of the event - */ - public int remainingBudget() { - return budget - expense; - } +// /** +// * Gets the remaining budget of the event. +// * +// * @return the remaining budget of the event +// */ +// public int remainingBudget() { +// return budget - expense; +// } public String toString() { - return description + " [budget]" + budget + " [expense]" + expense; + if (time == null) { + return description + " [expense]" + expense; + } + return description + " [expense]" + expense + " [time]" + time; } } diff --git a/src/main/java/seedu/moneymind/storage/CategoryMapToString.java b/src/main/java/seedu/moneymind/storage/CategoryMapToString.java deleted file mode 100644 index 26dbd54b1e..0000000000 --- a/src/main/java/seedu/moneymind/storage/CategoryMapToString.java +++ /dev/null @@ -1,27 +0,0 @@ -package seedu.moneymind.storage; - -import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_MAP; -import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; -import static seedu.moneymind.string.Strings.NEW_LINE; -import static seedu.moneymind.command.CategoryCommand.categoryMap; - -/** - * Converts categoryMap to a String. - */ -public class CategoryMapToString { - /** - * Converts categoryMap to a String. - * - * @return String of categoryMap - */ - public static String categoryMapToString() { - String output = ""; - if (!categoryMap.isEmpty()) { - output = STORAGE_CATEGORY_MAP + NEW_LINE; - for (String key : categoryMap.keySet()) { - output += STORAGE_NEXT_VARIABLE + key + STORAGE_NEXT_VARIABLE + categoryMap.get(key) + NEW_LINE; - } - } - return output; - } -} diff --git a/src/main/java/seedu/moneymind/storage/CategoryToString.java b/src/main/java/seedu/moneymind/storage/CategoryToString.java deleted file mode 100644 index 6ea1934f93..0000000000 --- a/src/main/java/seedu/moneymind/storage/CategoryToString.java +++ /dev/null @@ -1,32 +0,0 @@ -package seedu.moneymind.storage; - -import seedu.moneymind.event.Event; -import seedu.moneymind.category.Category; - -import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; -import static seedu.moneymind.string.Strings.NEW_LINE; -import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_NAME; - -/** - * Converts a Category object to a String. - */ -public class CategoryToString { - /** - * Converts a Category object to a String. - * - * @param category the Category object to be converted - * @return the String representation of the Category object - */ - public static String categoryToString(Category category) { - // String of category, to be returned - String output = ""; - - // Adds the category name to the output - output += STORAGE_CATEGORY_NAME + category.getName() + NEW_LINE; - for (Event event : category.events) { - output += STORAGE_NEXT_VARIABLE + event.getDescription() + STORAGE_NEXT_VARIABLE + event.getBudget() - + STORAGE_NEXT_VARIABLE + event.getExpense() + NEW_LINE; - } - return output; - } -} diff --git a/src/main/java/seedu/moneymind/storage/FormatToTxt.java b/src/main/java/seedu/moneymind/storage/FormatToTxt.java deleted file mode 100644 index b04fcbc65a..0000000000 --- a/src/main/java/seedu/moneymind/storage/FormatToTxt.java +++ /dev/null @@ -1,24 +0,0 @@ -package seedu.moneymind.storage; - -import java.util.ArrayList; - -import seedu.moneymind.category.Category; - -/** - * Converts an ArrayList of Category objects to a String. - */ -public class FormatToTxt { - /** - * Converts an ArrayList of Category objects to a String. - * - * @param categories the ArrayList of Category objects to be converted - * @return the String representation of the ArrayList of Category objects - */ - public static String formatToTxt(ArrayList categories) { - String output = ""; - for (Category category : categories) { - output += CategoryToString.categoryToString(category); - } - return output; - } -} diff --git a/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java b/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java deleted file mode 100644 index 0fe1d02bf6..0000000000 --- a/src/main/java/seedu/moneymind/storage/LoadToCategoryMap.java +++ /dev/null @@ -1,23 +0,0 @@ -package seedu.moneymind.storage; - -import java.util.HashMap; - -import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; -import static seedu.moneymind.string.Strings.NEW_LINE; -import static seedu.moneymind.command.CategoryCommand.categoryMap; - -/** - * Converts a String to a HashMap. - */ -public class LoadToCategoryMap { - public static void loadToCategoryMap(String input) { - // hashmap to store the category name and its index in the category list - HashMap loadedMap = new HashMap(); - String[] loadedMapEntries = input.split(NEW_LINE); - for (String entry : loadedMapEntries) { - String[] entryComponents = entry.split(STORAGE_NEXT_VARIABLE); - loadedMap.put(entryComponents[1], Integer.parseInt(entryComponents[2])); - } - categoryMap = loadedMap; - } -} diff --git a/src/main/java/seedu/moneymind/storage/Storage.java b/src/main/java/seedu/moneymind/storage/Storage.java deleted file mode 100644 index aaec87822a..0000000000 --- a/src/main/java/seedu/moneymind/storage/Storage.java +++ /dev/null @@ -1,114 +0,0 @@ -package seedu.moneymind.storage; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.Scanner; -import java.util.logging.Logger; -import java.io.FileWriter; -import java.io.IOException; - -import seedu.moneymind.category.Category; -import seedu.moneymind.category.CategoryList; - -import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_MAP; -import static seedu.moneymind.string.Strings.NEW_LINE; - -/** - * Storage class to save and load data from a file - */ -public class Storage { - private static File textFile; - private static String filePath = "EventList.txt"; - private static Logger logger = Logger.getLogger("Storage"); - - /** - * Constructor for Storage class - */ - public Storage() { - setupFile(); - } - - /** - * Sets up the file to be read and written to - */ - private static void setupFile() { - logger.info("Setting up file"); - // create file object - textFile = new File(filePath); - - // create file if it does not exist - try { - textFile.createNewFile(); - } catch (IOException e) { - logger.warning("File already exists"); - System.out.println("The file already exists."); - } - } - - /** - * Saves an ArrayList of Category to EventList.txt file - * - * @param list ArrayList of Category - */ - public void saveToFile(ArrayList list) { - String writeToFile = FormatToTxt.formatToTxt(list) + CategoryMapToString.categoryMapToString(); - - // write task list to text file - try { - FileWriter dukeWriter = new FileWriter(textFile); - dukeWriter.write(writeToFile); - dukeWriter.close(); - } catch (IOException e) { - logger.warning("File cannot be accessed"); - System.out.println("I cannot seem to access the saved file. Did you perhaps delete it?"); - } - } - - /** - * Loads an ArrayList of Category from EventList.txt file - * - * @return ArrayList of Category - */ - public ArrayList loadFromFile() { - Scanner textFileScanner; - // String to store the text file - String fileString = ""; - - try { - textFileScanner = new Scanner(textFile); - // read file line by line and add to fileString - while (textFileScanner.hasNextLine()) { - fileString += textFileScanner.nextLine() + System.lineSeparator(); - } - } catch (FileNotFoundException e) { - logger.warning("File cannot be accessed"); - System.out.println("I cannot seem to access the saved tasks. Did you perhaps lock it away?"); - } - // split fileString into 2 parts using STORAGE_CATEGORY_MAP - String[] splitString = fileString.split(STORAGE_CATEGORY_MAP + NEW_LINE); - // convert fileString to ArrayList of Category - ArrayList savedList = StringToCategory.stringToCategory(splitString[0]); - if (splitString.length == 2) { - logger.info("Loading category map"); - LoadToCategoryMap.loadToCategoryMap(splitString[1]); - } - return savedList; - } - - /** - * Saves the current list of Category to EventList.txt file - */ - public void save() { - logger.info("Saving to file"); - saveToFile(CategoryList.categories); - } - - /** - * Loads the list of Category from EventList.txt file - */ - public void load() { - logger.info("Loading from file"); - CategoryList.categories = loadFromFile(); - } -} diff --git a/src/main/java/seedu/moneymind/storage/StringToCategory.java b/src/main/java/seedu/moneymind/storage/StringToCategory.java deleted file mode 100644 index 0a058247fa..0000000000 --- a/src/main/java/seedu/moneymind/storage/StringToCategory.java +++ /dev/null @@ -1,45 +0,0 @@ -package seedu.moneymind.storage; - -import seedu.moneymind.event.Event; -import seedu.moneymind.category.Category; - -import java.util.ArrayList; - -import static seedu.moneymind.string.Strings.STORAGE_CATEGORY_NAME; -import static seedu.moneymind.string.Strings.STORAGE_NEXT_VARIABLE; - -/** - * Converts a String from file.txt to an ArrayList of Category objects. - */ -public class StringToCategory { - /** - * Converts a String from file.txt to an ArrayList of Category objects. - * - * @param inputFromFile String from file.txt - * @return ArrayList of Category objects - */ - public static ArrayList stringToCategory(String inputFromFile) { - // ArrayList of Categories objects, to be returned - ArrayList categories = new ArrayList<>(); - - // Reads inputFromFile line by line - String[] lines = inputFromFile.split(System.lineSeparator()); - for (String string : lines) { - // Creates a new Category object if the line is a new category, ignoring the save file symbol - if (string.startsWith(STORAGE_CATEGORY_NAME)) { - categories.add(new Category(string.substring(STORAGE_CATEGORY_NAME.length()))); - } else if (string.startsWith(STORAGE_NEXT_VARIABLE)) { - // Remove the first next variable symbol - string = string.substring(STORAGE_NEXT_VARIABLE.length()); - // Splits the line into 3 parts, each part being a variable of an Event object - String[] eventDetails = string.split(STORAGE_NEXT_VARIABLE); - // Creates a new Event object - Event event = new Event(eventDetails[0], Integer.parseInt(eventDetails[1]), - Integer.parseInt(eventDetails[2])); - // Adds an Event object to the last Category object in the ArrayList - categories.get(categories.size() - 1).addEvent(event); - } - } - return categories; - } -} diff --git a/src/main/java/seedu/moneymind/string/Strings.java b/src/main/java/seedu/moneymind/string/Strings.java index f5a3538a13..44729c823d 100644 --- a/src/main/java/seedu/moneymind/string/Strings.java +++ b/src/main/java/seedu/moneymind/string/Strings.java @@ -54,12 +54,16 @@ public class Strings { "inside the brackets empty!"; public static final String EMPTY_DELETION = "☹ OOPS!!! The description of a delete cannot be empty."; public static final String SUBTLE_BUG_MESSAGE = "☹ OOPS!!! Something went wrong, please report to the developer."; - public static final String EVENT_REGEX = "(.+) b/(-?\\d+) e/(-?\\d+)"; + public static final String EVENT_REGEX = "^(?.*?) e\\/(?.*?)(?: +t\\/(?