{{ page.title | escape }}
+**A:** You can navigate to this site [here](https://docs.oracle.com/en/java/javase/11/install/overview-jdk-installation.html) and download Java 11 according to your system’s specifications. + +**Q:** Do I need an internet connection to run FoodRem?
+**A:** No, FoodRem can boot up and run all functionalities without an internet connection. + +**Q:** Can I use FoodRem on my mobile device?
+**A:** Unfortunately, FoodRem is only designed to run on your desktop/laptop such that you can use the command line interface. + +**Q:** How do I transfer my data to another computer?
+**A:** Install FoodRem on the other computer and overwrite the empty data file with the data file created by FoodRem in your current computer. diff --git a/docs/_ug/Features.md b/docs/_ug/Features.md new file mode 100644 index 00000000000..c4df9b4b4d2 --- /dev/null +++ b/docs/_ug/Features.md @@ -0,0 +1,28 @@ + +There are two core features that FoodRem provides: + +* Inventory Management System +* Inventory Analysis Tool + + + +### Inventory Management System + +FoodRem allows you to track your inventory during your daily operations. + +1. Quickly **create, view, edit, and remove** your available inventory. +1. **Sort** your inventory items by name, [[ quantity ]], unit, [[ bought-date:bought date]], [[ expiry-date:expiry date ]], price and remarks. +1. **Tag** [[ item:items ]] in your inventory using an efficient tagging system where you can create, rename and delete existing [[ tag:tags ]]. +1. **Filter** your inventory items by item name and tag. + +```warning +FoodRem can only hold up to 10,000 items and 100 tags! +``` + +### Inventory Analysis + +FoodRem tracks data that helps you streamline your business decisions through **statistics**: + +1. Find out how much **cost was incurred** due to food wastage. +1. Track your top 3 **most expensive items**. +1. View your items that are **expiring** soon. diff --git a/docs/_ug/HowToUseUserGuide.md b/docs/_ug/HowToUseUserGuide.md new file mode 100644 index 00000000000..3635a173e8e --- /dev/null +++ b/docs/_ug/HowToUseUserGuide.md @@ -0,0 +1,28 @@ + +Thank you for choosing FoodRem! We are delighted to have you as a user and we aim to serve you and your business well! + +```info +We **highly recommend** that you read through the User Guide in a **sequential order**. Please note the importance of the [Quick Reference Guide](#quick-reference-guide) section, which covers how to use FoodRem! +``` + +```tip +This User Guide is highly navigable; simply click on any item in the [Table of Contents](#toc-heading) and be directed to it! Clicking on the respective headings will bring you back to the Table of Contents, so it's easy to jump across sections! +``` + +If you have not installed FoodRem head over to the [Installation](#installation) section. + +Once FoodRem is installed, you can head over to the section [Quick Reference Guide](#quick-reference-guide) which covers the basics of using FoodRem. This includes: + +* FoodRem's [Layout](#layout) +* What [Items and Tags](#key-definitions) are in FoodRem +* What [Flags](#flags) and [Placeholders](#placeholders) are +* FoodRem's [Command format](#command-format) +* [Trying out](#trying-your-first-command) your first FoodRem command + +If you are an experienced user, you can refer to the [Command Summary](#command-summary) for a quick overview of all of FoodRem's commands. + +If you are stuck, refer to the section on [Troubleshooting](#troubleshooting) or [FAQ](#faq). + +You can also refer to the [Glossary](#glossary) for definitions of commonly used terms in FoodRem. + +{% include_relative _ug/AdmonitionBoxes.md %} diff --git a/docs/_ug/Installation.md b/docs/_ug/Installation.md new file mode 100644 index 00000000000..1d11be26810 --- /dev/null +++ b/docs/_ug/Installation.md @@ -0,0 +1,18 @@ + + +If you haven't installed FoodRem, simply follow these steps to set it up: + +1. Download and install [Java 11](https://docs.oracle.com/en/java/javase/11/install/overview-jdk-installation.html) on your computer +1. Download the latest `foodrem.jar` file from our [releases page](https://github.com/AY2223S1-CS2103T-W16-2/tp/releases/latest) +1. Copy the jar file to an empty folder. This will be your home folder for FoodRem +1. Double-click on the jar file to launch FoodRem + +```warning +Remember to add `foodrem.jar` into an empty folder as additional data and configuration files will be created when launching FoodRem for the first time! +``` + +Congratulations! You now have FoodRem set up. + +```danger +When you launch FoodRem, notice that you will have a folder called "data" that is created in the same folder as `foodrem.jar`. Editing the file might corrupt your data, avoid doing this unless you know what you are doing! +``` diff --git a/docs/_ug/KeyDefinitions.md b/docs/_ug/KeyDefinitions.md new file mode 100644 index 00000000000..53184ea65b6 --- /dev/null +++ b/docs/_ug/KeyDefinitions.md @@ -0,0 +1,74 @@ + +#### Item + +An [[ item:Item ]] in FoodRem represents something in your inventory. This can be an ingredient, a piece of equipment, and more. Feel free to include or exclude certain attributes for each item, although you must minimally provide a name for the item. + +The following are the attributes stored for each item: + +* Item name +* Item [[ quantity ]] +* Item unit (unit of measurement e.g. `kg`, `packets`) +* Item [[ bought-date:bought date]] +* Item [[ expiry-date:expiry date]] +* Item price +* Item remarks +* Item [[ tag:tags ]] + +FoodRem Items are unique by name and case-sensitive. This means you cannot add two or more items of the same name. + +Restrictions for all attributes can be found in the [Placeholders](#placeholders) section. + +#### Tag + +A Tag in FoodRem serves as a means to categorise and filter items. These tags are also unique and case-sensitive. + +We can tag multiple items with the same tag and each item can have multiple tags. These Tags are optional. + +Feel free to add tags as you see fit to organize your inventory. Examples of how you may use a tag can include: + +* Categorizing food items, e.g. `Vegetable`, `Herb`, `Condiment`, `Meat` +* Marking where the item is stored, e.g. `Fridge`, `Cupboard`, `Shelf` +* Noting its perishability, e.g. `Perishable`, `Non-Perishable` + +Tags can be renamed and these changes would be reflected on all items immediately. + +FoodRem Tags are unique by name and case-sensitive. This means you cannot add two or more tags of the same name. + +#### Flags + +Flags are [[ delimiter:delimiters ]] that enable FoodRem to distinguish different [[ parameter:parameters ]] without ambiguity. + +You would put in the corresponding [Placeholder](#placeholders) immediately after each flag. + +```tip +You may find the following image taken from the subsequent [Command Format](#command-format) section helpful: + +![CommandExample](images/CommandExample.png) + +``` + +Please refer to the subsequent [Command Format](#command-format) section to see how Flags and Placeholders are used together. + +| Flag | Corresponding Placeholder | +|------|---------------------------| +| n/ | ITEM_NAME
TAG_NAME | +| qty/ | QUANTITY | +| u/ | UNIT | +| bgt/ | BOUGHT_DATE | +| exp/ | EXPIRY_DATE | +| p/ | PRICE | +| r/ | REMARKS | + +#### Placeholders + +Placeholders in this User Guide refers to the UPPER_CASE words that can be replaced by valid user input supplied. These placeholders follow immediately after a [Flag](#flags). + +Please refer to the subsequent [Command Format](#command-format) section to see how Flags and Placeholders are used together. + +```note +The placeholders `INDEX`, `COMMAND_WORD`, and `KEYWORD` do not have any corresponding flags. They are marked as "Not Applicable" in the table below. +``` + +{% include_relative _ug/Placeholders.md %} + +{% include page-break.html %} diff --git a/docs/_ug/Layout.md b/docs/_ug/Layout.md new file mode 100644 index 00000000000..9d9dc900c24 --- /dev/null +++ b/docs/_ug/Layout.md @@ -0,0 +1,20 @@ + + + +When you launch FoodRem, FoodRem appears on your screen as a [[ graphical-user-interface:Graphical User Interface ]], or GUI. Let's look at the layout of the different components of FoodRem. + +FoodRem's GUI consists of a single main window, as well as the [[ help-window:Help Window ]]. The main window consists of three components: + +1. Command Input Box +1. Item List Box +1. Command Output Box + +The following picture of the main window shows the three components, numbered accordingly: + +![FoodRem UI](images/UiAnnotated.png) + +Besides the main window, FoodRem also has the Help Window. It is not part of the main GUI and is only shown after a [Help Command](#receive-help-during-usage-help) is run. + +The Help Window looks like the following: + +![Help Window](images/HelpWindow.png) diff --git a/docs/_ug/Placeholders.md b/docs/_ug/Placeholders.md new file mode 100644 index 00000000000..97ee7bd3086 --- /dev/null +++ b/docs/_ug/Placeholders.md @@ -0,0 +1,62 @@ + + + + +{% capture INDEX %}{% include_relative _ug/placeholders/INDEX.md %}{% endcapture %} +{% capture ITEM_NAME %}{% include_relative _ug/placeholders/ITEM_NAME.md %}{% endcapture %} +{% capture TAG_NAME %}{% include_relative _ug/placeholders/TAG_NAME.md %}{% endcapture %} +{% capture QUANTITY %}{% include_relative _ug/placeholders/QUANTITY.md %}{% endcapture %} +{% capture UNIT %}{% include_relative _ug/placeholders/UNIT.md %}{% endcapture %} +{% capture BOUGHT_DATE %}{% include_relative _ug/placeholders/BOUGHT_DATE.md %}{% endcapture %} +{% capture EXPIRY_DATE %}{% include_relative _ug/placeholders/EXPIRY_DATE.md %}{% endcapture %} +{% capture PRICE %}{% include_relative _ug/placeholders/PRICE.md %}{% endcapture %} +{% capture REMARKS %}{% include_relative _ug/placeholders/REMARKS.md %}{% endcapture %} +{% capture COMMAND_WORD %}{% include_relative _ug/placeholders/COMMAND_WORD.md %}{% endcapture %} +{% capture KEYWORD %}{% include_relative _ug/placeholders/KEYWORD.md %}{% endcapture %} + +{% assign INDEX = INDEX | markdownify %} +{% assign ITEM_NAME = ITEM_NAME | markdownify %} +{% assign TAG_NAME = TAG_NAME | markdownify %} +{% assign QUANTITY = QUANTITY | markdownify %} +{% assign UNIT = UNIT | markdownify %} +{% assign BOUGHT_DATE = BOUGHT_DATE | markdownify %} +{% assign EXPIRY_DATE = EXPIRY_DATE | markdownify %} +{% assign PRICE = PRICE | markdownify %} +{% assign REMARKS = REMARKS | markdownify %} +{% assign COMMAND_WORD = COMMAND_WORD | markdownify %} +{% assign KEYWORD = KEYWORD | markdownify %} + + + + +{% capture TABLE %} +| Placeholder | Corresponding Flag | Description | +|--------------|---------------------|----------------| +| INDEX | (Not Applicable) | :INDEX: | +| ITEM_NAME | n/ | :ITEM_NAME: | +| TAG_NAME | n/ | :TAG_NAME: | +| QUANTITY | qty/ | :QUANTITY: | +| UNIT | u/ | :UNIT: | +| BOUGHT_DATE | bgt/ | :BOUGHT_DATE: | +| EXPIRY_DATE | exp/ | :EXPIRY_DATE: | +| PRICE | p/ | :PRICE: | +| REMARKS | r/ | :REMARKS: | +| COMMAND_WORD | (Not Applicable) | :COMMAND_WORD: | +| KEYWORD | (Not Applicable) | :KEYWORD: | +{% endcapture %} + + +{{ TABLE + | markdownify + | replace: ":INDEX:", INDEX + | replace: ":ITEM_NAME:", ITEM_NAME + | replace: ":TAG_NAME:", TAG_NAME + | replace: ":QUANTITY:", QUANTITY + | replace: ":UNIT:", UNIT + | replace: ":BOUGHT_DATE:", BOUGHT_DATE + | replace: ":EXPIRY_DATE:", EXPIRY_DATE + | replace: ":PRICE:", PRICE + | replace: ":REMARKS:", REMARKS + | replace: ":COMMAND_WORD:", COMMAND_WORD + | replace: ":KEYWORD:", KEYWORD +}} diff --git a/docs/_ug/QuickstartGuide.md b/docs/_ug/QuickstartGuide.md new file mode 100644 index 00000000000..9f35cfa6bb0 --- /dev/null +++ b/docs/_ug/QuickstartGuide.md @@ -0,0 +1,29 @@ + + +This section covers all you should know about FoodRem, as well as a [guided tutorial](#trying-your-first-command). Of special note is the [Key Definitions](#key-definitions) and [Command Format](#command-format) sections, which covers essential knowledge to using FoodRem's features. + +### Layout + +{% include_relative _ug/Layout.md %} + +### Key Definitions + +{% include_relative _ug/KeyDefinitions.md %} + +### Command Format + +You will encounter FoodRem [[ command:commands ]] throughout this User Guide. Before you delve into the different commands in [Commands](#commands), let’s learn what a command consists of. + +Here is an example: + +![CommandExample](images/CommandExample.png) + +A command consists of: + +1. Command Word: Tells FoodRem what action you wish to execute. These actions are covered in [Commands](#commands). +1. [Flags](#flags): Distinguishes between inputs. A flag is usually followed by a placeholder. +1. [Placeholders](#placeholders): Represents data that you wish to input. Replace this with valid data. For example, `ITEM_NAME` in `n/ITEM_NAME` can be replaced with `n/Potato`. + +### Trying your first command + +{% include_relative _ug/TryingFirstCommand.md %} diff --git a/docs/_ug/Troubleshooting.md b/docs/_ug/Troubleshooting.md new file mode 100644 index 00000000000..38ca8237e88 --- /dev/null +++ b/docs/_ug/Troubleshooting.md @@ -0,0 +1,48 @@ + +**Problem:** + +The JAR file not launching even after double-clicking the file. + +**Solution:** + +1. Open your terminal + * Windows: + * The default key combination to launch your terminal is Ctrl+Shift+P + * Mac: + * Use Cmd+Space to open Spotlight Search + * Search for "terminal" and click it to launch. +1. Navigate to the location where "foodrem.jar" is stored within your terminal. +1. On your terminal, run `java -jar "foodrem.jar"` + + +**Problem:** + +The JAR file not launching in Windows Subsystem for Linux (WSL). + +```note +WSL does not support GUI applications by default. +``` +**Solution:** + +1. Our recommendation is to run FoodRem on Windows and not on WSL. + +**Problem:** + +The JAR file not launching in Linux machines running Wayland. + +**Solution:** + +```info +Under the hood, FoodRem uses JavaFX 11 to render the UI for the GUI. +Unfortunately, JavaFX 11 has poor support for Wayland which is why FoodRem is unable to support Wayland currently. +``` + +1. FoodRem is only supported on machines with the following operating systems: Windows, macOS and Linux11. Please use a computer running on these operating systems. + +**Problem:** + +Unable to exit/save FoodRem to data file + +**Solution:** + +1. This error is due to `foodrem.jar` being started in a protected folder. (Examples of write-protected folders include `C:\WINDOWS\System32` in windows and the `/etc` dir in linux)
Please move the `foodrem.jar` file into another folder in your computer and start FoodRem from that folder. diff --git a/docs/_ug/TryingFirstCommand.md b/docs/_ug/TryingFirstCommand.md new file mode 100644 index 00000000000..debdd36b7ae --- /dev/null +++ b/docs/_ug/TryingFirstCommand.md @@ -0,0 +1,91 @@ + + +To let you become more familiar with FoodRem, let's practice executing some [[ command:commands ]]. + +To start off, let's try out the `new` command! This command lets you add an [Item](#item) to FoodRem. + +One of the available commands in FoodRem is the command to create a new item. + +**Format:** `new n/ITEM_NAME [qty/QUANTITY] [u/UNIT] [bgt/BOUGHT_DATE] [exp/EXPIRY_DATE] [p/PRICE] [r/REMARKS]` + +**What does the format mean?** + +The first word of every command allows FoodRem to distinguish different commands. + +* `new` tells FoodRem that this is the command to create a new item +* [Flags](#flags) such as `n/` and `qty/` are [[ delimiter:delimiters ]] that enable FoodRem to distinguish different [[ parameter:parameters ]] supplied by you without ambiguity +* [Placeholders](#placeholders) such as `ITEM_NAME` and `QUANTITY` shows you what you should place in each portion of the command + +Notice that there is a pair of square brackets `[]` surrounding some [[ parameter:parameters ]] like `qty/QUANTITY` in the format. This indicates that the parameter is **optional**. Each of these [[ placeholder:placeholders ]] in the [[ parameter:parameters ]] have a default value based on the commands. These are documented in the [Commands](#commands) section for each command. + +```note +The [Placeholder](#placeholders) section covers the restrictions for respective placeholders. For example, the date format of BOUGHT_DATE, certain characters you cannot use and the limit and precision of numbers. +``` + +**Let's try an example!** + +Suppose you just bought 30 kg worth of potatoes, today is 5th September 2022, and you do not feel the need to record an [[ expiry-date:expiry date ]], price or remarks for this item. + +`ITEM_NAME`: Potatoes + +`QUANTITY`: 30 + +`UNIT`: kg + +`BOUGHT_DATE`: 05-09-2022 + +The command you would like to enter into the command box would be: + +`new n/Potatoes qty/30 u/kg bgt/05-09-2022` + +Alternatively, executing these would do the same thing: + +* `new qty/30 n/Potatoes bgt/05-09-2022 u/kg` + + This is because the order of the flags does not matter. + +* `new qty/100 n/Carrots qty/30 n/Potatoes bgt/05-09-2022 u/kg` + + {{ site.data.constraints.lastValueOfDuplicates }} In this case, the name "Carrots" will be overridden by "Potatoes", and the quantity "100" will be overridden by "30". + +However, note that the following executions are invalid: + +* `newn/Potatoesqty/30u/kgbgt/05-09-2022` + + There must be between the placeholders and flags. + +* `new qty/-48 n/PÖtátÖes bgt/05/09/22 u/|kg|` + + The restrictions of placeholders are not followed. + +* `new` + + There is insufficient information provided; you must minimally provide a name. + +Find out more about restrictions in the sections [Flags](#flags), [Placeholders](#placeholders) and [Commands](#commands). + +--- + +Let's try out another command -- the `inc` command! `inc` lets you increment the quantity of an item. + +```warning +The format for different commands are not always identical. For example, executing the `new` command and the `inc` command will have different formats! +``` + +For example, after creating the potatoes item, you decided to buy 40 kg more of potatoes. + +**Format:** `inc INDEX [qty/QUANTITY]` + +Suppose the `INDEX` for potatoes is `1` in the application, the command you would like to enter into the [Command Input Box](#layout) would be: + +`inc 1 qty/40` + +You should now have a better understanding of how commands are formatted and used. All commands are consolidated in the [Command Summary](#command-summary). + +Here is a checklist you can use before running a [[ command ]]: + +* [ ] I know the restrictions of the command +* [ ] I know what [[ parameter:parameters ]] are supplied to the command +* [ ] I know the [[ flag:flags ]] for each parameter to be supplied +* [ ] I know the restrictions of each parameter +* [ ] I know the effects of not specifying each optional flag. diff --git a/docs/_ug/commandSummary/GeneralCommands.md b/docs/_ug/commandSummary/GeneralCommands.md new file mode 100644 index 00000000000..45fed9d6800 --- /dev/null +++ b/docs/_ug/commandSummary/GeneralCommands.md @@ -0,0 +1,41 @@ + + + + +{% capture help %}{% include_relative _ug/commandSummary/generalCommands/help.md %}{% endcapture %} +{% capture reset %}{% include_relative _ug/commandSummary/generalCommands/reset.md %}{% endcapture %} +{% capture exit %}{% include_relative _ug/commandSummary/generalCommands/exit.md %}{% endcapture %} + +{% assign help = help | markdownify %} +{% assign reset = reset | markdownify %} +{% assign exit = exit | markdownify %} + +{% capture helpexample %}{% include_relative _ug/commandSummary/generalCommandsExamples/help.md %}{% endcapture %} +{% capture resetexample %}{% include_relative _ug/commandSummary/generalCommandsExamples/reset.md %}{% endcapture %} +{% capture exitexample %}{% include_relative _ug/commandSummary/generalCommandsExamples/exit.md %}{% endcapture %} + +{% assign helpexample = helpexample | markdownify %} +{% assign resetexample = resetexample | markdownify %} +{% assign exitexample = exitexample | markdownify %} + + + + +{% capture TABLE %} +| Action | Format | Example | +|-------------------------------------------------------|---------|----------------| +| Shows a help dialog with a list of available commands | :help: | :helpexample: | +| Clears all items and tags in FoodRem | :reset: | :resetexample: | +| Exits FoodRem | :exit: | :exitexample: | +{% endcapture %} + + +{{ TABLE + | markdownify + | replace: ":help:", help + | replace: ":reset:", reset + | replace: ":exit:", exit + | replace: ":helpexample:", helpexample + | replace: ":resetexample:", resetexample + | replace: ":exitexample:", exitexample +}} diff --git a/docs/_ug/commandSummary/ItemCommands.md b/docs/_ug/commandSummary/ItemCommands.md new file mode 100644 index 00000000000..f876fb93c75 --- /dev/null +++ b/docs/_ug/commandSummary/ItemCommands.md @@ -0,0 +1,90 @@ + + + + +{% capture new %}{% include_relative _ug/commandSummary/itemCommands/new.md %}{% endcapture %} +{% capture list %}{% include_relative _ug/commandSummary/itemCommands/list.md %}{% endcapture %} +{% capture find %}{% include_relative _ug/commandSummary/itemCommands/find.md %}{% endcapture %} +{% capture sort %}{% include_relative _ug/commandSummary/itemCommands/sort.md %}{% endcapture %} +{% capture view %}{% include_relative _ug/commandSummary/itemCommands/view.md %}{% endcapture %} +{% capture inc %}{% include_relative _ug/commandSummary/itemCommands/inc.md %}{% endcapture %} +{% capture dec %}{% include_relative _ug/commandSummary/itemCommands/dec.md %}{% endcapture %} +{% capture edit %}{% include_relative _ug/commandSummary/itemCommands/edit.md %}{% endcapture %} +{% capture rmk %}{% include_relative _ug/commandSummary/itemCommands/rmk.md %}{% endcapture %} +{% capture del %}{% include_relative _ug/commandSummary/itemCommands/del.md %}{% endcapture %} + +{% assign new = new | markdownify %} +{% assign list = list | markdownify %} +{% assign find = find | markdownify %} +{% assign sort = sort | markdownify %} +{% assign view = view | markdownify %} +{% assign inc = inc | markdownify %} +{% assign dec = dec | markdownify %} +{% assign edit = edit | markdownify %} +{% assign rmk = rmk | markdownify %} +{% assign del = del | markdownify %} + +{% capture newexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/new.md %}{% endcapture %} +{% capture listexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/list.md %}{% endcapture %} +{% capture findexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/find.md %}{% endcapture %} +{% capture sortexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/sort.md %}{% endcapture %} +{% capture viewexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/view.md %}{% endcapture %} +{% capture incexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/inc.md %}{% endcapture %} +{% capture decexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/dec.md %}{% endcapture %} +{% capture editexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/edit.md %}{% endcapture %} +{% capture rmkexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/rmk.md %}{% endcapture %} +{% capture delexample %}{% include_relative _ug/commandSummary/itemCommandsExamples/del.md %}{% endcapture %} + +{% assign newexample = newexample | markdownify %} +{% assign listexample = listexample | markdownify %} +{% assign findexample = findexample | markdownify %} +{% assign sortexample = sortexample | markdownify %} +{% assign viewexample = viewexample | markdownify %} +{% assign incexample = incexample | markdownify %} +{% assign decexample = decexample | markdownify %} +{% assign editexample = editexample | markdownify %} +{% assign rmkexample = rmkexample | markdownify %} +{% assign delexample = delexample | markdownify %} + + + + +{% capture TABLE %} +| Action | Format | Example | +|------------------------------------------------------------------------------------|--------|---------------| +| Create a new item | :new: | :newexample: | +| List all items | :list: | :listexample: | +| Search for an item | :find: | :findexample: | +| Sort all items by name, quantity, unit, bought date, expiry date, price or remark | :sort: | :sortexample: | +| View the information of an item | :view: | :viewexample: | +| Increase the quantity of an item | :inc: | :incexample: | +| Decrease the quantity of an item | :dec: | :decexample: | +| Edit the information of an item | :edit: | :editexample: | +| Add a remark to an item | :rmk: | :rmkexample: | +| Delete an item | :del: | :delexample: | +{% endcapture %} + + +{{ TABLE + | markdownify + | replace: ":new:", new + | replace: ":list:", list + | replace: ":find:", find + | replace: ":sort:", sort + | replace: ":view:", view + | replace: ":inc:", inc + | replace: ":dec:", dec + | replace: ":edit:", edit + | replace: ":rmk:", rmk + | replace: ":del:", del + | replace: ":newexample:", newexample + | replace: ":listexample:", listexample + | replace: ":findexample:", findexample + | replace: ":sortexample:", sortexample + | replace: ":viewexample:", viewexample + | replace: ":incexample:", incexample + | replace: ":decexample:", decexample + | replace: ":editexample:", editexample + | replace: ":rmkexample:", rmkexample + | replace: ":delexample:", delexample +}} diff --git a/docs/_ug/commandSummary/StatisticsCommands.md b/docs/_ug/commandSummary/StatisticsCommands.md new file mode 100644 index 00000000000..cc01803311b --- /dev/null +++ b/docs/_ug/commandSummary/StatisticsCommands.md @@ -0,0 +1,24 @@ + + + + +{% capture stats %}{% include_relative _ug/commandSummary/statisticsCommands/stats.md %}{% endcapture %} +{% assign stats = stats | markdownify %} +{% capture statsexample %}{% include_relative _ug/commandSummary/statisticsCommandsExamples/stats.md %}{% endcapture %} +{% assign statsexample = statsexample | markdownify %} + + + + +{% capture TABLE %} +| Action | Format | Example | +|-------------------------------------------------------|---------|----------------| +| Displays all statistics collected by FoodRem | :stats: | :statsexample: | +{% endcapture %} + + +{{ TABLE +| markdownify +| replace: ":stats:", stats +| replace: ":statsexample:", statsexample +}} diff --git a/docs/_ug/commandSummary/TagCommands.md b/docs/_ug/commandSummary/TagCommands.md new file mode 100644 index 00000000000..dbcb3fcb302 --- /dev/null +++ b/docs/_ug/commandSummary/TagCommands.md @@ -0,0 +1,69 @@ + + + + +{% capture newtag %}{% include_relative _ug/commandSummary/tagCommands/newtag.md %}{% endcapture %} +{% capture listtag %}{% include_relative _ug/commandSummary/tagCommands/listtag.md %}{% endcapture %} +{% capture tag %}{% include_relative _ug/commandSummary/tagCommands/tag.md %}{% endcapture %} +{% capture untag %}{% include_relative _ug/commandSummary/tagCommands/untag.md %}{% endcapture %} +{% capture renametag %}{% include_relative _ug/commandSummary/tagCommands/renametag.md %}{% endcapture %} +{% capture deletetag %}{% include_relative _ug/commandSummary/tagCommands/deletetag.md %}{% endcapture %} +{% capture filtertag %}{% include_relative _ug/commandSummary/tagCommands/filtertag.md %}{% endcapture %} + +{% assign newtag = newtag | markdownify %} +{% assign listtag = listtag | markdownify %} +{% assign tag = tag | markdownify %} +{% assign untag = untag | markdownify %} +{% assign renametag = renametag | markdownify %} +{% assign deletetag = deletetag | markdownify %} +{% assign filtertag = filtertag | markdownify %} + +{% capture newtagexample %}{% include_relative _ug/commandSummary/tagCommandsExamples/newtag.md %}{% endcapture %} +{% capture listtagexample %}{% include_relative _ug/commandSummary/tagCommandsExamples/listtag.md %}{% endcapture %} +{% capture tagexample %}{% include_relative _ug/commandSummary/tagCommandsExamples/tag.md %}{% endcapture %} +{% capture untagexample %}{% include_relative _ug/commandSummary/tagCommandsExamples/untag.md %}{% endcapture %} +{% capture renametagexample %}{% include_relative _ug/commandSummary/tagCommandsExamples/renametag.md %}{% endcapture %} +{% capture deletetagexample %}{% include_relative _ug/commandSummary/tagCommandsExamples/deletetag.md %}{% endcapture %} +{% capture filtertagexample %}{% include_relative _ug/commandSummary/tagCommandsExamples/filtertag.md %}{% endcapture %} + +{% assign newtagexample = newtagexample | markdownify %} +{% assign listtagexample = listtagexample | markdownify %} +{% assign tagexample = tagexample | markdownify %} +{% assign untagexample = untagexample | markdownify %} +{% assign renametagexample = renametagexample | markdownify %} +{% assign deletetagexample = deletetagexample | markdownify %} +{% assign filtertagexample = filtertagexample | markdownify %} + + + + +{% capture TABLE %} +| Action | Format | Example | +|---------------------|-------------|--------------------| +| Create a new tag | :newtag: | :newtagexample: | +| List all tags | :listtag: | :listtagexample: | +| Tag an item | :tag: | :tagexample: | +| Untag an item | :untag: | :untagexample: | +| Rename a tag | :renametag: | :renametagexample: | +| Delete a tag | :deletetag: | :deletetagexample: | +| Filter items by tag | :filtertag: | :filtertagexample: | +{% endcapture %} + + +{{ TABLE + | markdownify + | replace: ":newtag:", newtag + | replace: ":listtag:", listtag + | replace: ":tag:", tag + | replace: ":untag:", untag + | replace: ":renametag:", renametag + | replace: ":deletetag:", deletetag + | replace: ":filtertag:", filtertag + | replace: ":newtagexample:", newtagexample + | replace: ":listtagexample:", listtagexample + | replace: ":tagexample:", tagexample + | replace: ":untagexample:", untagexample + | replace: ":renametagexample:", renametagexample + | replace: ":deletetagexample:", deletetagexample + | replace: ":filtertagexample:", filtertagexample +}} diff --git a/docs/_ug/commandSummary/generalCommands/exit.md b/docs/_ug/commandSummary/generalCommands/exit.md new file mode 100644 index 00000000000..3fa3f6bfe1f --- /dev/null +++ b/docs/_ug/commandSummary/generalCommands/exit.md @@ -0,0 +1,2 @@ + +`exit` diff --git a/docs/_ug/commandSummary/generalCommands/help.md b/docs/_ug/commandSummary/generalCommands/help.md new file mode 100644 index 00000000000..e9372f385ab --- /dev/null +++ b/docs/_ug/commandSummary/generalCommands/help.md @@ -0,0 +1,2 @@ + +`help` diff --git a/docs/_ug/commandSummary/generalCommands/reset.md b/docs/_ug/commandSummary/generalCommands/reset.md new file mode 100644 index 00000000000..57ac8a36a74 --- /dev/null +++ b/docs/_ug/commandSummary/generalCommands/reset.md @@ -0,0 +1,2 @@ + +`reset` diff --git a/docs/_ug/commandSummary/generalCommandsExamples/exit.md b/docs/_ug/commandSummary/generalCommandsExamples/exit.md new file mode 100644 index 00000000000..3fa3f6bfe1f --- /dev/null +++ b/docs/_ug/commandSummary/generalCommandsExamples/exit.md @@ -0,0 +1,2 @@ + +`exit` diff --git a/docs/_ug/commandSummary/generalCommandsExamples/help.md b/docs/_ug/commandSummary/generalCommandsExamples/help.md new file mode 100644 index 00000000000..e9372f385ab --- /dev/null +++ b/docs/_ug/commandSummary/generalCommandsExamples/help.md @@ -0,0 +1,2 @@ + +`help` diff --git a/docs/_ug/commandSummary/generalCommandsExamples/reset.md b/docs/_ug/commandSummary/generalCommandsExamples/reset.md new file mode 100644 index 00000000000..57ac8a36a74 --- /dev/null +++ b/docs/_ug/commandSummary/generalCommandsExamples/reset.md @@ -0,0 +1,2 @@ + +`reset` diff --git a/docs/_ug/commandSummary/itemCommands/dec.md b/docs/_ug/commandSummary/itemCommands/dec.md new file mode 100644 index 00000000000..50d62920851 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/dec.md @@ -0,0 +1,2 @@ + +`dec INDEX [qty/QUANTITY]` diff --git a/docs/_ug/commandSummary/itemCommands/del.md b/docs/_ug/commandSummary/itemCommands/del.md new file mode 100644 index 00000000000..3630c1d73a2 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/del.md @@ -0,0 +1,2 @@ + +`del INDEX` diff --git a/docs/_ug/commandSummary/itemCommands/edit.md b/docs/_ug/commandSummary/itemCommands/edit.md new file mode 100644 index 00000000000..7d092d26ade --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/edit.md @@ -0,0 +1,2 @@ + +`edit INDEX [n/ITEM_NAME] [qty/QUANTITY] [u/UNIT] [bgt/BOUGHT_DATE] [exp/EXPIRY_DATE] [p/PRICE] [R/REMARKS]` diff --git a/docs/_ug/commandSummary/itemCommands/find.md b/docs/_ug/commandSummary/itemCommands/find.md new file mode 100644 index 00000000000..fa6f3391b21 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/find.md @@ -0,0 +1,4 @@ + +`find KEYWORD [KEYWORD...]` _(Minimally one `KEYWORD` must be provided)_ + +**Note**: You can provide multiple keywords to find an item. For example, `find potato chips yellow`. diff --git a/docs/_ug/commandSummary/itemCommands/inc.md b/docs/_ug/commandSummary/itemCommands/inc.md new file mode 100644 index 00000000000..58a2799063c --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/inc.md @@ -0,0 +1,2 @@ + +`inc INDEX [qty/QUANTITY]` diff --git a/docs/_ug/commandSummary/itemCommands/list.md b/docs/_ug/commandSummary/itemCommands/list.md new file mode 100644 index 00000000000..b08cb5b8c11 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/list.md @@ -0,0 +1,2 @@ + +`list` diff --git a/docs/_ug/commandSummary/itemCommands/new.md b/docs/_ug/commandSummary/itemCommands/new.md new file mode 100644 index 00000000000..688ff9c6f72 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/new.md @@ -0,0 +1,2 @@ + +`new n/ITEM_NAME [qty/QUANTITY] [u/UNIT] [bgt/BOUGHT_DATE] [exp/EXPIRY_DATE] [p/PRICE] [r/REMARKS]` diff --git a/docs/_ug/commandSummary/itemCommands/rmk.md b/docs/_ug/commandSummary/itemCommands/rmk.md new file mode 100644 index 00000000000..a55655ecc5d --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/rmk.md @@ -0,0 +1,2 @@ + +`rmk INDEX [r/REMARKS]` diff --git a/docs/_ug/commandSummary/itemCommands/sort.md b/docs/_ug/commandSummary/itemCommands/sort.md new file mode 100644 index 00000000000..1577d48c781 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/sort.md @@ -0,0 +1,2 @@ + +`sort [n/] [qty/] [u/] [bgt/] [exp/] [p/] [r/]` diff --git a/docs/_ug/commandSummary/itemCommands/view.md b/docs/_ug/commandSummary/itemCommands/view.md new file mode 100644 index 00000000000..2ccfbad8dd1 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommands/view.md @@ -0,0 +1,2 @@ + +`view INDEX` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/dec.md b/docs/_ug/commandSummary/itemCommandsExamples/dec.md new file mode 100644 index 00000000000..c17cd6e0940 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/dec.md @@ -0,0 +1,2 @@ + +`dec 1 qty/100` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/del.md b/docs/_ug/commandSummary/itemCommandsExamples/del.md new file mode 100644 index 00000000000..a23635e1f64 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/del.md @@ -0,0 +1,2 @@ + +`del 1` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/edit.md b/docs/_ug/commandSummary/itemCommandsExamples/edit.md new file mode 100644 index 00000000000..dcbee826ab2 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/edit.md @@ -0,0 +1,2 @@ + +`edit 1 n/Potatoes qty/60 u/kg` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/find.md b/docs/_ug/commandSummary/itemCommandsExamples/find.md new file mode 100644 index 00000000000..05cb6ad4379 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/find.md @@ -0,0 +1,2 @@ + +`find Potato` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/inc.md b/docs/_ug/commandSummary/itemCommandsExamples/inc.md new file mode 100644 index 00000000000..d6f18978b3e --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/inc.md @@ -0,0 +1,2 @@ + +`inc 1 qty/100` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/list.md b/docs/_ug/commandSummary/itemCommandsExamples/list.md new file mode 100644 index 00000000000..b08cb5b8c11 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/list.md @@ -0,0 +1,2 @@ + +`list` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/new.md b/docs/_ug/commandSummary/itemCommandsExamples/new.md new file mode 100644 index 00000000000..0272bb92d91 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/new.md @@ -0,0 +1,2 @@ + +`new n/Potato qty/70 u/kg bgt/01-02-2022 exp/01-03-2022` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/rmk.md b/docs/_ug/commandSummary/itemCommandsExamples/rmk.md new file mode 100644 index 00000000000..df1d579fb8d --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/rmk.md @@ -0,0 +1,2 @@ + +`rmk 1 r/For Party` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/sort.md b/docs/_ug/commandSummary/itemCommandsExamples/sort.md new file mode 100644 index 00000000000..ce36d2c2c79 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/sort.md @@ -0,0 +1,2 @@ + +`sort n/` diff --git a/docs/_ug/commandSummary/itemCommandsExamples/view.md b/docs/_ug/commandSummary/itemCommandsExamples/view.md new file mode 100644 index 00000000000..fb016a9bc80 --- /dev/null +++ b/docs/_ug/commandSummary/itemCommandsExamples/view.md @@ -0,0 +1,2 @@ + +`view 1` diff --git a/docs/_ug/commandSummary/statisticsCommands/stats.md b/docs/_ug/commandSummary/statisticsCommands/stats.md new file mode 100644 index 00000000000..e24c0d50910 --- /dev/null +++ b/docs/_ug/commandSummary/statisticsCommands/stats.md @@ -0,0 +1,2 @@ + +`stats` diff --git a/docs/_ug/commandSummary/statisticsCommandsExamples/stats.md b/docs/_ug/commandSummary/statisticsCommandsExamples/stats.md new file mode 100644 index 00000000000..e24c0d50910 --- /dev/null +++ b/docs/_ug/commandSummary/statisticsCommandsExamples/stats.md @@ -0,0 +1,2 @@ + +`stats` diff --git a/docs/_ug/commandSummary/tagCommands/deletetag.md b/docs/_ug/commandSummary/tagCommands/deletetag.md new file mode 100644 index 00000000000..f57d5c2682c --- /dev/null +++ b/docs/_ug/commandSummary/tagCommands/deletetag.md @@ -0,0 +1,2 @@ + +`deletetag n/TAG_NAME` diff --git a/docs/_ug/commandSummary/tagCommands/filtertag.md b/docs/_ug/commandSummary/tagCommands/filtertag.md new file mode 100644 index 00000000000..22ef1f61607 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommands/filtertag.md @@ -0,0 +1,2 @@ + +`filtertag n/TAG_NAME` diff --git a/docs/_ug/commandSummary/tagCommands/listtag.md b/docs/_ug/commandSummary/tagCommands/listtag.md new file mode 100644 index 00000000000..54f8dec5725 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommands/listtag.md @@ -0,0 +1,2 @@ + +`listtag` diff --git a/docs/_ug/commandSummary/tagCommands/newtag.md b/docs/_ug/commandSummary/tagCommands/newtag.md new file mode 100644 index 00000000000..1d5abe22125 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommands/newtag.md @@ -0,0 +1,2 @@ + +`newtag n/TAG_NAME` diff --git a/docs/_ug/commandSummary/tagCommands/renametag.md b/docs/_ug/commandSummary/tagCommands/renametag.md new file mode 100644 index 00000000000..e00d284c175 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommands/renametag.md @@ -0,0 +1,2 @@ + +`renametag n/TAG_NAME n/TAG_NAME` diff --git a/docs/_ug/commandSummary/tagCommands/tag.md b/docs/_ug/commandSummary/tagCommands/tag.md new file mode 100644 index 00000000000..36addbdbfef --- /dev/null +++ b/docs/_ug/commandSummary/tagCommands/tag.md @@ -0,0 +1,2 @@ + +`tag INDEX n/TAG_NAME` diff --git a/docs/_ug/commandSummary/tagCommands/untag.md b/docs/_ug/commandSummary/tagCommands/untag.md new file mode 100644 index 00000000000..41ca1841b1e --- /dev/null +++ b/docs/_ug/commandSummary/tagCommands/untag.md @@ -0,0 +1,2 @@ + +`untag INDEX n/TAG_NAME` diff --git a/docs/_ug/commandSummary/tagCommandsExamples/deletetag.md b/docs/_ug/commandSummary/tagCommandsExamples/deletetag.md new file mode 100644 index 00000000000..2b2846456ae --- /dev/null +++ b/docs/_ug/commandSummary/tagCommandsExamples/deletetag.md @@ -0,0 +1,2 @@ + +`deletetag n/Food` diff --git a/docs/_ug/commandSummary/tagCommandsExamples/filtertag.md b/docs/_ug/commandSummary/tagCommandsExamples/filtertag.md new file mode 100644 index 00000000000..bfef42cde3f --- /dev/null +++ b/docs/_ug/commandSummary/tagCommandsExamples/filtertag.md @@ -0,0 +1,2 @@ + +`filtertag n/Fruits` diff --git a/docs/_ug/commandSummary/tagCommandsExamples/listtag.md b/docs/_ug/commandSummary/tagCommandsExamples/listtag.md new file mode 100644 index 00000000000..54f8dec5725 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommandsExamples/listtag.md @@ -0,0 +1,2 @@ + +`listtag` diff --git a/docs/_ug/commandSummary/tagCommandsExamples/newtag.md b/docs/_ug/commandSummary/tagCommandsExamples/newtag.md new file mode 100644 index 00000000000..296ef68b218 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommandsExamples/newtag.md @@ -0,0 +1,2 @@ + +`newtag n/Food` diff --git a/docs/_ug/commandSummary/tagCommandsExamples/renametag.md b/docs/_ug/commandSummary/tagCommandsExamples/renametag.md new file mode 100644 index 00000000000..9210972e0e7 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommandsExamples/renametag.md @@ -0,0 +1,2 @@ + +`renametag n/Condiments n/Condiment` diff --git a/docs/_ug/commandSummary/tagCommandsExamples/tag.md b/docs/_ug/commandSummary/tagCommandsExamples/tag.md new file mode 100644 index 00000000000..4127a560598 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommandsExamples/tag.md @@ -0,0 +1,2 @@ + +`tag 1 n/Condiments` diff --git a/docs/_ug/commandSummary/tagCommandsExamples/untag.md b/docs/_ug/commandSummary/tagCommandsExamples/untag.md new file mode 100644 index 00000000000..a69fff1cb80 --- /dev/null +++ b/docs/_ug/commandSummary/tagCommandsExamples/untag.md @@ -0,0 +1,2 @@ + +`untag 1 n/Condiments` diff --git a/docs/_ug/commands/GeneralCommands.md b/docs/_ug/commands/GeneralCommands.md new file mode 100644 index 00000000000..27790292ede --- /dev/null +++ b/docs/_ug/commands/GeneralCommands.md @@ -0,0 +1,143 @@ + + +#### Receive help during usage: `help` + +**Format**: `help [COMMAND_WORD]` + +> Displays help for FoodRem + +```note +COMMAND_WORD is strictly any of the following: + +* exit +* help +* reset +* dec +* del +* edit +* find +* inc +* list +* new +* rmk +* sort +* view +* deletetag +* filtertag +* listtag +* newtag +* renametag +* tag +* untag +``` + +**Example:** + + + + +
-
-However, if you have no such prior knowledge, removing a field can take a quite a bit of detective work. This tutorial takes you through that process. **At least have a read even if you don't actually do the steps yourself.** -
- ![UnsafeDeleteOnField](../images/remove/UnsafeDeleteOnField.png) - -1. Remove the usages of `address` and select `Do refactor` when you are done. - -
- ![DebuggerStep1](../images/tracing/DebuggerStep1.png) - -1. Use the _Show execution point_ feature to jump to the line of code that we stopped at:
- ![ShowExecutionPoint](../images/tracing/ShowExecutionPoint.png)
- `CommandResult commandResult = logic.execute(commandText);` is the line that you end up at (i.e., the place where we put the breakpoint). - -1. We are interested in the `logic.execute(commandText)` portion of that line so let’s _Step in_ into that method call:
- ![StepInto](../images/tracing/StepInto.png) - -1. We end up in `LogicManager#execute()` (not `Logic#execute` -- but this is expected because we know the `execute()` method in the `Logic` interface is actually implemented by the `LogicManager` class). Let’s take a look at the body of the method. Given below is the same code, with additional explanatory comments. - - **LogicManager\#execute().** - - ``` java - @Override - public CommandResult execute(String commandText) - throws CommandException, ParseException { - - //Logging, safe to ignore - logger.info("----------------[USER COMMAND][" + commandText + "]"); - - CommandResult commandResult; - //Parse user input from String to a Command - Command command = addressBookParser.parseCommand(commandText); - //Executes the Command and stores the result - commandResult = command.execute(model); - - try { - //We can deduce that the previous line of code modifies model in some way - // since it's being stored here. - storage.saveAddressBook(model.getAddressBook()); - } catch (IOException ioe) { - throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe); - } - - return commandResult; - } - ``` - -1. `LogicManager#execute()` appears to delegate most of the heavy lifting to other components. Let’s take a closer look at each one. - -1. _Step over_ the logging code since it is of no interest to us now. - ![StepOver](../images/tracing/StepOver.png) - -1. _Step into_ the line where user input in parsed from a String to a Command, which should bring you to the `AddressBookParser#parseCommand()` method (partial code given below): - ``` java - public Command parseCommand(String userInput) throws ParseException { - ... - final String commandWord = matcher.group("commandWord"); - final String arguments = matcher.group("arguments"); - ... - ``` - -1. _Step over_ the statements in that method until you reach the `switch` statement. The 'Variables' window now shows the value of both `commandWord` and `arguments`:
- ![Variables](../images/tracing/Variables.png) - -1. We see that the value of `commandWord` is now `edit` but `arguments` is still not processed in any meaningful way. - -1. Stepping through the `switch` block, we end up at a call to `EditCommandParser().parse()` as expected (because the command we typed is an edit command). - - ``` java - ... - case EditCommand.COMMAND_WORD: - return new EditCommandParser().parse(arguments); - ... - ``` - -1. Let’s see what `EditCommandParser#parse()` does by stepping into it. You might have to click the 'step into' button multiple times here because there are two method calls in that statement: `EditCommandParser()` and `parse()`. - -
- ![EditCommand](../images/tracing/EditCommand.png) - -1. As you just traced through some code involved in parsing a command, you can take a look at this class diagram to see where the various parsing-related classes you encountered fit into the design of the `Logic` component. - - -1. Let’s continue stepping through until we return to `LogicManager#execute()`. - - The sequence diagram below shows the details of the execution path through the Logic component. Does the execution path you traced in the code so far match the diagram?
- ![Tracing an `edit` command through the Logic component](../images/tracing/LogicSequenceDiagram.png) - -1. Now, step over until you read the statement that calls the `execute()` method of the `EditCommand` object received, and step into that `execute()` method (partial code given below): - - **`EditCommand#execute()`:** - ``` java - @Override - public CommandResult execute(Model model) throws CommandException { - ... - Person personToEdit = lastShownList.get(index.getZeroBased()); - Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); - if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); - } - model.setPerson(personToEdit, editedPerson); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson)); - } - ``` - -1. As suspected, `command#execute()` does indeed make changes to the `model` object. Specifically, - * it uses the `setPerson()` method (defined in the interface `Model` and implemented in `ModelManager` as per the usual pattern) to update the person data. - * it uses the `updateFilteredPersonList` method to ask the `Model` to populate the 'filtered list' with _all_ persons.
- FYI, The 'filtered list' is the list of persons resulting from the most recent operation that will be shown to the user immediately after. For the `edit` command, we populate it with all the persons so that the user can see the edited person along with all other persons. If this was a `find` command, we would be setting that list to contain the search results instead.
- To provide some context, given below is the class diagram of the `Model` component. See if you can figure out where the 'filtered list' of persons is being tracked. -
- * :bulb: This may be a good time to read through the [`Model` component section of the DG](../DeveloperGuide.html#model-component) - -1. As you step through the rest of the statements in the `EditCommand#execute()` method, you'll see that it creates a `CommandResult` object (containing information about the result of the execution) and returns it.
- Advancing the debugger by one more step should take you back to the middle of the `LogicManager#execute()` method.
- -1. Given that you have already seen quite a few classes in the `Logic` component in action, see if you can identify in this partial class diagram some of the classes you've encountered so far, and see how they fit into the class structure of the `Logic` component: - - * :bulb: This may be a good time to read through the [`Logic` component section of the DG](../DeveloperGuide.html#logic-component) - -1. Similar to before, you can step over/into statements in the `LogicManager#execute()` method to examine how the control is transferred to the `Storage` component and what happens inside that component. - -
- - * :bulb: This may be a good time to read through the [`Storage` component section of the DG](../DeveloperGuide.html#storage-component) - -1. We can continue to step through until you reach the end of the `LogicManager#execute()` method and return to the `MainWindow#executeCommand()` method (the place where we put the original breakpoint). - -1. Stepping into `resultDisplay.setFeedbackToUser(commandResult.getFeedbackToUser());`, we end up in: - - **`ResultDisplay#setFeedbackToUser()`** - ``` java - public void setFeedbackToUser(String feedbackToUser) { - requireNonNull(feedbackToUser); - resultDisplay.setText(feedbackToUser); - } - ``` - -1. Finally, you can step through until you reach the end of`MainWindow#executeCommand()`.
- :bulb: This may be a good time to read through the [`UI` component section of the DG](../DeveloperGuide.html#ui-component) - - -## Conclusion - -In this tutorial, we traced a valid edit command from raw user input to the result being displayed to the user. From this tutorial, you learned more about how the various components work together to produce a response to a user command. - -Here are some quick questions you can try to answer based on your execution path tracing. In some cases, you can do further tracing for the given commands to find exactly what happens. - -1. In this tutorial, we traced the "happy path" (i.e., no errors). What - do you think will happen if we traced the following commands - instead? What exceptions do you think will be thrown (if any), where - will the exceptions be thrown and where will they be handled? - - 1. `redit 1 n/Alice Yu` - - 2. `edit 0 n/Alice Yu` - - 3. `edit 1 n/Alex Yeoh` - - 4. `edit 1` - - 5. `edit 1 n/アリス ユー` - - 6. `edit 1 t/one t/two t/three t/one` - -2. What components will you have to modify to perform the following - enhancements to the application? - - 1. Make command words case-insensitive - - 2. Allow `delete` to remove more than one index at a time - - 3. Save the address book in the CSV format instead - - 4. Add a new command - - 5. Add a new field to `Person` - - 6. Add a new entity to the address book diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java deleted file mode 100644 index 1deb3a1e469..00000000000 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ /dev/null @@ -1,13 +0,0 @@ -package seedu.address.commons.core; - -/** - * Container for user visible messages. - */ -public class Messages { - - public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; - public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; - public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; - public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; - -} diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java deleted file mode 100644 index 19124db485c..00000000000 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ /dev/null @@ -1,21 +0,0 @@ -package seedu.address.commons.exceptions; - -/** - * Signals that some given data does not fulfill some constraints. - */ -public class IllegalValueException extends Exception { - /** - * @param message should contain relevant information on the failed constraint(s) - */ - public IllegalValueException(String message) { - super(message); - } - - /** - * @param message should contain relevant information on the failed constraint(s) - * @param cause of the main exception - */ - public IllegalValueException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java deleted file mode 100644 index 61cc8c9a1cb..00000000000 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ /dev/null @@ -1,68 +0,0 @@ -package seedu.address.commons.util; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Arrays; - -/** - * Helper functions for handling strings. - */ -public class StringUtil { - - /** - * Returns true if the {@code sentence} contains the {@code word}. - * Ignores case, but a full word match is required. - *
examples:
- * containsWordIgnoreCase("ABc def", "abc") == true - * containsWordIgnoreCase("ABc def", "DEF") == true - * containsWordIgnoreCase("ABc def", "AB") == false //not a full word match - *- * @param sentence cannot be null - * @param word cannot be null, cannot be empty, must be a single word - */ - public static boolean containsWordIgnoreCase(String sentence, String word) { - requireNonNull(sentence); - requireNonNull(word); - - String preppedWord = word.trim(); - checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty"); - checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word"); - - String preppedSentence = sentence; - String[] wordsInPreppedSentence = preppedSentence.split("\\s+"); - - return Arrays.stream(wordsInPreppedSentence) - .anyMatch(preppedWord::equalsIgnoreCase); - } - - /** - * Returns a detailed message of the t, including the stack trace. - */ - public static String getDetails(Throwable t) { - requireNonNull(t); - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); - return t.getMessage() + "\n" + sw.toString(); - } - - /** - * Returns true if {@code s} represents a non-zero unsigned integer - * e.g. 1, 2, 3, ..., {@code Integer.MAX_VALUE}
- * Will return false for any other non-null string input - * e.g. empty string, "-1", "0", "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters) - * @throws NullPointerException if {@code s} is null. - */ - public static boolean isNonZeroUnsignedInteger(String s) { - requireNonNull(s); - - try { - int value = Integer.parseInt(s); - return value > 0 && !s.startsWith("+"); // "+1" is successfully parsed by Integer#parseInt(String) - } catch (NumberFormatException nfe) { - return false; - } - } -} diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java deleted file mode 100644 index 92cd8fa605a..00000000000 --- a/src/main/java/seedu/address/logic/Logic.java +++ /dev/null @@ -1,50 +0,0 @@ -package seedu.address.logic; - -import java.nio.file.Path; - -import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; - -/** - * API of the Logic component - */ -public interface Logic { - /** - * Executes the command and returns the result. - * @param commandText The command as entered by the user. - * @return the result of the command execution. - * @throws CommandException If an error occurs during command execution. - * @throws ParseException If an error occurs during parsing. - */ - CommandResult execute(String commandText) throws CommandException, ParseException; - - /** - * Returns the AddressBook. - * - * @see seedu.address.model.Model#getAddressBook() - */ - ReadOnlyAddressBook getAddressBook(); - - /** Returns an unmodifiable view of the filtered list of persons */ - ObservableList
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found, - * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book. + * Returns a {@code ModelManager} with the data from {@code storage}'s foodRem and {@code userPrefs}.
+ * The data from the sample foodRem will be used instead if {@code storage}'s foodRem is not found, + * or an empty foodRem will be used instead if errors occur when reading {@code storage}'s foodRem. */ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { - Optional
* {@code Index} should be used right from the start (when parsing in a new user input), so that if the current
* component wants to communicate with another component, it can send an {@code Index} to avoid having to know what
* base the other component is using for its index. However, after receiving the {@code Index}, that component can
* convert it back to an int if the index will not be passed to a different component again.
*/
public class Index {
- private int zeroBasedIndex;
+ private final int zeroBasedIndex;
/**
* Index can only be created by calling {@link Index#fromZeroBased(int)} or
@@ -23,14 +23,6 @@ private Index(int zeroBasedIndex) {
this.zeroBasedIndex = zeroBasedIndex;
}
- public int getZeroBased() {
- return zeroBasedIndex;
- }
-
- public int getOneBased() {
- return zeroBasedIndex + 1;
- }
-
/**
* Creates a new {@code Index} using a zero-based index.
*/
@@ -45,10 +37,24 @@ public static Index fromOneBased(int oneBasedIndex) {
return new Index(oneBasedIndex - 1);
}
+ /**
+ * Returns the zeroBasedIndex.
+ */
+ public int getZeroBased() {
+ return zeroBasedIndex;
+ }
+
+ /**
+ * Returns the oneBasedIndex.
+ */
+ public int getOneBased() {
+ return zeroBasedIndex + 1;
+ }
+
@Override
public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Index // instanceof handles nulls
- && zeroBasedIndex == ((Index) other).zeroBasedIndex); // state check
+ return other == this
+ || (other instanceof Index
+ && zeroBasedIndex == ((Index) other).zeroBasedIndex);
}
}
diff --git a/src/main/java/seedu/foodrem/commons/enums/CommandType.java b/src/main/java/seedu/foodrem/commons/enums/CommandType.java
new file mode 100644
index 00000000000..5fb8e3726a3
--- /dev/null
+++ b/src/main/java/seedu/foodrem/commons/enums/CommandType.java
@@ -0,0 +1,363 @@
+package seedu.foodrem.commons.enums;
+
+import static seedu.foodrem.logic.commands.generalcommands.HelpCommand.DEFAULT_HELP_MESSAGE;
+import static seedu.foodrem.logic.parser.CliSyntax.PREFIX_ITEM_BOUGHT_DATE;
+import static seedu.foodrem.logic.parser.CliSyntax.PREFIX_ITEM_EXPIRY_DATE;
+import static seedu.foodrem.logic.parser.CliSyntax.PREFIX_ITEM_PRICE;
+import static seedu.foodrem.logic.parser.CliSyntax.PREFIX_ITEM_QUANTITY;
+import static seedu.foodrem.logic.parser.CliSyntax.PREFIX_ITEM_REMARKS;
+import static seedu.foodrem.logic.parser.CliSyntax.PREFIX_ITEM_UNIT;
+import static seedu.foodrem.logic.parser.CliSyntax.PREFIX_NAME;
+
+import java.util.Arrays;
+import java.util.StringJoiner;
+
+/**
+ * Represents the command word to be keyed in by a user to execute a command.
+ */
+public enum CommandType {
+ // General Commands
+ EXIT_COMMAND("exit") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Exits FoodRem.\n\n"
+ + "Example:\n"
+ + getCommandWord();
+ }
+ },
+ HELP_COMMAND("help") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Displays help for FoodRem.\n\n"
+ + "Format:\n"
+ + getCommandWord() + " [COMMAND_WORD]\n\n"
+ + "Example:\n"
+ + getCommandWord() + "\n"
+ + getCommandWord() + " new";
+ }
+ },
+ RESET_COMMAND("reset") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Clears all data in FoodRem. "
+ + "This includes all items and tags currently stored.\n\n"
+ + "Example:\n"
+ + getCommandWord();
+ }
+ },
+
+ // Item Commands
+ DECREMENT_COMMAND("dec") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Decrements the quantity of " + THE_ITEM_IN_LIST
+ + "If a quantity is not provided, the item quantity will be decremented by 1.\n\n"
+ + "Format:\n"
+ + getCommandWord() + " INDEX [" + PREFIX_ITEM_QUANTITY + "QUANTITY]\n\n"
+ + "Examples:\n"
+ + getCommandWord() + " 10\n"
+ + getCommandWord() + " 10 " + PREFIX_ITEM_QUANTITY + "100";
+ }
+ },
+ DELETE_COMMAND("del") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Deletes " + THE_ITEM_IN_LIST
+ + "\n"
+ + "Format:\n"
+ + getCommandWord() + " INDEX\n\n"
+ + "Example:\n"
+ + getCommandWord() + " 1";
+ }
+ },
+ EDIT_COMMAND("edit") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Updates the details of " + THE_ITEM_IN_LIST
+ + "Existing values will be overwritten by the input values.\n\n"
+ + "Format (At least one optional prefix must be present):\n"
+ + getCommandWord() + " INDEX "
+ + "[" + PREFIX_NAME + "ITEM_NAME] "
+ + "[" + PREFIX_ITEM_QUANTITY + "QUANTITY] "
+ + "[" + PREFIX_ITEM_UNIT + "UNIT] "
+ + "[" + PREFIX_ITEM_BOUGHT_DATE + "BOUGHT_DATE] "
+ + "[" + PREFIX_ITEM_EXPIRY_DATE + "EXPIRY_DATE] "
+ + "[" + PREFIX_ITEM_PRICE + "PRICE] "
+ + "[" + PREFIX_ITEM_REMARKS + "REMARKS]\n\n"
+ + "Examples:\n"
+ + getCommandWord() + " 1 "
+ + PREFIX_ITEM_QUANTITY + "1000 "
+ + PREFIX_ITEM_UNIT + "grams "
+ + PREFIX_ITEM_PRICE + "10.2\n"
+ + getCommandWord() + " 2 "
+ + PREFIX_NAME + "Potatoes";
+ }
+ },
+ FILTER_TAG_COMMAND("filtertag") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Filters all items in FoodRem by the specified tag"
+ + "\n\n"
+ + "Format:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "TAG_NAME\n\n"
+ + "Example:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "Vegetables ";
+ }
+ },
+ FIND_COMMAND("find") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Finds all items in FoodRem whose names contain substrings of "
+ + "the KEYWORDS (case-insensitive).\n\n"
+ + "Format:\n"
+ + getCommandWord() + " KEYWORD [KEYWORDS]...\n\n"
+ + "Examples:\n"
+ + getCommandWord() + " Potatoes\n"
+ + getCommandWord() + " Potatoes Carrots Cucumbers";
+ }
+ },
+ INCREMENT_COMMAND("inc") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Increments the quantity of " + THE_ITEM_IN_LIST
+ + "If a quantity is not provided, the item quantity will be incremented by 1.\n\n"
+ + "Format:\n"
+ + getCommandWord() + " INDEX [" + PREFIX_ITEM_QUANTITY + "QUANTITY]\n\n"
+ + "Examples:\n"
+ + getCommandWord() + " 10\n"
+ + getCommandWord() + " 10 " + PREFIX_ITEM_QUANTITY + "100";
+ }
+ },
+ LIST_COMMAND("list") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": List all items in FoodRem.\n\n"
+ + "Example:\n"
+ + getCommandWord();
+ }
+ },
+ NEW_COMMAND("new") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Creates a new item with the provided item name. "
+ + "All fields apart from ITEM_NAME are optional.\n\n"
+ + "Format:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "ITEM_NAME "
+ + "[" + PREFIX_ITEM_QUANTITY + "QUANTITY] "
+ + "[" + PREFIX_ITEM_UNIT + "UNIT] "
+ + "[" + PREFIX_ITEM_BOUGHT_DATE + "BOUGHT_DATE] "
+ + "[" + PREFIX_ITEM_EXPIRY_DATE + "EXPIRY_DATE] "
+ + "[" + PREFIX_ITEM_PRICE + "PRICE] "
+ + "[" + PREFIX_ITEM_REMARKS + "REMARKS]\n\n"
+ + "Examples:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "Potatoes\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "Potatoes "
+ + PREFIX_ITEM_QUANTITY + "10 "
+ + PREFIX_ITEM_UNIT + "kg "
+ + PREFIX_ITEM_BOUGHT_DATE + "11-10-2022 "
+ + PREFIX_ITEM_EXPIRY_DATE + "21-10-2022 "
+ + PREFIX_ITEM_PRICE + "10 "
+ + PREFIX_ITEM_REMARKS + "For Salad";
+ }
+ },
+ REMARK_COMMAND("rmk") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Adds a remark to " + THE_ITEM_IN_LIST
+ + "\nFormat:\n"
+ + getCommandWord() + " INDEX [" + PREFIX_ITEM_REMARKS + "REMARKS]\n\n"
+ + "Examples:\n"
+ + getCommandWord() + "\n"
+ + getCommandWord() + " 1 " + PREFIX_ITEM_REMARKS + "For oranges";
+ }
+ },
+ SORT_COMMAND("sort") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Sorts all items in FoodRem according to the specified criteria.\n"
+ + "Available criteria includes sorting by name, quantity, unit, bought date, expiry date, "
+ + "price and remarks.\n\n"
+ + "Format (Only one of the optional prefix should be present):\n"
+ + getCommandWord() + " "
+ + "[" + PREFIX_NAME + "] "
+ + "[" + PREFIX_ITEM_QUANTITY + "] "
+ + "[" + PREFIX_ITEM_UNIT + "] "
+ + "[" + PREFIX_ITEM_BOUGHT_DATE + "] "
+ + "[" + PREFIX_ITEM_EXPIRY_DATE + "] "
+ + "[" + PREFIX_ITEM_PRICE + "] "
+ + "[" + PREFIX_ITEM_REMARKS + "]\n\n"
+ + "Examples:\n"
+ + getCommandWord() + " " + PREFIX_NAME + "\n"
+ + getCommandWord() + " " + PREFIX_ITEM_UNIT;
+ }
+ },
+ VIEW_COMMAND("view") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Displays the information of " + THE_ITEM_IN_LIST
+ + "The name, quantity, bought date, expiry date, unit, price, remarks and associated tags "
+ + "of the items will be displayed.\n\n"
+ + "Format:\n"
+ + getCommandWord() + " INDEX\n\n"
+ + "Example:\n"
+ + getCommandWord() + " 1";
+ }
+ },
+
+ // Tag Commands
+ DELETE_TAG_COMMAND("deletetag") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Deletes an existing tag in FoodRem.\n"
+ + "\n"
+ + "Format:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "TAG_NAME\n\n"
+ + "Example:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "Vegetables";
+ }
+ },
+ LIST_TAG_COMMAND("listtag") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": List all tags in FoodRem.\n\n"
+ + "Example:\n"
+ + getCommandWord();
+ }
+ },
+ NEW_TAG_COMMAND("newtag") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Creates a tag in FoodRem.\n\n"
+ + "Format:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "TAG_NAME\n\n"
+ + "Example:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "Vegetables ";
+ }
+ },
+ RENAME_TAG_COMMAND("renametag") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Renames an existing tag in FoodRem.\n\n"
+ + "Format (Original Tag: First TAG_NAME. Renamed Tag: Second TAG_NAME.):\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "TAG_NAME "
+ + PREFIX_NAME + "TAG_NAME\n\n"
+ + "Example:\n"
+ + getCommandWord() + " "
+ + PREFIX_NAME + "Vegetables "
+ + PREFIX_NAME + "Fruits";
+ }
+ },
+ TAG_COMMAND("tag") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Tags " + THE_ITEM_IN_LIST
+ + "\n"
+ + "Format:\n"
+ + getCommandWord() + " "
+ + "INDEX "
+ + PREFIX_NAME + "TAG_NAME\n\n"
+ + "Example:\n"
+ + getCommandWord() + " "
+ + "1 "
+ + PREFIX_NAME + "Condiments";
+ }
+ },
+ UNTAG_COMMAND("untag") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Untags " + THE_ITEM_IN_LIST
+ + "\n"
+ + "Format:\n"
+ + getCommandWord() + " "
+ + "INDEX "
+ + PREFIX_NAME + "TAG_NAME\n\n"
+ + "Example:\n"
+ + getCommandWord() + " "
+ + "1 "
+ + PREFIX_NAME + "Condiments";
+ }
+ },
+
+ // STATISTICS COMMAND
+ STATS_COMMAND("stats") {
+ @Override
+ public String getUsage() {
+ return getCommandWord() + ": Display statistics collected by FoodRem."
+ + "Example: " + getCommandWord();
+ }
+ },
+
+ // INVALID
+ DEFAULT("default") {
+ @Override
+ public String getUsage() {
+ return DEFAULT_HELP_MESSAGE;
+ }
+ };
+
+ private static final String THE_ITEM_IN_LIST =
+ "the item at the specified index.\n";
+
+ private final String commandWord;
+
+ /**
+ * Constructs a CommandWord enum.
+ *
+ * @param commandWord the value representing the string value of the enum.
+ */
+ CommandType(String commandWord) {
+ this.commandWord = commandWord;
+ }
+
+ /**
+ * Returns the string value of a CommandWord.
+ *
+ * @return the string representation of a CommandWord.
+ */
+ public String getCommandWord() {
+ return commandWord;
+ }
+
+ /**
+ * Returns the string value of a help message for the CommandWord.
+ *
+ * @return the string representation a help message for a CommandWord.
+ */
+ public abstract String getUsage();
+
+ /**
+ * Returns the CommandWord object from the string value of a command word.
+ *
+ * @param word a string value of the enum represented by the value provided.
+ * @return a CommandWord object of the command represented by the string.
+ */
+ public static CommandType parseWord(String word) {
+ return Arrays.stream(values())
+ .filter(type -> type.commandWord.equals(word))
+ .findFirst().orElse(DEFAULT);
+ }
+
+ /**
+ * Returns the list of all command words separated by commas
+ */
+ public static String listAllCommandWords() {
+ StringJoiner stringJoiner = new StringJoiner(", ");
+ for (CommandType type : values()) {
+ if (type.equals(DEFAULT)) {
+ continue;
+ }
+ stringJoiner.add(type.commandWord);
+ }
+ return stringJoiner.toString();
+ }
+}
diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/foodrem/commons/exceptions/DataConversionException.java
similarity index 68%
rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java
rename to src/main/java/seedu/foodrem/commons/exceptions/DataConversionException.java
index 1f689bd8e3f..ff4a4349a81 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java
+++ b/src/main/java/seedu/foodrem/commons/exceptions/DataConversionException.java
@@ -1,11 +1,13 @@
-package seedu.address.commons.exceptions;
+package seedu.foodrem.commons.exceptions;
/**
* Represents an error during conversion of data from one format to another
*/
public class DataConversionException extends Exception {
+ /**
+ * Constructs a DataConversionException.
+ */
public DataConversionException(Exception cause) {
super(cause);
}
-
}
diff --git a/src/main/java/seedu/foodrem/commons/exceptions/ItemStorageFullException.java b/src/main/java/seedu/foodrem/commons/exceptions/ItemStorageFullException.java
new file mode 100644
index 00000000000..82469009610
--- /dev/null
+++ b/src/main/java/seedu/foodrem/commons/exceptions/ItemStorageFullException.java
@@ -0,0 +1,20 @@
+package seedu.foodrem.commons.exceptions;
+
+/**
+ * Represents an error when more items are added when the storage is full.
+ */
+public class ItemStorageFullException extends StorageFullException {
+ /**
+ * Constructs an ItemStorageFullException.
+ */
+ public ItemStorageFullException(int maxNumberOfItems) {
+ super(String.format("The item storage is full. FoodRem can only hold up to %s items.", maxNumberOfItems));
+ }
+
+ /**
+ * Constructs an ItemStorageFullException.
+ */
+ public ItemStorageFullException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/seedu/foodrem/commons/exceptions/StorageFullException.java b/src/main/java/seedu/foodrem/commons/exceptions/StorageFullException.java
new file mode 100644
index 00000000000..dc3d855f2ba
--- /dev/null
+++ b/src/main/java/seedu/foodrem/commons/exceptions/StorageFullException.java
@@ -0,0 +1,13 @@
+package seedu.foodrem.commons.exceptions;
+
+/**
+ * Represents an error when the storage is full.
+ */
+public class StorageFullException extends RuntimeException {
+ /**
+ * Constructs a StorageFullException.
+ */
+ public StorageFullException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/seedu/foodrem/commons/exceptions/TagStorageFullException.java b/src/main/java/seedu/foodrem/commons/exceptions/TagStorageFullException.java
new file mode 100644
index 00000000000..330e98e5dd3
--- /dev/null
+++ b/src/main/java/seedu/foodrem/commons/exceptions/TagStorageFullException.java
@@ -0,0 +1,20 @@
+package seedu.foodrem.commons.exceptions;
+
+/**
+ * Represents an error when more items are added when the storage is full.
+ */
+public class TagStorageFullException extends StorageFullException {
+ /**
+ * Constructs a TagStorageFullException.
+ */
+ public TagStorageFullException(int maxNumberOfTags) {
+ super(String.format("The tag storage is full. FoodRem can only hold up to %s tags.", maxNumberOfTags));
+ }
+
+ /**
+ * Constructs a TagStorageFullException.
+ */
+ public TagStorageFullException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/foodrem/commons/util/AppUtil.java
similarity index 94%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/seedu/foodrem/commons/util/AppUtil.java
index 87aa89c0326..ebe7b9cd599 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/foodrem/commons/util/AppUtil.java
@@ -1,15 +1,14 @@
-package seedu.address.commons.util;
+package seedu.foodrem.commons.util;
import static java.util.Objects.requireNonNull;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
+import seedu.foodrem.MainApp;
/**
* A container for App specific utility functions
*/
public class AppUtil {
-
/**
* Gets an {@code Image} from the specified path.
*/
diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/foodrem/commons/util/CollectionUtil.java
similarity index 87%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/seedu/foodrem/commons/util/CollectionUtil.java
index eafe4dfd681..c58f71015c8 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/seedu/foodrem/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.foodrem.commons.util;
import static java.util.Objects.requireNonNull;
@@ -11,7 +11,6 @@
* Utility methods related to Collections
*/
public class CollectionUtil {
-
/** @see #requireAllNonNull(Collection) */
public static void requireAllNonNull(Object... items) {
requireNonNull(items);
@@ -27,7 +26,7 @@ public static void requireAllNonNull(Collection> items) {
}
/**
- * Returns true if {@code items} contain any elements that are non-null.
+ * Returns {@code true} if {@code items} contain any elements that are non-null.
*/
public static boolean isAnyNonNull(Object... items) {
return items != null && Arrays.stream(items).anyMatch(Objects::nonNull);
diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/foodrem/commons/util/ConfigUtil.java
similarity index 77%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/seedu/foodrem/commons/util/ConfigUtil.java
index f7f8a2bd44c..616def2b104 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/seedu/foodrem/commons/util/ConfigUtil.java
@@ -1,17 +1,16 @@
-package seedu.address.commons.util;
+package seedu.foodrem.commons.util;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.foodrem.commons.core.Config;
+import seedu.foodrem.commons.exceptions.DataConversionException;
/**
* A class for accessing the Config File.
*/
public class ConfigUtil {
-
public static Optional
* Returns null if there are no matches
- *
*/
private Level getLoggingLevel(String loggingLevelString) {
return Level.parse(loggingLevelString);
@@ -139,5 +139,4 @@ public Class
* E.g if {@code argsString} = "e/hip/900", {@code prefix} = "p/" and
* {@code fromIndex} = 0, this method returns -1 as there are no valid
* occurrences of "p/" with whitespace before it. However, if
@@ -72,7 +72,7 @@ private static List
examples:
+ * containsWordIgnoreCase("ABc def", "abc") == true
+ * containsWordIgnoreCase("ABc def", "DEF") == true
+ * containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
+ *
+ *
+ * @param sentence cannot be null
+ * @param word cannot be null, cannot be empty, must be a single word
+ */
+ public static boolean containsWordIgnoreCase(String sentence, String word) {
+ requireNonNull(sentence);
+ requireNonNull(word);
+
+ String preppedWord = word.trim();
+ checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty");
+ checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word");
+
+ String[] wordsInPreppedSentence = sentence.split("\\s+");
+
+ return Arrays.stream(wordsInPreppedSentence)
+ .anyMatch(preppedWord::equalsIgnoreCase);
+ }
+
+ /**
+ * Returns {@code true} if the {@code sentence} contains the {@code word}.
+ * Ignores case, and does not need a full word match.
+ *
examples:
+ * containsSubstringIgnoreCase("ABc def", "abc") == true
+ * containsSubstringIgnoreCase("ABc def", "DEF") == true
+ * containsSubstringIgnoreCase("ABc def", "AB") == true
+ * containsSubstringIgnoreCase("ABc def", "GH") == false
+ *
+ *
+ * @param sentence cannot be null
+ * @param word cannot be null, cannot be empty, must be a single word
+ */
+ public static boolean containsSubstringIgnoreCase(String sentence, String word) {
+ requireNonNull(sentence);
+ requireNonNull(word);
+
+ String preppedWord = word.trim().toLowerCase();
+ checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty");
+ checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word");
+
+ String[] wordsInPreppedSentence = sentence.split("\\s+");
+
+ return Arrays.stream(wordsInPreppedSentence)
+ .anyMatch(w -> w.toLowerCase().contains(preppedWord));
+ }
+
+ /**
+ * Returns a detailed message of the t, including the stack trace.
+ */
+ public static String getDetails(Throwable t) {
+ requireNonNull(t);
+ StringWriter sw = new StringWriter();
+ t.printStackTrace(new PrintWriter(sw));
+ return t.getMessage() + "\n" + sw;
+ }
+
+ /**
+ * Returns {@code true} if {@code s} represents a non-zero unsigned integer
+ * e.g. 1, 2, 3, ..., {@code Integer.MAX_VALUE}
+ * Will return {@code false} for any other non-null string input
+ * e.g. empty string, "-1", "0", "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters)
+ *
+ * @throws NullPointerException if {@code s} is null.
+ */
+ public static boolean isNonZeroUnsignedInteger(String s) {
+ return isInteger(s) && Integer.parseInt(s) > 0;
+ }
+
+ /**
+ * Returns {@code true} if {@code s} represents an integer
+ * e.g. {@code Integer.MIN_VALUE} -3, -2, -1, 0, 1, 2, 3, ..., {@code Integer.MAX_VALUE}
+ * Will return {@code false} for any other non-null string input
+ * e.g. empty string, "0", "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters)
+ *
+ * @throws NullPointerException if {@code s} is null.
+ */
+ public static boolean isInteger(String s) {
+ requireNonNull(s);
+
+ try {
+ Integer.parseInt(s);
+ return !s.startsWith("+"); // "+1" is successfully parsed by Integer#parseInt(String)
+ } catch (NumberFormatException nfe) {
+ return false;
+ }
+ }
+
+ /**
+ * Validates if a string is can be parsed into an index, and if the index is positive.
+ *
+ * @throws NullPointerException if {@code s} is null.
+ */
+ public static Index validateAndGetIndexFromString(String string, String commandUsage) {
+ requireNonNull(string);
+ requireNonNull(commandUsage);
+
+ String trimmedArgument = string.trim();
+
+ if (trimmedArgument.isEmpty()) {
+ throw new ParseException(String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, commandUsage));
+ }
+
+ if (!StringUtil.isInteger(trimmedArgument)) {
+ throw new ParseException(String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, commandUsage));
+ }
+
+ if (!StringUtil.isNonZeroUnsignedInteger(trimmedArgument)) {
+ throw new ParseException(Messages.MESSAGE_NON_POSITIVE_INDEX);
+ }
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(trimmedArgument);
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, commandUsage), pe);
+ }
+ return index;
+ }
+
+ /**
+ * Compares two strings by first ignoring case.
+ * Using compare directly will yield AZaz instead of AaZz.
+ *
+ * @throws NullPointerException if {@code s1} or {@code s2} is null.
+ */
+ public static int compareTo(String s1, String s2) {
+ requireNonNull(s1);
+ requireNonNull(s2);
+ int compareLowerCase = s1.compareToIgnoreCase(s2);
+ if (compareLowerCase == 0) {
+ return s1.compareTo(s2);
+ }
+ return compareLowerCase;
+ }
+}
diff --git a/src/main/java/seedu/foodrem/commons/util/ValidationUtil.java b/src/main/java/seedu/foodrem/commons/util/ValidationUtil.java
new file mode 100644
index 00000000000..5940d6fef32
--- /dev/null
+++ b/src/main/java/seedu/foodrem/commons/util/ValidationUtil.java
@@ -0,0 +1,66 @@
+package seedu.foodrem.commons.util;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.format.ResolverStyle;
+
+/**
+ * Helper functions for handling validation.
+ */
+public class ValidationUtil {
+ /**
+ * Returns {@code true} if a string can be parsed into a double, {@code false} otherwise.
+ *
+ * @param doubleString a string to be parsed.
+ */
+ public static boolean isParsableDouble(String doubleString) {
+ try {
+ Double.parseDouble(doubleString);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if a string can be parsed into a date with the provided format, {@code false} otherwise.
+ *
+ * @param dateString a string to be parsed.
+ * @param dateRegex the format the of the date to be parsed.
+ */
+ public static boolean isParsableDateString(String dateString, String dateRegex) {
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateRegex);
+ try {
+ LocalDate.parse(dateString, dateTimeFormatter.withResolverStyle(ResolverStyle.STRICT));
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if a double is positive or zero, {@code false} otherwise
+ *
+ * @param number a double to be checked
+ */
+ public static boolean isNonNegative(double number) {
+ return number >= 0;
+ }
+
+ /**
+ * Returns {@code true} if a string representing a double is too precise, {@code false} otherwise.
+ *
+ * @param string a string that represents a double.
+ * @param maxNumberOfDecimalPlaces an int representing the number of decimal places
+ */
+ public static boolean isDoubleTooPrecise(String string, int maxNumberOfDecimalPlaces) {
+ assert maxNumberOfDecimalPlaces >= 0;
+ String decimalPoint = ".";
+ if (!string.contains(decimalPoint)) {
+ return false;
+ }
+ int numberOfDecimalPoints = string.length() - string.indexOf(decimalPoint) - 1;
+ return numberOfDecimalPoints > maxNumberOfDecimalPlaces;
+ }
+}
diff --git a/src/main/java/seedu/foodrem/logic/Logic.java b/src/main/java/seedu/foodrem/logic/Logic.java
new file mode 100644
index 00000000000..153d3950dc2
--- /dev/null
+++ b/src/main/java/seedu/foodrem/logic/Logic.java
@@ -0,0 +1,52 @@
+package seedu.foodrem.logic;
+
+import java.nio.file.Path;
+
+import javafx.collections.ObservableList;
+import seedu.foodrem.commons.core.GuiSettings;
+import seedu.foodrem.logic.commands.CommandResult;
+import seedu.foodrem.logic.commands.exceptions.CommandException;
+import seedu.foodrem.model.ReadOnlyFoodRem;
+import seedu.foodrem.model.item.Item;
+
+/**
+ * API of the Logic component
+ */
+public interface Logic {
+ /**
+ * Executes the command and returns the result.
+ *
+ * @param commandText The command as entered by the user.
+ * @return the result of the command execution.
+ * @throws CommandException If an error occurs during command execution.
+ * @throws IllegalArgumentException If an error occurs during parsing.
+ */
+ CommandResult> execute(String commandText) throws CommandException, IllegalArgumentException;
+
+ /**
+ * Returns FoodRem.
+ *
+ * @see seedu.foodrem.model.Model#getFoodRem()
+ */
+ ReadOnlyFoodRem getFoodRem();
+
+ /**
+ * Returns an unmodifiable view of the current list of items.
+ */
+ ObservableList
- * e.g. {@code some preamble text t/ 11.00 t/12.00 k/ m/ July} where prefixes are {@code t/ k/ m/}.
+ * e.g. {@code some preamble text t/ 11.00 t/12.00 k/ m/ July} where prefixes are {@code t/ k/ m/}.
* 1. An argument's value can be an empty string e.g. the value of {@code k/} in the above example.
* 2. Leading and trailing whitespaces of an argument value will be discarded.
* 3. An argument may be repeated and all its values will be accumulated e.g. the value of {@code t/}
- * in the above example.
+ * in the above example.
*/
public class ArgumentTokenizer {
-
/**
* Tokenizes an arguments string and returns an {@code ArgumentMultimap} object that maps prefixes to their
* respective argument values. Only the given prefixes will be recognized in the arguments string.
*
* @param argsString Arguments string of the form: {@code preamble