Skip to content

Commit c38ba74

Browse files
authored
Merge pull request nus-cs2103-AY2021S1#84 from tanwayne890/branch-ListCategory
Add list category
2 parents b1ac682 + a8ff9f9 commit c38ba74

File tree

7 files changed

+166
-29
lines changed

7 files changed

+166
-29
lines changed

docs/UserGuide.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,20 @@ Examples:
7676

7777
Shows a list of all expenses.
7878

79-
Format: `list [c/CATEGORY]`
80-
81-
<div markdown="span" class="alert alert-primary">:bulb: **Tip:**
82-
Category item is optional for showing all expenses in the specific category.
83-
</div>
79+
Format: `list`
8480

8581
Examples:
8682
* `list`: list all the expenses in all the categories.
87-
* `list c/FOODBEVERAGE`: list all the expenses in the food beverage category.
83+
84+
### Listing all expenses in a category : `listbycategory`
85+
86+
Shows a list of all expenses belongs to the category.
87+
88+
Format: `listbycategory CATEGORY`
89+
90+
Examples:
91+
* `listbycategory entertainment`: list all the expenses in entertainment.
92+
8893

8994
### Deleting an expense: `delete`
9095

src/main/java/seedu/address/commons/core/Messages.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
public class Messages {
77
public static final String MESSAGE_INVALID_EXPENSE_DISPLAYED_INDEX = "The expense index provided is invalid";
8-
8+
public static final String MESSAGE_EXPENSES_LISTED_OVERVIEW = "%1$d expenses listed!";
99

1010

1111
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package seedu.address.logic.commands;
2+
3+
import static java.util.Objects.requireNonNull;
4+
5+
import seedu.address.commons.core.Messages;
6+
import seedu.address.model.Model;
7+
import seedu.address.model.person.CategoryContainsKeywordsPredicate;
8+
9+
/**
10+
* Finds and lists all expenses in expense book whose category contains any of the argument keywords.
11+
* Keyword matching is case insensitive.
12+
*/
13+
public class ListExpenseByCategoryCommand extends Command {
14+
15+
public static final String COMMAND_WORD = "listbycategory";
16+
17+
public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all expenses whose category contains any of "
18+
+ "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
19+
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
20+
+ "Example: " + COMMAND_WORD + "entertainment";
21+
22+
private final CategoryContainsKeywordsPredicate predicate;
23+
24+
public ListExpenseByCategoryCommand(CategoryContainsKeywordsPredicate predicate) {
25+
this.predicate = predicate;
26+
}
27+
28+
@Override
29+
public CommandResult execute(Model model) {
30+
requireNonNull(model);
31+
model.updateFilteredExpenseList(predicate);
32+
return new CommandResult(
33+
String.format(Messages.MESSAGE_EXPENSES_LISTED_OVERVIEW, model.getFilteredExpenseList().size()));
34+
}
35+
36+
@Override
37+
public boolean equals(Object other) {
38+
return other == this // short circuit if same object
39+
|| (other instanceof ListExpenseByCategoryCommand // instanceof handles nulls
40+
&& predicate.equals(((ListExpenseByCategoryCommand) other).predicate)); // state check
41+
}
42+
}

src/main/java/seedu/address/logic/parser/ExpenseBookParser.java

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@
66
import java.util.regex.Matcher;
77
import java.util.regex.Pattern;
88

9+
import seedu.address.logic.commands.AddExpenseCommand;
10+
import seedu.address.logic.commands.Command;
11+
import seedu.address.logic.commands.DeleteExpenseCommand;
12+
import seedu.address.logic.commands.DeleteDescriptionCommand;
13+
import seedu.address.logic.commands.DescriptionCommand;
14+
import seedu.address.logic.commands.ListExpenseCommand;
15+
import seedu.address.logic.commands.ListExpenseByCategoryCommand;
16+
import seedu.address.logic.commands.HelpCommand;
17+
import seedu.address.logic.commands.ViewCommand;
18+
import seedu.address.logic.commands.SetBudgetCommand;
19+
import seedu.address.logic.commands.ShowBudgetCommand;
20+
import seedu.address.logic.parser.exceptions.ParseException;
21+
922
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
1023
import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
1124

@@ -34,35 +47,50 @@ public Command parseCommand(String userInput) throws ParseException {
3447
final String commandWord = matcher.group("commandWord");
3548
final String arguments = matcher.group("arguments");
3649
switch (commandWord) {
37-
case DescriptionCommand.COMMAND_WORD:
38-
return new DescriptionCommandParser().parse(arguments);
50+
case DescriptionCommand.COMMAND_WORD:
51+
return new DescriptionCommandParser().parse(arguments);
52+
53+
case AddExpenseCommand.COMMAND_WORD:
54+
return new AddExpenseCommandParser().parse(arguments);
55+
56+
case DeleteExpenseCommand.COMMAND_WORD:
57+
return new DeleteExpenseCommandParser().parse(arguments);
58+
59+
case ListExpenseCommand.COMMAND_WORD:
60+
return new ListExpenseCommand();
61+
62+
case ViewCommand.COMMAND_WORD:
63+
return new ViewCommandParser().parse(arguments);
3964

40-
case AddExpenseCommand.COMMAND_WORD:
41-
return new AddExpenseCommandParser().parse(arguments);
65+
case ViewCategoryCommand.COMMAND_WORD:
66+
return new ViewCategoryCommandParser().parse(arguments);
4267

43-
case DeleteExpenseCommand.COMMAND_WORD:
44-
return new DeleteExpenseCommandParser().parse(arguments);
68+
case DeleteDescriptionCommand.COMMAND_WORD:
69+
return new DeleteDescriptionCommandParser().parse(arguments);
4570

46-
case ListExpenseCommand.COMMAND_WORD:
47-
return new ListExpenseCommand();
71+
case DeleteExpenseCommand.COMMAND_WORD:
72+
return new DeleteExpenseCommandParser().parse(arguments);
4873

49-
case ViewCommand.COMMAND_WORD:
50-
return new ViewCommandParser().parse(arguments);
74+
case ListExpenseCommand.COMMAND_WORD:
75+
return new ListExpenseCommand();
5176

52-
case ViewCategoryCommand.COMMAND_WORD:
53-
return new ViewCategoryCommandParser().parse(arguments);
77+
case ListExpenseByCategoryCommand.COMMAND_WORD:
78+
return new ListExpenseByCategoryCommandParser().parse(arguments);
5479

55-
case DeleteDescriptionCommand.COMMAND_WORD:
56-
return new DeleteDescriptionCommandParser().parse(arguments);
80+
case ViewCommand.COMMAND_WORD:
81+
return new ViewCommandParser().parse(arguments);
5782

58-
case ShowBudgetCommand.COMMAND_WORD:
59-
return new ShowBudgetCommandParser().parse(arguments);
83+
case DeleteDescriptionCommand.COMMAND_WORD:
84+
return new DeleteDescriptionCommandParser().parse(arguments);
6085

61-
case SetBudgetCommand.COMMAND_WORD:
62-
return new SetBudgetCommandParser().parse(arguments);
86+
case ShowBudgetCommand.COMMAND_WORD:
87+
return new ShowBudgetCommandParser().parse(arguments);
6388

64-
default:
65-
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
89+
case SetBudgetCommand.COMMAND_WORD:
90+
return new SetBudgetCommandParser().parse(arguments);
91+
92+
default:
93+
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
6694
}
6795
}
6896
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package seedu.address.logic.parser;
2+
3+
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
4+
5+
import java.util.Arrays;
6+
7+
import seedu.address.logic.commands.ListExpenseByCategoryCommand;
8+
import seedu.address.logic.parser.exceptions.ParseException;
9+
import seedu.address.model.person.CategoryContainsKeywordsPredicate;
10+
11+
/**
12+
* Parses input arguments and creates a new ListExpenseByCategoryCommand object
13+
*/
14+
public class ListExpenseByCategoryCommandParser implements Parser<ListExpenseByCategoryCommand> {
15+
16+
/**
17+
* Parses the given {@code String} of arguments in the context of the ListExpenseByCategoryCommand
18+
* and returns a ListExpenseByCategoryCommand object for execution.
19+
* @throws ParseException if the user input does not conform the expected format
20+
*/
21+
public ListExpenseByCategoryCommand parse(String args) throws ParseException {
22+
String trimmedArgs = args.trim();
23+
if (trimmedArgs.isEmpty()) {
24+
throw new ParseException(
25+
String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListExpenseByCategoryCommand.MESSAGE_USAGE));
26+
}
27+
28+
String[] categoryKeywords = trimmedArgs.split("\\s+");
29+
30+
return new ListExpenseByCategoryCommand(new CategoryContainsKeywordsPredicate(Arrays.asList(categoryKeywords)));
31+
}
32+
33+
}

src/main/java/seedu/address/model/ModelManager.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public class ModelManager implements Model {
2828
private final FilteredList<Person> filteredPersons;
2929

3030
private final FilteredList<Expense> filteredExpenses;
31-
// private final ExpenseBook expenseBook;
3231

3332

3433
/**
@@ -42,7 +41,6 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs
4241

4342
this.addressBook = new AddressBook(addressBook);
4443
this.userPrefs = new UserPrefs(userPrefs);
45-
// this.expenseBook = new ExpenseBook(expenseBook);
4644
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
4745
filteredExpenses = new FilteredList<>(this.addressBook.getExpenseList());
4846
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package seedu.address.model.person;
2+
3+
import java.util.List;
4+
import java.util.function.Predicate;
5+
6+
import seedu.address.commons.util.StringUtil;
7+
8+
/**
9+
* Tests that a {@code Expense}'s {@code Category} matches any of the keywords given.
10+
*/
11+
public class CategoryContainsKeywordsPredicate implements Predicate<Expense> {
12+
private final List<String> keywords;
13+
14+
public CategoryContainsKeywordsPredicate(List<String> keywords) {
15+
this.keywords = keywords;
16+
}
17+
18+
@Override
19+
public boolean test(Expense expense) {
20+
return keywords.stream()
21+
.anyMatch(keyword -> StringUtil.containsWordIgnoreCase(expense.getCategory().categoryName, keyword));
22+
}
23+
24+
@Override
25+
public boolean equals(Object other) {
26+
return other == this // short circuit if same object
27+
|| (other instanceof CategoryContainsKeywordsPredicate // instanceof handles nulls
28+
&& keywords.equals(((CategoryContainsKeywordsPredicate) other).keywords)); // state check
29+
}
30+
31+
}

0 commit comments

Comments
 (0)