diff --git a/src/main/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommand.java b/src/main/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommand.java index dd680c1174e..f1b5a3a169f 100644 --- a/src/main/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommand.java +++ b/src/main/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommand.java @@ -3,13 +3,13 @@ import static java.util.Objects.requireNonNull; import static seedu.foodrem.commons.enums.CommandType.FILTER_TAG_COMMAND; -import seedu.foodrem.commons.core.Messages; import seedu.foodrem.logic.commands.Command; import seedu.foodrem.logic.commands.CommandResult; import seedu.foodrem.logic.commands.exceptions.CommandException; import seedu.foodrem.model.Model; import seedu.foodrem.model.item.TagSetContainsTagPredicate; import seedu.foodrem.model.tag.Tag; +import seedu.foodrem.viewmodels.FilterByTag; /** * Filters all items in FoodRem for items that contain the specified tag @@ -17,37 +17,35 @@ public class FilterTagCommand extends Command { private final TagSetContainsTagPredicate pred; + private final Tag tag; + /** * @param tag to filter the Item list for Items tagged with it */ public FilterTagCommand(Tag tag) { requireNonNull(tag); this.pred = new TagSetContainsTagPredicate(tag); + this.tag = tag; } @Override - public CommandResult execute(Model model) throws CommandException { + public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - if (!model.hasTag(pred.getTag())) { + if (!model.hasTag(tag)) { throw new CommandException("This tag does not exist in the FoodRem"); } model.updateFilteredItemList(pred); - return CommandResult.from(String.format(this.getSuccessMessage(), - model.getCurrentList().size())); + String primaryMessage = "Filtered by tag:"; + String secondaryMessage = String.format("%s items filtered", model.getCurrentList().size()); + return CommandResult.from(new FilterByTag(tag, primaryMessage, secondaryMessage)); } public static String getUsage() { return FILTER_TAG_COMMAND.getUsage(); } - protected String getSuccessMessage() { - return String.format("Filtered by tag: %s\n%s", - this.pred.getTag().getName(), - Messages.MESSAGE_ITEMS_FILTERED_OVERVIEW); - } - @Override public boolean equals(Object other) { return other == this diff --git a/src/main/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommand.java b/src/main/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommand.java index 8c34c897fb8..7bc56959a7d 100644 --- a/src/main/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommand.java +++ b/src/main/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommand.java @@ -8,6 +8,7 @@ import seedu.foodrem.logic.commands.exceptions.CommandException; import seedu.foodrem.model.Model; import seedu.foodrem.model.tag.Tag; +import seedu.foodrem.viewmodels.TagsWithMessage; /** * Deletes an existing tag in FoodRem. @@ -17,6 +18,8 @@ public class DeleteTagCommand extends Command { /** * Creates an DeleteTagCommand to delete the specified {@code Tag} + * + * @param tagToDelete the tag that will be deleted from foodRem. */ public DeleteTagCommand(Tag tagToDelete) { requireNonNull(tagToDelete); @@ -24,7 +27,7 @@ public DeleteTagCommand(Tag tagToDelete) { } @Override - public CommandResult execute(Model model) throws CommandException { + public CommandResult execute(Model model) throws CommandException { requireNonNull(model); if (!model.hasTag(toDelete)) { @@ -32,7 +35,7 @@ public CommandResult execute(Model model) throws CommandException { } model.deleteTag(toDelete); - return CommandResult.from(String.format("Tag deleted: %1$s", toDelete)); + return CommandResult.from(new TagsWithMessage("Tag deleted:", toDelete)); } public static String getUsage() { diff --git a/src/main/java/seedu/foodrem/logic/commands/tagcommands/ListTagCommand.java b/src/main/java/seedu/foodrem/logic/commands/tagcommands/ListTagCommand.java index f344b0f885c..2baa997da14 100644 --- a/src/main/java/seedu/foodrem/logic/commands/tagcommands/ListTagCommand.java +++ b/src/main/java/seedu/foodrem/logic/commands/tagcommands/ListTagCommand.java @@ -3,33 +3,23 @@ import static java.util.Objects.requireNonNull; import static seedu.foodrem.commons.enums.CommandType.LIST_TAG_COMMAND; -import java.util.List; - import seedu.foodrem.logic.commands.Command; import seedu.foodrem.logic.commands.CommandResult; import seedu.foodrem.model.Model; import seedu.foodrem.model.tag.Tag; +import seedu.foodrem.viewmodels.TagsWithMessage; /** * Lists all the tags available */ public class ListTagCommand extends Command { + private static final String MESSAGE_SUCCESS = "Listed all tags:"; + @Override - public CommandResult execute(Model model) { + public CommandResult execute(Model model) { requireNonNull(model); model.updateFilteredTagList(Model.PREDICATE_SHOW_ALL_TAGS); - List allTags = model.getFilteredTagList(); - - StringBuilder allTagsList = new StringBuilder("Listed all tags:\n"); - - for (Tag tag : allTags) { - allTagsList.append(tag.getName()); - allTagsList.append(System.getProperty("line.separator")); - } - - String tagList = allTagsList.toString(); - - return CommandResult.from(tagList); + return CommandResult.from(new TagsWithMessage(MESSAGE_SUCCESS, model.getFilteredTagList().toArray(Tag[]::new))); } public static String getUsage() { diff --git a/src/main/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommand.java b/src/main/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommand.java index 32ee5af9e56..02c73b06039 100644 --- a/src/main/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommand.java +++ b/src/main/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommand.java @@ -8,6 +8,7 @@ import seedu.foodrem.logic.commands.exceptions.CommandException; import seedu.foodrem.model.Model; import seedu.foodrem.model.tag.Tag; +import seedu.foodrem.viewmodels.TagsWithMessage; /** * Adds a tag to FoodRem. @@ -16,7 +17,9 @@ public class NewTagCommand extends Command { private final Tag toAdd; /** - * Creates an AddTagCommand to add the specified {@code Tag} + * Creates a NewTagCommand to add the specified {@code Tag} + * + * @param tag the tag that will be added to foodRem. */ public NewTagCommand(Tag tag) { requireNonNull(tag); @@ -24,7 +27,7 @@ public NewTagCommand(Tag tag) { } @Override - public CommandResult execute(Model model) throws CommandException { + public CommandResult execute(Model model) throws CommandException { requireNonNull(model); if (model.hasTag(toAdd)) { @@ -32,7 +35,7 @@ public CommandResult execute(Model model) throws CommandException { } model.addTag(toAdd); - return CommandResult.from(String.format("New tag added: %1$s", toAdd)); + return CommandResult.from(new TagsWithMessage("New tag added:", toAdd)); } public static String getUsage() { diff --git a/src/main/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommand.java b/src/main/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommand.java index a0540a7bc40..c3baff2bff3 100644 --- a/src/main/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommand.java +++ b/src/main/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommand.java @@ -8,6 +8,7 @@ import seedu.foodrem.logic.commands.exceptions.CommandException; import seedu.foodrem.model.Model; import seedu.foodrem.model.tag.Tag; +import seedu.foodrem.viewmodels.TagToRename; /** * Renames an existing tag in FoodRem. @@ -17,7 +18,10 @@ public class RenameTagCommand extends Command { private final Tag renamedTag; /** - * Creates an AddTagCommand to add the specified {@code Tag} + * Creates a RenameTagCommand to rename a specified {@code Tag} + * + * @param originalTag the tag to be renamed + * @param renamedTag the new tag */ public RenameTagCommand(Tag originalTag, Tag renamedTag) { requireNonNull(originalTag); @@ -27,7 +31,7 @@ public RenameTagCommand(Tag originalTag, Tag renamedTag) { } @Override - public CommandResult execute(Model model) throws CommandException { + public CommandResult execute(Model model) throws CommandException { requireNonNull(model); if (!model.hasTag(originalTag)) { @@ -39,7 +43,7 @@ public CommandResult execute(Model model) throws CommandException { } model.setTag(originalTag, renamedTag); - return CommandResult.from(String.format("Original tag: %s\nRenamed tag: %s\n", originalTag, renamedTag)); + return CommandResult.from(new TagToRename(originalTag, renamedTag, "Tag renamed:")); } public static String getUsage() { diff --git a/src/main/java/seedu/foodrem/logic/commands/tagcommands/TagCommand.java b/src/main/java/seedu/foodrem/logic/commands/tagcommands/TagCommand.java index 70319a0bb41..6ba2e57ac83 100644 --- a/src/main/java/seedu/foodrem/logic/commands/tagcommands/TagCommand.java +++ b/src/main/java/seedu/foodrem/logic/commands/tagcommands/TagCommand.java @@ -3,7 +3,6 @@ import static java.util.Objects.requireNonNull; import static seedu.foodrem.commons.enums.CommandType.TAG_COMMAND; -import java.util.List; import java.util.Set; import seedu.foodrem.commons.core.index.Index; @@ -24,6 +23,9 @@ public class TagCommand extends Command { /** * Creates a TagCommand to tag the specified {@code Item} with a specified {@code Tag} + * + * @param tagName the name of the tag + * @param index the index of the item to tag */ public TagCommand(String tagName, Index index) { requireNonNull(tagName); @@ -34,33 +36,18 @@ public TagCommand(String tagName, Index index) { @Override public CommandResult execute(Model model) throws CommandException { - Item itemToTag = validateAndGetTargetItem(model, tag, index); + Item itemToTag = TagCommandUtil.validateAndGetItem(model, tag, index); + Set itemTags = itemToTag.getTagSet(); if (itemTags.contains(tag)) { throw new CommandException("This item has already been tagged with this tag"); } + itemTags.add(tag); Item newTagSetItem = Item.createItemWithTags(itemToTag, itemTags); - model.setItem(itemToTag, newTagSetItem); - return CommandResult.from( - new ItemWithMessage(newTagSetItem, "Item tagged successfully. View updated item below:")); - } - - static Item validateAndGetTargetItem(Model model, Tag tag, Index index) throws CommandException { - requireNonNull(model); - - if (!model.hasTag(tag)) { - throw new CommandException("This tag does not exist"); - } - - List lastShownList = model.getCurrentList(); - if (index.getZeroBased() >= lastShownList.size()) { - throw new CommandException("The item index does not exist"); - } - - return lastShownList.get(index.getZeroBased()); + return CommandResult.from(new ItemWithMessage(newTagSetItem, "Item tagged successfully. Updated item:")); } public static String getUsage() { diff --git a/src/main/java/seedu/foodrem/logic/commands/tagcommands/TagCommandUtil.java b/src/main/java/seedu/foodrem/logic/commands/tagcommands/TagCommandUtil.java new file mode 100644 index 00000000000..e61a0f323b6 --- /dev/null +++ b/src/main/java/seedu/foodrem/logic/commands/tagcommands/TagCommandUtil.java @@ -0,0 +1,40 @@ +package seedu.foodrem.logic.commands.tagcommands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import seedu.foodrem.commons.core.index.Index; +import seedu.foodrem.logic.commands.exceptions.CommandException; +import seedu.foodrem.model.Model; +import seedu.foodrem.model.item.Item; +import seedu.foodrem.model.tag.Tag; + +/** + * Handles validation for tag commands + */ +public class TagCommandUtil { + private TagCommandUtil() {} + + /** + * Checks if a model has a tag and if the index is valid before getting the item. + * + * @param model the current model + * @param tag the tag to be validated + * @param index the index of the item + */ + public static Item validateAndGetItem(Model model, Tag tag, Index index) throws CommandException { + requireNonNull(model); + + if (!model.hasTag(tag)) { + throw new CommandException("This tag does not exist"); + } + + List lastShownList = model.getCurrentList(); + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException("The item index does not exist"); + } + + return lastShownList.get(index.getZeroBased()); + } +} diff --git a/src/main/java/seedu/foodrem/logic/commands/tagcommands/UntagCommand.java b/src/main/java/seedu/foodrem/logic/commands/tagcommands/UntagCommand.java index e511d573c94..fa070755c3c 100644 --- a/src/main/java/seedu/foodrem/logic/commands/tagcommands/UntagCommand.java +++ b/src/main/java/seedu/foodrem/logic/commands/tagcommands/UntagCommand.java @@ -22,7 +22,10 @@ public class UntagCommand extends Command { private final Tag tag; /** - * Creates a TagCommand to tag the specified {@code Item} with a specified {@code Tag} + * Creates an UntagCommand to untag the specified {@code Item} with a specified {@code Tag} + * + * @param tagName the name of the tag + * @param index the index of the item to untag */ public UntagCommand(String tagName, Index index) { requireNonNull(tagName); @@ -33,17 +36,18 @@ public UntagCommand(String tagName, Index index) { @Override public CommandResult execute(Model model) throws CommandException { - Item itemToUntag = TagCommand.validateAndGetTargetItem(model, tag, index); + Item itemToUntag = TagCommandUtil.validateAndGetItem(model, tag, index); + Set itemTags = itemToUntag.getTagSet(); if (!itemTags.contains(tag)) { - throw new CommandException("This item is not tagged with this tag"); + throw new CommandException("This item has not been tagged with this tag"); } + itemTags.remove(tag); Item newTagSetItem = Item.createItemWithTags(itemToUntag, itemTags); model.setItem(itemToUntag, newTagSetItem); - return CommandResult.from( - new ItemWithMessage(newTagSetItem, "Item untagged successfully. View updated item below:")); + return CommandResult.from(new ItemWithMessage(newTagSetItem, "Item untagged successfully. Updated item:")); } public static String getUsage() { diff --git a/src/main/java/seedu/foodrem/viewmodels/FilterByTag.java b/src/main/java/seedu/foodrem/viewmodels/FilterByTag.java new file mode 100644 index 00000000000..2ab5d880068 --- /dev/null +++ b/src/main/java/seedu/foodrem/viewmodels/FilterByTag.java @@ -0,0 +1,53 @@ +package seedu.foodrem.viewmodels; + +import java.util.Objects; + +import seedu.foodrem.model.tag.Tag; + +/** + * A view model for generating a view with tags as well as two messages. + * @author Tan Yi Xian + */ +public class FilterByTag { + private final Tag tag; + private final String primaryMessage; + private final String secondaryMessage; + + /** + * Creates a view model containing the message and the tags to rename. + * @param tag the tag. + * @param primaryMessage the message to be displayed above the tags. + * @param secondaryMessage the message to displayed under the tags. + */ + public FilterByTag(Tag tag, String primaryMessage, String secondaryMessage) { + this.tag = tag; + this.primaryMessage = primaryMessage; + this.secondaryMessage = secondaryMessage; + } + + public Tag getTag() { + return tag; + } + + public String getPrimaryMessage() { + return primaryMessage; + } + + public String getSecondaryMessage() { + return secondaryMessage; + } + + @Override + public boolean equals(Object other) { + return this == other + || (other instanceof FilterByTag + && tag.equals(((FilterByTag) other).tag) + && primaryMessage.equals(((FilterByTag) other).primaryMessage) + && secondaryMessage.equals(((FilterByTag) other).secondaryMessage)); + } + + @Override + public int hashCode() { + return Objects.hash(tag, primaryMessage, secondaryMessage); + } +} diff --git a/src/main/java/seedu/foodrem/viewmodels/TagToRename.java b/src/main/java/seedu/foodrem/viewmodels/TagToRename.java new file mode 100644 index 00000000000..97d4bde7fb3 --- /dev/null +++ b/src/main/java/seedu/foodrem/viewmodels/TagToRename.java @@ -0,0 +1,53 @@ +package seedu.foodrem.viewmodels; + +import java.util.Objects; + +import seedu.foodrem.model.tag.Tag; + +/** + * A view model for generating a view with tags as well as a message. + * @author Tan Yi Xian + */ +public class TagToRename { + private final Tag originalTag; + private final Tag renamedTag; + private final String message; + + /** + * Creates a view model containing the message and the tags to rename. + * @param originalTag the original tag. + * @param renamedTag the renamed tag. + * @param message the message to display. + */ + public TagToRename(Tag originalTag, Tag renamedTag, String message) { + this.originalTag = originalTag; + this.renamedTag = renamedTag; + this.message = message; + } + + public Tag getOriginalTag() { + return originalTag; + } + + public Tag getRenamedTag() { + return renamedTag; + } + + public String getMessage() { + return message; + } + + @Override + public boolean equals(Object other) { + return this == other + || (other instanceof TagToRename + && originalTag.equals(((TagToRename) other).originalTag) + && renamedTag.equals(((TagToRename) other).renamedTag) + && message.equals(((TagToRename) other).message)); + } + + @Override + public int hashCode() { + return Objects.hash(originalTag, renamedTag, message); + } +} diff --git a/src/main/java/seedu/foodrem/viewmodels/TagsWithMessage.java b/src/main/java/seedu/foodrem/viewmodels/TagsWithMessage.java new file mode 100644 index 00000000000..0561c9e0e45 --- /dev/null +++ b/src/main/java/seedu/foodrem/viewmodels/TagsWithMessage.java @@ -0,0 +1,46 @@ +package seedu.foodrem.viewmodels; + +import java.util.Arrays; +import java.util.Objects; + +import seedu.foodrem.model.tag.Tag; + +/** + * A view model for generating a view with tags as well as a message. + * @author Tan Yi Xian + */ +public class TagsWithMessage { + private final Tag[] tags; + private final String message; + + /** + * Creates a view model containing the message and the tags to display. + * @param tags the tags to display. + * @param message the message to display. + */ + public TagsWithMessage(String message, Tag... tags) { + this.tags = tags; + this.message = message; + } + + public Tag[] getTags() { + return tags; + } + + public String getMessage() { + return message; + } + + @Override + public boolean equals(Object other) { + return this == other + || (other instanceof TagsWithMessage + && Arrays.equals(tags, ((TagsWithMessage) other).tags) + && message.equals(((TagsWithMessage) other).message)); + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(tags), message); + } +} diff --git a/src/main/java/seedu/foodrem/views/FilterByTagView.java b/src/main/java/seedu/foodrem/views/FilterByTagView.java new file mode 100644 index 00000000000..de7769e58a9 --- /dev/null +++ b/src/main/java/seedu/foodrem/views/FilterByTagView.java @@ -0,0 +1,39 @@ +package seedu.foodrem.views; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.control.Separator; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import seedu.foodrem.viewmodels.FilterByTag; + +/** + * A view of a {@code FilterByTag}. This can be displayed. + * @author Tan Yi Xian + */ +public class FilterByTagView { + private static final double SPACING_UNIT = 8; + + /** + * Creates a new detailed view of the given tags as well as + * message contained in the {@code FilterByTag} view model. + * @param filterByTag the tags to be displayed. + * @return the node to be displayed in the UI. + */ + public static Node from(FilterByTag filterByTag) { + final VBox container = new VBox(); + container.setSpacing(SPACING_UNIT); + + final Label primaryMessage = new Label(filterByTag.getPrimaryMessage()); + primaryMessage.setWrapText(true); + final Separator separator = new Separator(); + separator.getStyleClass().add("lined-separator"); + final HBox itemView = new HBox(TagsView.from(filterByTag.getTag())); + itemView.setSpacing(SPACING_UNIT); + final Label secondaryMessage = new Label(filterByTag.getSecondaryMessage()); + secondaryMessage.setWrapText(true); + + container.getChildren().addAll(primaryMessage, separator, itemView, secondaryMessage); + return container; + } +} diff --git a/src/main/java/seedu/foodrem/views/ItemView.java b/src/main/java/seedu/foodrem/views/ItemView.java index 06501f5370b..9c13449b10f 100644 --- a/src/main/java/seedu/foodrem/views/ItemView.java +++ b/src/main/java/seedu/foodrem/views/ItemView.java @@ -1,9 +1,5 @@ package seedu.foodrem.views; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.control.Label; @@ -13,7 +9,6 @@ import javafx.scene.layout.VBox; import javafx.scene.text.TextAlignment; import seedu.foodrem.model.item.Item; -import seedu.foodrem.model.tag.Tag; /** * A view of an {@code Item}. This can be displayed. @@ -35,14 +30,8 @@ public static Node from(Item item) { name.prefWidth(Double.MAX_VALUE); // Name and tags at the top left - final List tagsList = new ArrayList<>(); - tagsList.add(new Label("Tags: ")); - item.getTagSet().stream().sorted(Comparator.comparing(Tag::getName)) - .forEach(tag -> tagsList.add(buildTagNodeFrom(tag.getName()))); - if (tagsList.size() == 1) { - tagsList.add(new Label("-")); - } - final HBox tags = new HBox(tagsList.toArray(Node[]::new)); + final HBox tags = new HBox(new Label("Tags: ")); + tags.getChildren().addAll(TagsView.from(item.getTagSet())); tags.setAlignment(Pos.CENTER_LEFT); tags.setSpacing(SPACING_UNIT); @@ -79,12 +68,6 @@ public static Node from(Item item) { return itemView; } - private static Node buildTagNodeFrom(String tagName) { - final Label label = new Label(tagName); - label.getStyleClass().add("item-detail-tag"); - return label; - } - /** * Builds the string representation of the item's quantity attached to its units. * @param item the item whose quantity is to be formatted. diff --git a/src/main/java/seedu/foodrem/views/ItemWithMessageView.java b/src/main/java/seedu/foodrem/views/ItemWithMessageView.java index 7ee258f5a42..1e4aa6b9185 100644 --- a/src/main/java/seedu/foodrem/views/ItemWithMessageView.java +++ b/src/main/java/seedu/foodrem/views/ItemWithMessageView.java @@ -20,6 +20,7 @@ public class ItemWithMessageView { * @return the node to be displayed in the UI. */ public static Node from(ItemWithMessage itemWithMessage) { + // TODO: Refactor code duplication final VBox container = new VBox(); container.setSpacing(SPACING_UNIT); diff --git a/src/main/java/seedu/foodrem/views/TagToRenameView.java b/src/main/java/seedu/foodrem/views/TagToRenameView.java new file mode 100644 index 00000000000..246a056b817 --- /dev/null +++ b/src/main/java/seedu/foodrem/views/TagToRenameView.java @@ -0,0 +1,42 @@ +package seedu.foodrem.views; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.control.Separator; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import seedu.foodrem.viewmodels.TagToRename; + +/** + * A view of an {@code TagToRename}. This can be displayed. + * @author Tan Yi Xian + */ +public class TagToRenameView { + private static final double SPACING_UNIT = 8; + + /** + * Creates a new detailed view of the tags to be renamed, the renamed tag, all tags + * and the message contained in the {@code TagToRename} view model. + * @param tagToRename the information of tag to be renamed and message. + * @return the node to be displayed in the UI. + */ + public static Node from(TagToRename tagToRename) { + // TODO: Refactor code duplication + final VBox container = new VBox(); + container.setSpacing(SPACING_UNIT); + + final Label messageView = new Label(tagToRename.getMessage()); + messageView.setWrapText(true); + final Separator separator = new Separator(); + separator.getStyleClass().add("lined-separator"); + + final HBox originalTag = new HBox(new Label("Original Tag:"), TagView.from(tagToRename.getOriginalTag())); + final HBox renamedTag = new HBox(new Label("Renamed Tag:"), TagView.from(tagToRename.getRenamedTag())); + + originalTag.setSpacing(SPACING_UNIT); + renamedTag.setSpacing(SPACING_UNIT); + + container.getChildren().addAll(messageView, separator, originalTag, renamedTag); + return container; + } +} diff --git a/src/main/java/seedu/foodrem/views/TagView.java b/src/main/java/seedu/foodrem/views/TagView.java new file mode 100644 index 00000000000..b27b804b8b0 --- /dev/null +++ b/src/main/java/seedu/foodrem/views/TagView.java @@ -0,0 +1,24 @@ +package seedu.foodrem.views; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import seedu.foodrem.model.tag.Tag; + +/** + * A view of a {@code Tag}. This can be displayed. + * @author Richard Dominick + */ +public class TagView { + private TagView() {} // Prevents instantiation + + /** + * Creates a new view of the given string. + * @param tag the tag to be displayed. + * @return the node to be displayed in the UI. + */ + public static Node from(Tag tag) { + final Label label = new Label(tag.getName()); + label.getStyleClass().add("item-detail-tag"); + return label; + } +} diff --git a/src/main/java/seedu/foodrem/views/TagsView.java b/src/main/java/seedu/foodrem/views/TagsView.java new file mode 100644 index 00000000000..a127faa2820 --- /dev/null +++ b/src/main/java/seedu/foodrem/views/TagsView.java @@ -0,0 +1,45 @@ +package seedu.foodrem.views; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import seedu.foodrem.model.tag.Tag; + +/** + * A view of a list of {@code Tags}. This can be displayed. + * @author Tan Yi Xian, Richard Dominick + */ +public class TagsView { + private static final String EMPTY_TAGS = "-"; + + private TagsView() {} // Prevents instantiation + + /** + * Creates a new detailed view of the given tags from a list. + * @param tags the tags to be displayed. + * @return the node to be displayed in the UI. + */ + public static Node[] from(Tag... tags) { + final List tagsList = new ArrayList<>(); + Arrays.stream(tags).sorted(Comparator.comparing(Tag::getName)) + .forEach(tag -> tagsList.add(TagView.from(tag))); + if (tagsList.isEmpty()) { + tagsList.add(new Label(EMPTY_TAGS)); + } + return tagsList.toArray(Node[]::new); + } + + /** + * Creates a new detailed view of the given tags from a set. + * @param tags the tags to be displayed. + * @return the node to be displayed in the UI. + */ + public static Node[] from(Collection tags) { + return from(tags.toArray(Tag[]::new)); + } +} diff --git a/src/main/java/seedu/foodrem/views/TagsWithMessageView.java b/src/main/java/seedu/foodrem/views/TagsWithMessageView.java new file mode 100644 index 00000000000..2a42d4cc36f --- /dev/null +++ b/src/main/java/seedu/foodrem/views/TagsWithMessageView.java @@ -0,0 +1,39 @@ +package seedu.foodrem.views; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.control.Separator; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.VBox; +import seedu.foodrem.viewmodels.TagsWithMessage; + +/** + * A view of an {@code TagsWithMessage}. This can be displayed. + * @author Tan Yi Xian + */ +public class TagsWithMessageView { + private static final double SPACING_UNIT = 8; + + /** + * Creates a new detailed view of the given tags as well as + * message contained in the {@code TagsWithMessage} view model. + * @param tagsWithMessage the tags to be displayed. + * @return the node to be displayed in the UI. + */ + public static Node from(TagsWithMessage tagsWithMessage) { + // TODO: Refactor code duplication + final VBox container = new VBox(); + container.setSpacing(SPACING_UNIT); + + final Label messageView = new Label(tagsWithMessage.getMessage()); + messageView.setWrapText(true); + final Separator separator = new Separator(); + separator.getStyleClass().add("lined-separator"); + final FlowPane itemView = new FlowPane(TagsView.from(tagsWithMessage.getTags())); + itemView.setVgap(SPACING_UNIT); + itemView.setHgap(SPACING_UNIT); + + container.getChildren().addAll(messageView, separator, itemView); + return container; + } +} diff --git a/src/main/java/seedu/foodrem/views/UiView.java b/src/main/java/seedu/foodrem/views/UiView.java index a6ae737456c..879e6273375 100644 --- a/src/main/java/seedu/foodrem/views/UiView.java +++ b/src/main/java/seedu/foodrem/views/UiView.java @@ -4,7 +4,10 @@ import seedu.foodrem.model.item.Item; import seedu.foodrem.ui.ResultDisplay; +import seedu.foodrem.viewmodels.FilterByTag; import seedu.foodrem.viewmodels.ItemWithMessage; +import seedu.foodrem.viewmodels.TagToRename; +import seedu.foodrem.viewmodels.TagsWithMessage; /** * A UI view manager to handle view updates to a result display. @@ -42,6 +45,18 @@ public void viewFrom(Object object) { display.place(ItemWithMessageView.from((ItemWithMessage) object)); return; } + if (object instanceof TagsWithMessage) { + display.place(TagsWithMessageView.from((TagsWithMessage) object)); + return; + } + if (object instanceof TagToRename) { + display.place(TagToRenameView.from((TagToRename) object)); + return; + } + if (object instanceof FilterByTag) { + display.place(FilterByTagView.from((FilterByTag) object)); + return; + } // Code should not reach here unless there is programmer error throw new UnsupportedOperationException(); diff --git a/src/test/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommandTest.java b/src/test/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommandTest.java index b41456acde8..cf6da042d14 100644 --- a/src/test/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommandTest.java +++ b/src/test/java/seedu/foodrem/logic/commands/itemcommands/FilterTagCommandTest.java @@ -16,11 +16,11 @@ import seedu.foodrem.model.UserPrefs; import seedu.foodrem.model.tag.Tag; import seedu.foodrem.testutil.TagBuilder; +import seedu.foodrem.viewmodels.FilterByTag; public class FilterTagCommandTest { private static final String EXPECTED_ERROR_NOT_FOUND = "This tag does not exist in the FoodRem"; - private static final String EXPECTED_SUCCESS_TAG_NAME = "Filtered by tag: %s\n"; - private static final String EXPECTED_SUCCESS_LIST_AFTER_FILTERING = "%1$d items after filtering!"; + private static final String EXPECTED_SUCCESS_LIST_AFTER_FILTERING = "%1$d items filtered"; private final Model model = new ModelManager(getTypicalFoodRem(), new UserPrefs()); private final Tag fruitsTag = new TagBuilder() @@ -37,30 +37,32 @@ public void execute_success() { .filter(item -> item.getTagSet().contains(vegetableTag)) .count(); - String expectedMessageVegetable = String.format(EXPECTED_SUCCESS_TAG_NAME, vegetableTag.getName()) - + String.format(EXPECTED_SUCCESS_LIST_AFTER_FILTERING, expectedSizeVegetable); + String expectedMessageVegetable = String.format(EXPECTED_SUCCESS_LIST_AFTER_FILTERING, expectedSizeVegetable); FilterTagCommand filterVegetableTagCommand = new FilterTagCommand(vegetableTag); Model expectedModelVegetable = new ModelManager(new FoodRem(model.getFoodRem()), new UserPrefs()); expectedModelVegetable.updateFilteredItemList(item -> item.getTagSet().contains(vegetableTag)); - assertCommandSuccess(filterVegetableTagCommand, model, expectedMessageVegetable, expectedModelVegetable); + assertCommandSuccess(filterVegetableTagCommand, model, + new FilterByTag(vegetableTag, "Filtered by tag:", expectedMessageVegetable), + expectedModelVegetable); long expectedSizeNumbers = model.getCurrentList() .stream() .filter(item -> item.getTagSet().contains(fruitsTag)) .count(); - String expectedMessageNumbers = String.format(EXPECTED_SUCCESS_TAG_NAME, fruitsTag.getName()) - + String.format(EXPECTED_SUCCESS_LIST_AFTER_FILTERING, expectedSizeNumbers); + String expectedMessageNumbers = String.format(EXPECTED_SUCCESS_LIST_AFTER_FILTERING, expectedSizeNumbers); FilterTagCommand filterNumbersTagCommand = new FilterTagCommand(fruitsTag); Model expectedModelNumbers = new ModelManager(new FoodRem(model.getFoodRem()), new UserPrefs()); expectedModelNumbers.updateFilteredItemList(item -> item.getTagSet().contains(fruitsTag)); - assertCommandSuccess(filterNumbersTagCommand, model, expectedMessageNumbers, expectedModelNumbers); + assertCommandSuccess(filterNumbersTagCommand, model, + new FilterByTag(fruitsTag, "Filtered by tag:", expectedMessageNumbers), + expectedModelNumbers); } @Test diff --git a/src/test/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommandTest.java b/src/test/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommandTest.java index 3038aa42dd0..5abf45c1250 100644 --- a/src/test/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommandTest.java +++ b/src/test/java/seedu/foodrem/logic/commands/tagcommands/DeleteTagCommandTest.java @@ -20,10 +20,11 @@ import seedu.foodrem.model.tag.Tag; import seedu.foodrem.testutil.TagBuilder; import seedu.foodrem.testutil.TypicalTags; +import seedu.foodrem.viewmodels.TagsWithMessage; public class DeleteTagCommandTest { private static final String EXPECTED_ERROR_NOT_FOUND = "This tag does not exist in the FoodRem"; - private static final String EXPECTED_FORMAT_SUCCESS = "Tag deleted: %1$s"; + private static final String EXPECTED_SUCCESS_MESSAGE = "Tag deleted:"; private final Model model = new ModelManager(getTypicalFoodRem(), new UserPrefs()); @@ -32,12 +33,11 @@ public void execute_deleteTag_success() { Tag tagToDelete = model.getFilteredTagList().get(INDEX_FIRST_ITEM.getZeroBased()); DeleteTagCommand deleteTagCommand = new DeleteTagCommand(tagToDelete); - String expectedMessage = String.format(EXPECTED_FORMAT_SUCCESS, tagToDelete); - ModelManager expectedModel = new ModelManager(model.getFoodRem(), new UserPrefs()); expectedModel.deleteTag(tagToDelete); - assertCommandSuccess(deleteTagCommand, model, expectedMessage, expectedModel); + assertCommandSuccess(deleteTagCommand, model, + new TagsWithMessage(EXPECTED_SUCCESS_MESSAGE, tagToDelete), expectedModel); for (Item item : model.getCurrentList()) { assertFalse(item.getTagSet().contains(tagToDelete)); @@ -54,12 +54,11 @@ public void execute_tagDeletedFromItems_success() { assertTrue(item.getTagSet().contains(tagToDelete)); } - String expectedMessage = String.format(EXPECTED_FORMAT_SUCCESS, tagToDelete); - ModelManager expectedModel = new ModelManager(model.getFoodRem(), new UserPrefs()); expectedModel.deleteTag(tagToDelete); - assertCommandSuccess(deleteTagCommand, model, expectedMessage, expectedModel); + assertCommandSuccess(deleteTagCommand, model, + new TagsWithMessage(EXPECTED_SUCCESS_MESSAGE, tagToDelete), expectedModel); // Tag should be deleted from all items for (Item item : model.getCurrentList()) { diff --git a/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandIntegrationTest.java b/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandIntegrationTest.java index 2e2ec7123fd..aa86f5b0c1e 100644 --- a/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandIntegrationTest.java +++ b/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandIntegrationTest.java @@ -12,13 +12,14 @@ import seedu.foodrem.model.UserPrefs; import seedu.foodrem.model.tag.Tag; import seedu.foodrem.testutil.TagBuilder; +import seedu.foodrem.viewmodels.TagsWithMessage; /** * Contains integration tests (interaction with the Model) for {@code AddTagCommand}. */ public class NewTagCommandIntegrationTest { private static final String EXPECTED_ERROR_DUPLICATE = "This tag already exists in FoodRem"; - private static final String EXPECTED_FORMAT_SUCCESS = "New tag added: %1$s"; + private static final String EXPECTED_SUCCESS_MESSAGE = "New tag added:"; private Model model; @@ -35,7 +36,7 @@ public void execute_newTag_success() { expectedModel.addTag(validTag); assertCommandSuccess(new NewTagCommand(validTag), model, - String.format(EXPECTED_FORMAT_SUCCESS, validTag), expectedModel); + new TagsWithMessage(EXPECTED_SUCCESS_MESSAGE, validTag), expectedModel); } @Test diff --git a/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandTest.java b/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandTest.java index bf7fff48baa..5c928505452 100644 --- a/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandTest.java +++ b/src/test/java/seedu/foodrem/logic/commands/tagcommands/NewTagCommandTest.java @@ -17,10 +17,11 @@ import seedu.foodrem.model.ReadOnlyFoodRem; import seedu.foodrem.model.tag.Tag; import seedu.foodrem.testutil.TagBuilder; +import seedu.foodrem.viewmodels.TagsWithMessage; public class NewTagCommandTest { private static final String EXPECTED_ERROR_DUPLICATE = "This tag already exists in FoodRem"; - private static final String EXPECTED_FORMAT_SUCCESS = "New tag added: %1$s"; + private static final String EXPECTED_SUCCESS_MESSAGE = "New tag added:"; @Test public void constructor_nullTag_throwsNullPointerException() { @@ -32,9 +33,10 @@ public void execute_tagAcceptedByModel_addSuccessful() throws Exception { ModelStubAcceptingTagAdded modelStub = new ModelStubAcceptingTagAdded(); Tag validTag = new TagBuilder().build(); - CommandResult commandResult = new NewTagCommand(validTag).execute(modelStub); + CommandResult commandResult = new NewTagCommand(validTag).execute(modelStub); - assertEquals(String.format(EXPECTED_FORMAT_SUCCESS, validTag), commandResult.getOutput()); + TagsWithMessage expectedOutput = new TagsWithMessage(EXPECTED_SUCCESS_MESSAGE, validTag); + assertEquals(expectedOutput, commandResult.getOutput()); assertEquals(List.of(validTag), modelStub.tagsAdded); } diff --git a/src/test/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommandTest.java b/src/test/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommandTest.java index 2d95e30f240..aa760f04e96 100644 --- a/src/test/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommandTest.java +++ b/src/test/java/seedu/foodrem/logic/commands/tagcommands/RenameTagCommandTest.java @@ -17,11 +17,12 @@ import seedu.foodrem.model.UserPrefs; import seedu.foodrem.model.tag.Tag; import seedu.foodrem.testutil.TagBuilder; +import seedu.foodrem.viewmodels.TagToRename; public class RenameTagCommandTest { private static final String EXPECTED_ERROR_NOT_FOUND = "This tag does not exist in the FoodRem."; private static final String EXPECTED_ERROR_DUPLICATE = "This tag name already exists in the FoodRem."; - private static final String EXPECTED_FORMAT_SUCCESS = "Original tag: %s\nRenamed tag: %s\n"; + private static final String EXPECTED_SUCCESS_MESSAGE = "Tag renamed:"; private final Model model = new ModelManager(getTypicalFoodRem(), new UserPrefs()); @Test @@ -30,12 +31,11 @@ public void execute_renameTag_success() { Tag renamedTag = new TagBuilder().withTagName("test").build(); RenameTagCommand renameTagCommand = new RenameTagCommand(originalTag, renamedTag); - String expectedMessage = String.format(EXPECTED_FORMAT_SUCCESS, originalTag, renamedTag); - Model expectedModel = new ModelManager(new FoodRem(model.getFoodRem()), new UserPrefs()); expectedModel.setTag(originalTag, renamedTag); - assertCommandSuccess(renameTagCommand, model, expectedMessage, expectedModel); + assertCommandSuccess(renameTagCommand, model, + new TagToRename(originalTag, renamedTag , EXPECTED_SUCCESS_MESSAGE), expectedModel); } @Test diff --git a/src/test/java/seedu/foodrem/logic/commands/tagcommands/TagCommandTest.java b/src/test/java/seedu/foodrem/logic/commands/tagcommands/TagCommandTest.java index 722fe22b67d..b215af51089 100644 --- a/src/test/java/seedu/foodrem/logic/commands/tagcommands/TagCommandTest.java +++ b/src/test/java/seedu/foodrem/logic/commands/tagcommands/TagCommandTest.java @@ -28,7 +28,7 @@ import seedu.foodrem.viewmodels.ItemWithMessage; public class TagCommandTest { - private static final String EXPECTED_SUCCESS_MESSAGE = "Item tagged successfully. View updated item below:"; + private static final String EXPECTED_SUCCESS_MESSAGE = "Item tagged successfully. Updated item:"; private static final String ERROR_DUPLICATE = "This item has already been tagged with this tag"; private static final String ERROR_NOT_FOUND_TAG = "This tag does not exist"; private static final String ERROR_NOT_FOUND_ITEM = "The item index does not exist"; diff --git a/src/test/java/seedu/foodrem/logic/commands/tagcommands/UntagCommandTest.java b/src/test/java/seedu/foodrem/logic/commands/tagcommands/UntagCommandTest.java index 47cd81ae528..2f0e00362f3 100644 --- a/src/test/java/seedu/foodrem/logic/commands/tagcommands/UntagCommandTest.java +++ b/src/test/java/seedu/foodrem/logic/commands/tagcommands/UntagCommandTest.java @@ -28,8 +28,8 @@ import seedu.foodrem.viewmodels.ItemWithMessage; public class UntagCommandTest { - private static final String EXPECTED_SUCCESS_MESSAGE = "Item untagged successfully. View updated item below:"; - private static final String ERROR_ITEM_DOES_NOT_CONTAIN_TAG = "This item is not tagged with this tag"; + private static final String EXPECTED_SUCCESS_MESSAGE = "Item untagged successfully. Updated item:"; + private static final String ERROR_ITEM_DOES_NOT_CONTAIN_TAG = "This item has not been tagged with this tag"; private static final String ERROR_NOT_FOUND_TAG = "This tag does not exist"; private static final String ERROR_NOT_FOUND_ITEM = "The item index does not exist"; diff --git a/src/test/java/seedu/foodrem/model/tag/TagTest.java b/src/test/java/seedu/foodrem/model/tag/TagTest.java index 652888a9e05..8fc5c612c28 100644 --- a/src/test/java/seedu/foodrem/model/tag/TagTest.java +++ b/src/test/java/seedu/foodrem/model/tag/TagTest.java @@ -1,5 +1,7 @@ package seedu.foodrem.model.tag; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static seedu.foodrem.testutil.Assert.assertThrows; import org.junit.jupiter.api.Test; @@ -7,13 +9,16 @@ import seedu.foodrem.logic.commands.CommandTestUtil; public class TagTest { + private static final String TAGNAME = "TagTest"; + private final Tag initialTag = new Tag(TAGNAME); + @Test - public void constructor_null_throwsNullPointerException() { + void constructor_null_throwsNullPointerException() { assertThrows(NullPointerException.class, () -> new Tag(null)); } @Test - public void constructor_invalidTagName_throwsIllegalArgumentException() { + void constructor_invalidTagName_throwsIllegalArgumentException() { assertThrows(IllegalArgumentException.class, () -> new Tag( CommandTestUtil.INVALID_TAG_NAME_DISALLOWED_PUNCTUATION)); assertThrows(IllegalArgumentException.class, () -> new Tag( @@ -21,8 +26,20 @@ public void constructor_invalidTagName_throwsIllegalArgumentException() { } @Test - public void isValidTagName() { + void isValidTagName() { // null tag name assertThrows(NullPointerException.class, () -> Tag.isValidTagName(null)); } + + @Test + void testEquals_equal() { + final Tag tagCopy = new Tag(TAGNAME); + assertEquals(tagCopy, initialTag); + } + + @Test + void testEquals_notEqual() { + final Tag tagCopy = new Tag(TAGNAME.concat("different")); + assertNotEquals(tagCopy, initialTag); + } }