diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000000..0cd51c5fb97
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,25 @@
+name: MarkBind Action
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build_and_deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install Graphviz
+ run: sudo apt-get install graphviz
+ - name: Install Java
+ uses: actions/setup-java@v3
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ - name: Build & Deploy MarkBind site
+ uses: MarkBind/markbind-action@v2
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ rootDirectory: './docs'
+ baseUrl: '/tp' # assuming your repo name is tp
+ version: '^5.2.0'
diff --git a/.gitignore b/.gitignore
index 284c4ca7cd9..eab4c7db6a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ src/test/data/sandbox/
# MacOS custom attributes files created by Finder
.DS_Store
docs/_site/
+docs/_markbind/logs/
diff --git a/README.md b/README.md
index 13f5c77403f..80ce6ae3bc1 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,38 @@
-[](https://github.com/se-edu/addressbook-level3/actions)
+[](https://github.com/AY2324S2-CS2103T-T14-1/tp/actions)
+[](https://codecov.io/gh/AY2324S2-CS2103T-T14-1/tp)
+
+# EffiTrack

+> Boost productivity, streamline success! Welcome to EffiTrack – where efficiency meets innovation. Revolutionize your workday with seamless employee performance tracking.
+
+## Value Proposition
+HR departments often struggle to accurately measure employee efficiency, leading to reduced productivity. Traditional methods of tracking employee performance, such as manual documentation or outdated systems, are time-consuming and prone to errors. EffiTrack solves these challenges by providing a centralized platform to effortlessly monitor employee efficiency.
+
+## Features
+- [ ] Add employee information
+- [ ] List all employees information
+- [ ] Edit an existing employee information
+- [ ] Find employees whose names contain any of the given keywords
+- [ ] Delete a specific employee
+- [ ] Clear all entries
+- [ ] Assign task to an employee
+- [ ] Mark an assigned task as done
+- [ ] Edit deadline of assigned task
+- [ ] Change person in charge of the task
+- [ ] Display upcoming deadlines
+- [ ] Display fire list
+- [ ] Generate efficiency report
+
+## Get Started
+1. Download EffiTrack here.
+2. Navigate to your Downloads folder using the terminal.
+3. Type `java -jar EffiTrack.jar` in your terminal.
+4. Press enter.
+5. Give it a try now!
+
+## Documentation
+For the detailed documentation of this project, see the **[EffiTrack Product Website](https://ay2324s2-cs2103t-t14-1.github.io/tp/)**.
-* This is **a sample project for Software Engineering (SE) students**.
- Example usages:
- * as a starting point of a course project (as opposed to writing everything from scratch)
- * as a case study
-* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details.
- * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big.
- * It comes with a **reasonable level of user and developer documentation**.
-* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...).
-* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**.
-* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info.
+## Acknowledgement
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org)
diff --git a/bin/main/images/ET_logo.png b/bin/main/images/ET_logo.png
new file mode 100644
index 00000000000..ae6b9779af7
Binary files /dev/null and b/bin/main/images/ET_logo.png differ
diff --git a/bin/main/images/address_book_32.png b/bin/main/images/address_book_32.png
new file mode 100644
index 00000000000..29810cf1fd9
Binary files /dev/null and b/bin/main/images/address_book_32.png differ
diff --git a/bin/main/images/calendar.png b/bin/main/images/calendar.png
new file mode 100644
index 00000000000..8b2bdf4f1c1
Binary files /dev/null and b/bin/main/images/calendar.png differ
diff --git a/bin/main/images/clock.png b/bin/main/images/clock.png
new file mode 100644
index 00000000000..0807cbf6451
Binary files /dev/null and b/bin/main/images/clock.png differ
diff --git a/bin/main/images/fail.png b/bin/main/images/fail.png
new file mode 100644
index 00000000000..6daf01290dd
Binary files /dev/null and b/bin/main/images/fail.png differ
diff --git a/bin/main/images/help_icon.png b/bin/main/images/help_icon.png
new file mode 100644
index 00000000000..f8e80d6c1c5
Binary files /dev/null and b/bin/main/images/help_icon.png differ
diff --git a/bin/main/images/info_icon.png b/bin/main/images/info_icon.png
new file mode 100644
index 00000000000..f8cef714095
Binary files /dev/null and b/bin/main/images/info_icon.png differ
diff --git a/bin/main/seedu/address/AppParameters.class b/bin/main/seedu/address/AppParameters.class
new file mode 100644
index 00000000000..e9381178706
Binary files /dev/null and b/bin/main/seedu/address/AppParameters.class differ
diff --git a/bin/main/seedu/address/Main.class b/bin/main/seedu/address/Main.class
new file mode 100644
index 00000000000..b96a3f8b880
Binary files /dev/null and b/bin/main/seedu/address/Main.class differ
diff --git a/bin/main/seedu/address/MainApp.class b/bin/main/seedu/address/MainApp.class
new file mode 100644
index 00000000000..30d5487cfea
Binary files /dev/null and b/bin/main/seedu/address/MainApp.class differ
diff --git a/bin/main/seedu/address/commons/core/Config.class b/bin/main/seedu/address/commons/core/Config.class
new file mode 100644
index 00000000000..fa02726ece7
Binary files /dev/null and b/bin/main/seedu/address/commons/core/Config.class differ
diff --git a/bin/main/seedu/address/commons/core/GuiSettings.class b/bin/main/seedu/address/commons/core/GuiSettings.class
new file mode 100644
index 00000000000..9c2af02974c
Binary files /dev/null and b/bin/main/seedu/address/commons/core/GuiSettings.class differ
diff --git a/bin/main/seedu/address/commons/core/LogsCenter.class b/bin/main/seedu/address/commons/core/LogsCenter.class
new file mode 100644
index 00000000000..65b54320337
Binary files /dev/null and b/bin/main/seedu/address/commons/core/LogsCenter.class differ
diff --git a/bin/main/seedu/address/commons/core/Version.class b/bin/main/seedu/address/commons/core/Version.class
new file mode 100644
index 00000000000..46bda2a930f
Binary files /dev/null and b/bin/main/seedu/address/commons/core/Version.class differ
diff --git a/bin/main/seedu/address/commons/core/index/Index.class b/bin/main/seedu/address/commons/core/index/Index.class
new file mode 100644
index 00000000000..1c335d6414d
Binary files /dev/null and b/bin/main/seedu/address/commons/core/index/Index.class differ
diff --git a/bin/main/seedu/address/commons/exceptions/DataLoadingException.class b/bin/main/seedu/address/commons/exceptions/DataLoadingException.class
new file mode 100644
index 00000000000..b94c62ba3e3
Binary files /dev/null and b/bin/main/seedu/address/commons/exceptions/DataLoadingException.class differ
diff --git a/bin/main/seedu/address/commons/exceptions/IllegalValueException.class b/bin/main/seedu/address/commons/exceptions/IllegalValueException.class
new file mode 100644
index 00000000000..af85ad747a5
Binary files /dev/null and b/bin/main/seedu/address/commons/exceptions/IllegalValueException.class differ
diff --git a/bin/main/seedu/address/commons/util/AppUtil.class b/bin/main/seedu/address/commons/util/AppUtil.class
new file mode 100644
index 00000000000..9d58ca88144
Binary files /dev/null and b/bin/main/seedu/address/commons/util/AppUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/CollectionUtil.class b/bin/main/seedu/address/commons/util/CollectionUtil.class
new file mode 100644
index 00000000000..810ea10f8b0
Binary files /dev/null and b/bin/main/seedu/address/commons/util/CollectionUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/ConfigUtil.class b/bin/main/seedu/address/commons/util/ConfigUtil.class
new file mode 100644
index 00000000000..7ff4b0b5f7c
Binary files /dev/null and b/bin/main/seedu/address/commons/util/ConfigUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/FileUtil.class b/bin/main/seedu/address/commons/util/FileUtil.class
new file mode 100644
index 00000000000..bcd9bc038f8
Binary files /dev/null and b/bin/main/seedu/address/commons/util/FileUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/InvalidationListenerManager.class b/bin/main/seedu/address/commons/util/InvalidationListenerManager.class
new file mode 100644
index 00000000000..41f912d2d71
Binary files /dev/null and b/bin/main/seedu/address/commons/util/InvalidationListenerManager.class differ
diff --git a/bin/main/seedu/address/commons/util/JsonUtil$LevelDeserializer.class b/bin/main/seedu/address/commons/util/JsonUtil$LevelDeserializer.class
new file mode 100644
index 00000000000..7cb75c8e974
Binary files /dev/null and b/bin/main/seedu/address/commons/util/JsonUtil$LevelDeserializer.class differ
diff --git a/bin/main/seedu/address/commons/util/JsonUtil.class b/bin/main/seedu/address/commons/util/JsonUtil.class
new file mode 100644
index 00000000000..c2c06f94ee7
Binary files /dev/null and b/bin/main/seedu/address/commons/util/JsonUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/StringUtil.class b/bin/main/seedu/address/commons/util/StringUtil.class
new file mode 100644
index 00000000000..02d815d7414
Binary files /dev/null and b/bin/main/seedu/address/commons/util/StringUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/ToStringBuilder.class b/bin/main/seedu/address/commons/util/ToStringBuilder.class
new file mode 100644
index 00000000000..6527c9dd69f
Binary files /dev/null and b/bin/main/seedu/address/commons/util/ToStringBuilder.class differ
diff --git a/bin/main/seedu/address/logic/CommandHistory.class b/bin/main/seedu/address/logic/CommandHistory.class
new file mode 100644
index 00000000000..bf06e173d71
Binary files /dev/null and b/bin/main/seedu/address/logic/CommandHistory.class differ
diff --git a/bin/main/seedu/address/logic/Logic.class b/bin/main/seedu/address/logic/Logic.class
new file mode 100644
index 00000000000..c2ed5b1c2de
Binary files /dev/null and b/bin/main/seedu/address/logic/Logic.class differ
diff --git a/bin/main/seedu/address/logic/LogicManager.class b/bin/main/seedu/address/logic/LogicManager.class
new file mode 100644
index 00000000000..b58bfb4558f
Binary files /dev/null and b/bin/main/seedu/address/logic/LogicManager.class differ
diff --git a/bin/main/seedu/address/logic/Messages.class b/bin/main/seedu/address/logic/Messages.class
new file mode 100644
index 00000000000..d5dddef743b
Binary files /dev/null and b/bin/main/seedu/address/logic/Messages.class differ
diff --git a/bin/main/seedu/address/logic/commands/AddCommand.class b/bin/main/seedu/address/logic/commands/AddCommand.class
new file mode 100644
index 00000000000..afaa4863bed
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/AddCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/AssignTaskCommand.class b/bin/main/seedu/address/logic/commands/AssignTaskCommand.class
new file mode 100644
index 00000000000..a7df5964cfb
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/AssignTaskCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ClearCommand.class b/bin/main/seedu/address/logic/commands/ClearCommand.class
new file mode 100644
index 00000000000..0349fd9e991
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ClearCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/Command.class b/bin/main/seedu/address/logic/commands/Command.class
new file mode 100644
index 00000000000..1e13a8c9919
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/Command.class differ
diff --git a/bin/main/seedu/address/logic/commands/CommandResult.class b/bin/main/seedu/address/logic/commands/CommandResult.class
new file mode 100644
index 00000000000..22f69e61bee
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/CommandResult.class differ
diff --git a/bin/main/seedu/address/logic/commands/DeleteCommand.class b/bin/main/seedu/address/logic/commands/DeleteCommand.class
new file mode 100644
index 00000000000..d22f3c91cbd
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/DeleteCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/EditCommand$EditPersonDescriptor.class b/bin/main/seedu/address/logic/commands/EditCommand$EditPersonDescriptor.class
new file mode 100644
index 00000000000..7fcb9da834e
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/EditCommand$EditPersonDescriptor.class differ
diff --git a/bin/main/seedu/address/logic/commands/EditCommand.class b/bin/main/seedu/address/logic/commands/EditCommand.class
new file mode 100644
index 00000000000..4eaa3acc34b
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/EditCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/EditDeadlineCommand.class b/bin/main/seedu/address/logic/commands/EditDeadlineCommand.class
new file mode 100644
index 00000000000..b923b321a91
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/EditDeadlineCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ExitCommand.class b/bin/main/seedu/address/logic/commands/ExitCommand.class
new file mode 100644
index 00000000000..5f6aee55a45
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ExitCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/FilterCommand.class b/bin/main/seedu/address/logic/commands/FilterCommand.class
new file mode 100644
index 00000000000..82ecfed8b78
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/FilterCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/FilterEfficiencyCommand.class b/bin/main/seedu/address/logic/commands/FilterEfficiencyCommand.class
new file mode 100644
index 00000000000..a3d15a0dc61
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/FilterEfficiencyCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/FindCommand.class b/bin/main/seedu/address/logic/commands/FindCommand.class
new file mode 100644
index 00000000000..d5a2f975b9f
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/FindCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/HelpCommand.class b/bin/main/seedu/address/logic/commands/HelpCommand.class
new file mode 100644
index 00000000000..4e0139fa3ee
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/HelpCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/HistoryCommand.class b/bin/main/seedu/address/logic/commands/HistoryCommand.class
new file mode 100644
index 00000000000..7bc1e46bfa4
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/HistoryCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ListCommand.class b/bin/main/seedu/address/logic/commands/ListCommand.class
new file mode 100644
index 00000000000..46209d6f4f6
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ListCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/MarkTaskCommand.class b/bin/main/seedu/address/logic/commands/MarkTaskCommand.class
new file mode 100644
index 00000000000..726cdf658b9
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/MarkTaskCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ReassignTaskCommand.class b/bin/main/seedu/address/logic/commands/ReassignTaskCommand.class
new file mode 100644
index 00000000000..7b515a01f0c
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ReassignTaskCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/RedoCommand.class b/bin/main/seedu/address/logic/commands/RedoCommand.class
new file mode 100644
index 00000000000..94468e9cff9
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/RedoCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/UndoCommand.class b/bin/main/seedu/address/logic/commands/UndoCommand.class
new file mode 100644
index 00000000000..e8876435713
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/UndoCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/exceptions/CommandException.class b/bin/main/seedu/address/logic/commands/exceptions/CommandException.class
new file mode 100644
index 00000000000..40ff643fea0
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/exceptions/CommandException.class differ
diff --git a/bin/main/seedu/address/logic/parser/AddCommandParser.class b/bin/main/seedu/address/logic/parser/AddCommandParser.class
new file mode 100644
index 00000000000..08b2cd7ecfb
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/AddCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/AddressBookParser.class b/bin/main/seedu/address/logic/parser/AddressBookParser.class
new file mode 100644
index 00000000000..350d6951f52
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/AddressBookParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/ArgumentMultimap.class b/bin/main/seedu/address/logic/parser/ArgumentMultimap.class
new file mode 100644
index 00000000000..767d6d013aa
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ArgumentMultimap.class differ
diff --git a/bin/main/seedu/address/logic/parser/ArgumentTokenizer$PrefixPosition.class b/bin/main/seedu/address/logic/parser/ArgumentTokenizer$PrefixPosition.class
new file mode 100644
index 00000000000..8762d805bfe
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ArgumentTokenizer$PrefixPosition.class differ
diff --git a/bin/main/seedu/address/logic/parser/ArgumentTokenizer.class b/bin/main/seedu/address/logic/parser/ArgumentTokenizer.class
new file mode 100644
index 00000000000..8f0636e00fa
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ArgumentTokenizer.class differ
diff --git a/bin/main/seedu/address/logic/parser/AssignTaskCommandParser.class b/bin/main/seedu/address/logic/parser/AssignTaskCommandParser.class
new file mode 100644
index 00000000000..71f04fd531a
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/AssignTaskCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/CliSyntax.class b/bin/main/seedu/address/logic/parser/CliSyntax.class
new file mode 100644
index 00000000000..6e84ee78c97
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/CliSyntax.class differ
diff --git a/bin/main/seedu/address/logic/parser/DeleteCommandParser.class b/bin/main/seedu/address/logic/parser/DeleteCommandParser.class
new file mode 100644
index 00000000000..f895138d75c
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/DeleteCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/EditCommandParser.class b/bin/main/seedu/address/logic/parser/EditCommandParser.class
new file mode 100644
index 00000000000..bb8d600735a
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/EditCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/EditDeadlineCommandParser.class b/bin/main/seedu/address/logic/parser/EditDeadlineCommandParser.class
new file mode 100644
index 00000000000..b4bddee9f02
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/EditDeadlineCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/FilterCommandParser.class b/bin/main/seedu/address/logic/parser/FilterCommandParser.class
new file mode 100644
index 00000000000..f3482afb110
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/FilterCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/FilterEfficiencyCommandParser.class b/bin/main/seedu/address/logic/parser/FilterEfficiencyCommandParser.class
new file mode 100644
index 00000000000..857c7f9fd4f
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/FilterEfficiencyCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/FindCommandParser.class b/bin/main/seedu/address/logic/parser/FindCommandParser.class
new file mode 100644
index 00000000000..a777c219dd3
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/FindCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/MarkTaskCommandParser.class b/bin/main/seedu/address/logic/parser/MarkTaskCommandParser.class
new file mode 100644
index 00000000000..d42eaa9a8f0
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/MarkTaskCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/Parser.class b/bin/main/seedu/address/logic/parser/Parser.class
new file mode 100644
index 00000000000..982a9364d07
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/Parser.class differ
diff --git a/bin/main/seedu/address/logic/parser/ParserTaskUtil.class b/bin/main/seedu/address/logic/parser/ParserTaskUtil.class
new file mode 100644
index 00000000000..3caf2ea794c
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ParserTaskUtil.class differ
diff --git a/bin/main/seedu/address/logic/parser/ParserUtil.class b/bin/main/seedu/address/logic/parser/ParserUtil.class
new file mode 100644
index 00000000000..1122270d2c0
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ParserUtil.class differ
diff --git a/bin/main/seedu/address/logic/parser/Prefix.class b/bin/main/seedu/address/logic/parser/Prefix.class
new file mode 100644
index 00000000000..6129b2f8ccc
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/Prefix.class differ
diff --git a/bin/main/seedu/address/logic/parser/ReassignTaskCommandParser.class b/bin/main/seedu/address/logic/parser/ReassignTaskCommandParser.class
new file mode 100644
index 00000000000..28cfa61d951
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ReassignTaskCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/exceptions/ParseException.class b/bin/main/seedu/address/logic/parser/exceptions/ParseException.class
new file mode 100644
index 00000000000..747cbb8b53d
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/exceptions/ParseException.class differ
diff --git a/bin/main/seedu/address/model/AddressBook.class b/bin/main/seedu/address/model/AddressBook.class
new file mode 100644
index 00000000000..7b7412b6c7c
Binary files /dev/null and b/bin/main/seedu/address/model/AddressBook.class differ
diff --git a/bin/main/seedu/address/model/Model.class b/bin/main/seedu/address/model/Model.class
new file mode 100644
index 00000000000..bd007f8c60a
Binary files /dev/null and b/bin/main/seedu/address/model/Model.class differ
diff --git a/bin/main/seedu/address/model/ModelManager.class b/bin/main/seedu/address/model/ModelManager.class
new file mode 100644
index 00000000000..3ed486d0c45
Binary files /dev/null and b/bin/main/seedu/address/model/ModelManager.class differ
diff --git a/bin/main/seedu/address/model/ReadOnlyAddressBook.class b/bin/main/seedu/address/model/ReadOnlyAddressBook.class
new file mode 100644
index 00000000000..9935c002ac7
Binary files /dev/null and b/bin/main/seedu/address/model/ReadOnlyAddressBook.class differ
diff --git a/bin/main/seedu/address/model/ReadOnlyUserPrefs.class b/bin/main/seedu/address/model/ReadOnlyUserPrefs.class
new file mode 100644
index 00000000000..7cb7a75a54e
Binary files /dev/null and b/bin/main/seedu/address/model/ReadOnlyUserPrefs.class differ
diff --git a/bin/main/seedu/address/model/UserPrefs.class b/bin/main/seedu/address/model/UserPrefs.class
new file mode 100644
index 00000000000..e14a7e438c1
Binary files /dev/null and b/bin/main/seedu/address/model/UserPrefs.class differ
diff --git a/bin/main/seedu/address/model/VersionedAddressBook$NoRedoableStateException.class b/bin/main/seedu/address/model/VersionedAddressBook$NoRedoableStateException.class
new file mode 100644
index 00000000000..5f342affc8a
Binary files /dev/null and b/bin/main/seedu/address/model/VersionedAddressBook$NoRedoableStateException.class differ
diff --git a/bin/main/seedu/address/model/VersionedAddressBook$NoUndoableStateException.class b/bin/main/seedu/address/model/VersionedAddressBook$NoUndoableStateException.class
new file mode 100644
index 00000000000..7945948fdc1
Binary files /dev/null and b/bin/main/seedu/address/model/VersionedAddressBook$NoUndoableStateException.class differ
diff --git a/bin/main/seedu/address/model/VersionedAddressBook.class b/bin/main/seedu/address/model/VersionedAddressBook.class
new file mode 100644
index 00000000000..16799dd3393
Binary files /dev/null and b/bin/main/seedu/address/model/VersionedAddressBook.class differ
diff --git a/bin/main/seedu/address/model/person/Address.class b/bin/main/seedu/address/model/person/Address.class
new file mode 100644
index 00000000000..d20fd1f2bff
Binary files /dev/null and b/bin/main/seedu/address/model/person/Address.class differ
diff --git a/bin/main/seedu/address/model/person/Department.class b/bin/main/seedu/address/model/person/Department.class
new file mode 100644
index 00000000000..19f3fb66fd0
Binary files /dev/null and b/bin/main/seedu/address/model/person/Department.class differ
diff --git a/bin/main/seedu/address/model/person/Efficiency.class b/bin/main/seedu/address/model/person/Efficiency.class
new file mode 100644
index 00000000000..fdde7266288
Binary files /dev/null and b/bin/main/seedu/address/model/person/Efficiency.class differ
diff --git a/bin/main/seedu/address/model/person/Email.class b/bin/main/seedu/address/model/person/Email.class
new file mode 100644
index 00000000000..60c4a39a391
Binary files /dev/null and b/bin/main/seedu/address/model/person/Email.class differ
diff --git a/bin/main/seedu/address/model/person/Name.class b/bin/main/seedu/address/model/person/Name.class
new file mode 100644
index 00000000000..816d0519e8f
Binary files /dev/null and b/bin/main/seedu/address/model/person/Name.class differ
diff --git a/bin/main/seedu/address/model/person/NameContainsKeywordsPredicate.class b/bin/main/seedu/address/model/person/NameContainsKeywordsPredicate.class
new file mode 100644
index 00000000000..7a3837d594f
Binary files /dev/null and b/bin/main/seedu/address/model/person/NameContainsKeywordsPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/Person.class b/bin/main/seedu/address/model/person/Person.class
new file mode 100644
index 00000000000..d795ffa4380
Binary files /dev/null and b/bin/main/seedu/address/model/person/Person.class differ
diff --git a/bin/main/seedu/address/model/person/PersonContainsKeywordsPredicate.class b/bin/main/seedu/address/model/person/PersonContainsKeywordsPredicate.class
new file mode 100644
index 00000000000..d818d40e6ac
Binary files /dev/null and b/bin/main/seedu/address/model/person/PersonContainsKeywordsPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/PersonLessThanEfficiencyPredicate.class b/bin/main/seedu/address/model/person/PersonLessThanEfficiencyPredicate.class
new file mode 100644
index 00000000000..ea05ce246b6
Binary files /dev/null and b/bin/main/seedu/address/model/person/PersonLessThanEfficiencyPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/Phone.class b/bin/main/seedu/address/model/person/Phone.class
new file mode 100644
index 00000000000..dd4f73e64e9
Binary files /dev/null and b/bin/main/seedu/address/model/person/Phone.class differ
diff --git a/bin/main/seedu/address/model/person/UniquePersonList.class b/bin/main/seedu/address/model/person/UniquePersonList.class
new file mode 100644
index 00000000000..263939ef051
Binary files /dev/null and b/bin/main/seedu/address/model/person/UniquePersonList.class differ
diff --git a/bin/main/seedu/address/model/person/exceptions/DuplicatePersonException.class b/bin/main/seedu/address/model/person/exceptions/DuplicatePersonException.class
new file mode 100644
index 00000000000..b93c81ba426
Binary files /dev/null and b/bin/main/seedu/address/model/person/exceptions/DuplicatePersonException.class differ
diff --git a/bin/main/seedu/address/model/person/exceptions/PersonNotFoundException.class b/bin/main/seedu/address/model/person/exceptions/PersonNotFoundException.class
new file mode 100644
index 00000000000..305ea567649
Binary files /dev/null and b/bin/main/seedu/address/model/person/exceptions/PersonNotFoundException.class differ
diff --git a/bin/main/seedu/address/model/tag/Tag.class b/bin/main/seedu/address/model/tag/Tag.class
new file mode 100644
index 00000000000..c812c5309e3
Binary files /dev/null and b/bin/main/seedu/address/model/tag/Tag.class differ
diff --git a/bin/main/seedu/address/model/task/Deadline.class b/bin/main/seedu/address/model/task/Deadline.class
new file mode 100644
index 00000000000..72743357342
Binary files /dev/null and b/bin/main/seedu/address/model/task/Deadline.class differ
diff --git a/bin/main/seedu/address/model/task/Task.class b/bin/main/seedu/address/model/task/Task.class
new file mode 100644
index 00000000000..87df665b292
Binary files /dev/null and b/bin/main/seedu/address/model/task/Task.class differ
diff --git a/bin/main/seedu/address/model/task/UniqueTaskList.class b/bin/main/seedu/address/model/task/UniqueTaskList.class
new file mode 100644
index 00000000000..adfc88b7b2e
Binary files /dev/null and b/bin/main/seedu/address/model/task/UniqueTaskList.class differ
diff --git a/bin/main/seedu/address/model/task/exceptions/DuplicateTaskException.class b/bin/main/seedu/address/model/task/exceptions/DuplicateTaskException.class
new file mode 100644
index 00000000000..3d683d67e63
Binary files /dev/null and b/bin/main/seedu/address/model/task/exceptions/DuplicateTaskException.class differ
diff --git a/bin/main/seedu/address/model/task/exceptions/TaskNotFoundException.class b/bin/main/seedu/address/model/task/exceptions/TaskNotFoundException.class
new file mode 100644
index 00000000000..04bb4afd4b3
Binary files /dev/null and b/bin/main/seedu/address/model/task/exceptions/TaskNotFoundException.class differ
diff --git a/bin/main/seedu/address/model/util/SampleDataUtil.class b/bin/main/seedu/address/model/util/SampleDataUtil.class
new file mode 100644
index 00000000000..88e775616af
Binary files /dev/null and b/bin/main/seedu/address/model/util/SampleDataUtil.class differ
diff --git a/bin/main/seedu/address/storage/AddressBookStorage.class b/bin/main/seedu/address/storage/AddressBookStorage.class
new file mode 100644
index 00000000000..30604d3aecd
Binary files /dev/null and b/bin/main/seedu/address/storage/AddressBookStorage.class differ
diff --git a/bin/main/seedu/address/storage/JsonAdaptedPerson.class b/bin/main/seedu/address/storage/JsonAdaptedPerson.class
new file mode 100644
index 00000000000..c6c6e8e51f3
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonAdaptedPerson.class differ
diff --git a/bin/main/seedu/address/storage/JsonAdaptedTag.class b/bin/main/seedu/address/storage/JsonAdaptedTag.class
new file mode 100644
index 00000000000..8f1e94de2cd
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonAdaptedTag.class differ
diff --git a/bin/main/seedu/address/storage/JsonAdaptedTask.class b/bin/main/seedu/address/storage/JsonAdaptedTask.class
new file mode 100644
index 00000000000..3a5f807c17b
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonAdaptedTask.class differ
diff --git a/bin/main/seedu/address/storage/JsonAddressBookStorage.class b/bin/main/seedu/address/storage/JsonAddressBookStorage.class
new file mode 100644
index 00000000000..1461ecb6000
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonAddressBookStorage.class differ
diff --git a/bin/main/seedu/address/storage/JsonSerializableAddressBook.class b/bin/main/seedu/address/storage/JsonSerializableAddressBook.class
new file mode 100644
index 00000000000..aa49924a915
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonSerializableAddressBook.class differ
diff --git a/bin/main/seedu/address/storage/JsonUserPrefsStorage.class b/bin/main/seedu/address/storage/JsonUserPrefsStorage.class
new file mode 100644
index 00000000000..e4c5c78b4a1
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonUserPrefsStorage.class differ
diff --git a/bin/main/seedu/address/storage/Storage.class b/bin/main/seedu/address/storage/Storage.class
new file mode 100644
index 00000000000..b071eb42645
Binary files /dev/null and b/bin/main/seedu/address/storage/Storage.class differ
diff --git a/bin/main/seedu/address/storage/StorageManager.class b/bin/main/seedu/address/storage/StorageManager.class
new file mode 100644
index 00000000000..d3de052b01a
Binary files /dev/null and b/bin/main/seedu/address/storage/StorageManager.class differ
diff --git a/bin/main/seedu/address/storage/UserPrefsStorage.class b/bin/main/seedu/address/storage/UserPrefsStorage.class
new file mode 100644
index 00000000000..8dac21a29ec
Binary files /dev/null and b/bin/main/seedu/address/storage/UserPrefsStorage.class differ
diff --git a/bin/main/seedu/address/ui/CommandBox$CommandExecutor.class b/bin/main/seedu/address/ui/CommandBox$CommandExecutor.class
new file mode 100644
index 00000000000..efc51a94329
Binary files /dev/null and b/bin/main/seedu/address/ui/CommandBox$CommandExecutor.class differ
diff --git a/bin/main/seedu/address/ui/CommandBox.class b/bin/main/seedu/address/ui/CommandBox.class
new file mode 100644
index 00000000000..c814f7be526
Binary files /dev/null and b/bin/main/seedu/address/ui/CommandBox.class differ
diff --git a/bin/main/seedu/address/ui/HelpWindow.class b/bin/main/seedu/address/ui/HelpWindow.class
new file mode 100644
index 00000000000..661d7775b4c
Binary files /dev/null and b/bin/main/seedu/address/ui/HelpWindow.class differ
diff --git a/bin/main/seedu/address/ui/MainWindow.class b/bin/main/seedu/address/ui/MainWindow.class
new file mode 100644
index 00000000000..dcf860b4da6
Binary files /dev/null and b/bin/main/seedu/address/ui/MainWindow.class differ
diff --git a/bin/main/seedu/address/ui/PersonCard.class b/bin/main/seedu/address/ui/PersonCard.class
new file mode 100644
index 00000000000..c76399591f3
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonCard.class differ
diff --git a/bin/main/seedu/address/ui/PersonListPanel$PersonListViewCell.class b/bin/main/seedu/address/ui/PersonListPanel$PersonListViewCell.class
new file mode 100644
index 00000000000..011b43afc82
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonListPanel$PersonListViewCell.class differ
diff --git a/bin/main/seedu/address/ui/PersonListPanel.class b/bin/main/seedu/address/ui/PersonListPanel.class
new file mode 100644
index 00000000000..62f755bb4f5
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonListPanel.class differ
diff --git a/bin/main/seedu/address/ui/ResultDisplay.class b/bin/main/seedu/address/ui/ResultDisplay.class
new file mode 100644
index 00000000000..a6c347ebb17
Binary files /dev/null and b/bin/main/seedu/address/ui/ResultDisplay.class differ
diff --git a/bin/main/seedu/address/ui/StatusBarFooter.class b/bin/main/seedu/address/ui/StatusBarFooter.class
new file mode 100644
index 00000000000..939a09aa487
Binary files /dev/null and b/bin/main/seedu/address/ui/StatusBarFooter.class differ
diff --git a/bin/main/seedu/address/ui/Ui.class b/bin/main/seedu/address/ui/Ui.class
new file mode 100644
index 00000000000..8778b647196
Binary files /dev/null and b/bin/main/seedu/address/ui/Ui.class differ
diff --git a/bin/main/seedu/address/ui/UiManager.class b/bin/main/seedu/address/ui/UiManager.class
new file mode 100644
index 00000000000..2146a11f756
Binary files /dev/null and b/bin/main/seedu/address/ui/UiManager.class differ
diff --git a/bin/main/seedu/address/ui/UiPart.class b/bin/main/seedu/address/ui/UiPart.class
new file mode 100644
index 00000000000..558b3782392
Binary files /dev/null and b/bin/main/seedu/address/ui/UiPart.class differ
diff --git a/bin/main/view/CommandBox.fxml b/bin/main/view/CommandBox.fxml
new file mode 100644
index 00000000000..033a5d66a29
--- /dev/null
+++ b/bin/main/view/CommandBox.fxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/DarkTheme.css b/bin/main/view/DarkTheme.css
new file mode 100644
index 00000000000..fc31dc6d21f
--- /dev/null
+++ b/bin/main/view/DarkTheme.css
@@ -0,0 +1,401 @@
+.background {
+ -fx-background-color: derive(#FBF9F1, 20%);
+ background-color: #383838; /* Used in the default.html file */
+}
+
+.command-pane {
+ -fx-background-color: #F2E6CE;
+}
+
+.label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: #555555;
+ -fx-opacity: 0.9;
+}
+
+.label-bright {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: black;
+ -fx-opacity: 1;
+}
+
+.label-header {
+ -fx-font-size: 32pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: black;
+ -fx-opacity: 1;
+}
+
+.text-field {
+ -fx-font-size: 12pt;
+ -fx-font-family: "Segoe UI Semibold";
+}
+
+.tab-pane {
+ -fx-padding: 0 0 0 0;
+}
+
+.tab-pane .tab-header-area {
+ -fx-padding: 0 0 0 0;
+ -fx-min-height: 0;
+ -fx-max-height: 0;
+}
+
+.table-view {
+ -fx-base: #FBF9F1;
+ -fx-control-inner-background: #FBF9F1;
+ -fx-background-color: #FBF9F1;
+ -fx-table-cell-border-color: transparent;
+ -fx-table-header-border-color: transparent;
+ -fx-padding: 5;
+}
+
+.table-view .column-header-background {
+ -fx-background-color: transparent;
+}
+
+.table-view .column-header, .table-view .filler {
+ -fx-size: 35;
+ -fx-border-width: 0 0 1 0;
+ -fx-background-color: transparent;
+ -fx-border-color:
+ transparent
+ transparent
+ derive(-fx-base, 80%)
+ transparent;
+ -fx-border-insets: 0 10 1 0;
+}
+
+.table-view .column-header .label {
+ -fx-font-size: 20pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: black;
+ -fx-alignment: center-left;
+ -fx-opacity: 1;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: -fx-focus-color;
+}
+
+.split-pane:horizontal .split-pane-divider {
+ -fx-background-color: #FBF9F1;
+}
+
+.split-pane {
+ -fx-border-radius: 1;
+ -fx-border-width: 1;
+ -fx-background-color: derive(#FBF9F1, 20%);
+}
+
+.list-view {
+ -fx-background-insets: 0;
+ -fx-padding: 0;
+ -fx-background-color: derive(#FBF9F1, 20%);
+}
+
+.list-cell {
+ -fx-background-radius: 5px;
+ -fx-label-padding: 0 0 0 0;
+ -fx-graphic-text-gap: 0;
+ -fx-padding: 0 0 5 0;
+ -fx-spacing: 10 10 10 10;
+}
+
+.list-cell:filled:even {
+ -fx-background-color: #BBAB8C;
+ -fx-background-insets: 0 0 5 0;
+}
+
+.list-cell:filled:odd {
+ -fx-background-color: #BB9E83;
+ -fx-background-insets: 0 0 5 0;
+}
+
+.list-cell:filled:selected {
+ -fx-background-color: #A9B388;
+}
+
+.list-cell:filled:selected #cardPane {
+ -fx-background-radius: 5px;
+ -fx-border-color: #6E8B74;
+ -fx-border-width: 1;
+ -fx-border-radius: 5px;
+}
+
+.list-cell .label {
+ -fx-text-fill: black;
+}
+
+.cell_big_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 16px;
+ -fx-text-fill: #010504;
+}
+
+.cell_small_label {
+ -fx-font-family: "Segoe UI";
+ -fx-font-size: 13px;
+ -fx-text-fill: #010504;
+}
+
+.efficiency_small_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 14px;
+ -fx-text-fill: #010504;
+}
+
+.stack-pane {
+ -fx-background-color: derive(#FBF9F1, 20%);
+}
+
+.pane-with-border {
+ -fx-background-color: derive(#FBF9F1, 20%);
+}
+
+.status-bar {
+ -fx-background-color: derive(#FBF9F1, 30%);
+}
+
+.result-display {
+ -fx-background-color: transparent;
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 12pt;
+ -fx-text-fill: black;
+}
+
+.result-display .label {
+ -fx-text-fill: black !important;
+}
+
+.status-bar .label {
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: black;
+ -fx-padding: 4px;
+ -fx-pref-height: 30px;
+}
+
+.status-bar-with-border {
+ -fx-background-color: derive(#FBF9F1, 30%);
+ -fx-border-color: derive(#1d1d1d, 25%);
+ -fx-border-width: 1px;
+}
+
+.status-bar-with-border .label {
+ -fx-text-fill: black;
+}
+
+.grid-pane {
+ -fx-background-color: derive(#FBF9F1, 30%);
+ -fx-border-width: 1px;
+}
+
+.grid-pane .stack-pane {
+ -fx-background-color: derive(#FBF9F1, 30%);
+}
+
+.context-menu {
+ -fx-background-color: derive(#FBF9F1, 50%);
+}
+
+.context-menu .label {
+ -fx-text-fill: black;
+}
+
+.menu-bar {
+ -fx-background-color: #FBF9F1;
+}
+
+.menu-bar .label {
+ -fx-font-size: 12pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: #B99470;
+ -fx-opacity: 0.9;
+}
+
+.menu {
+ -fx-background-color: #FBF9F1;
+}
+
+.menu .left-container {
+ -fx-background-color: #FBF9F1;
+}
+
+.menu:hover {
+ -fx-background-color: #BB9E83;
+}
+
+.menu:hover .label {
+ -fx-text-fill: black;
+}
+
+.menu:selected {
+ -fx-background-color: #BB9E83;
+}
+
+.menu:focused {
+ -fx-background-color: #BB9E83;
+}
+
+.menu-item {
+ -fx-background-color: derived(#FBF9F1, 30%);
+}
+
+.menu-item:hover {
+ -fx-background-color: #BB9E83;
+}
+
+.menu-item:hover .label {
+ -fx-text-fill: black;
+}
+
+/*
+ * Metro style Push Button
+ * Author: Pedro Duque Vieira
+ * http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/
+ */
+.button {
+ -fx-padding: 5 22 5 22;
+ -fx-border-color: #BB9E83;
+ -fx-border-width: 2;
+ -fx-background-radius: 0;
+ -fx-background-color: #BB9E83;
+ -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
+ -fx-font-size: 11pt;
+ -fx-text-fill: #d8d8d8;
+ -fx-background-insets: 0 0 0 0, 0, 1, 2;
+}
+
+.button:hover {
+ -fx-background-color: #BB9E83;
+}
+
+.button:pressed, .button:default:hover:pressed {
+ -fx-background-color: white;
+ -fx-text-fill: #1d1d1d;
+}
+
+.button:focused {
+ -fx-border-color: white, white;
+ -fx-border-width: 1, 1;
+ -fx-border-style: solid, segments(1, 1);
+ -fx-border-radius: 0, 0;
+ -fx-border-insets: 1 1 1 1, 0;
+}
+
+.button:disabled, .button:default:disabled {
+ -fx-opacity: 0.4;
+ -fx-background-color: #BB9E83;
+ -fx-text-fill: white;
+}
+
+.button:default {
+ -fx-background-color:#BBAB8C;
+ -fx-text-fill: black;
+}
+
+.button:default:hover {
+ -fx-background-color: #BB9E83;
+}
+
+.dialog-pane {
+ -fx-background-color: #FBF9F1;
+}
+
+.dialog-pane > *.button-bar > *.container {
+ -fx-background-color: #FBF9F1;
+}
+
+.dialog-pane > *.label.content {
+ -fx-font-size: 14px;
+ -fx-font-weight: bold;
+ -fx-text-fill: black;
+}
+
+.dialog-pane:header *.header-panel {
+ -fx-background-color: derive(#FBF9F1, 25%);
+}
+
+.dialog-pane:header *.header-panel *.label {
+ -fx-font-size: 18px;
+ -fx-font-style: italic;
+ -fx-fill: black;
+ -fx-text-fill: black;
+}
+
+.scroll-bar {
+ -fx-background-color: derive(#FBF9F1, 20%);
+}
+
+.scroll-bar .thumb {
+ -fx-background-color: #F2E6CE;
+ -fx-background-insets: 3;
+}
+
+.scroll-bar .increment-button, .scroll-bar .decrement-button {
+ -fx-background-color: transparent;
+ -fx-padding: 0 0 0 0;
+}
+
+.scroll-bar .increment-arrow, .scroll-bar .decrement-arrow {
+ -fx-shape: " ";
+}
+
+.scroll-bar:vertical .increment-arrow, .scroll-bar:vertical .decrement-arrow {
+ -fx-padding: 1 8 1 8;
+}
+
+.scroll-bar:horizontal .increment-arrow, .scroll-bar:horizontal .decrement-arrow {
+ -fx-padding: 8 1 8 1;
+}
+
+#cardPane {
+ -fx-background-color: transparent;
+ -fx-background-radius: 5px;
+ -fx-border-width: 0;
+}
+
+#commandTypeLabel {
+ -fx-font-size: 11px;
+ -fx-text-fill: #F70D1A;
+}
+
+#commandTextField {
+ -fx-border-width: 0;
+ -fx-border-radius: 10;
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 12pt;
+ -fx-text-fill: black;
+}
+
+#filterField, #personListPanel, #personWebpage {
+ -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0);
+}
+
+#listTitle {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 16px;
+ -fx-text-fill: #B99470;
+ -fx-alignment: center-left;
+}
+
+#resultDisplay .content {
+ -fx-background-color: transparent, #F2E6CE, transparent, #F2E6CE;
+ -fx-background-radius: 0;
+}
+
+#tags {
+ -fx-hgap: 7;
+ -fx-vgap: 3;
+}
+
+#tags .label {
+ -fx-text-fill: white;
+ -fx-background-color: #6E8B74;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 11;
+}
diff --git a/bin/main/view/Extensions.css b/bin/main/view/Extensions.css
new file mode 100644
index 00000000000..35238179aa8
--- /dev/null
+++ b/bin/main/view/Extensions.css
@@ -0,0 +1,20 @@
+
+.error {
+ -fx-text-fill: #d06651 !important; /* The error class should always override the default text-fill style */
+}
+
+.list-cell:empty {
+ /* Empty cells will not have alternating colours */
+ -fx-background: #FBF9F1;
+}
+
+.tag-selector {
+ -fx-border-width: 1;
+ -fx-border-color: white;
+ -fx-border-radius: 3;
+ -fx-background-radius: 3;
+}
+
+.tooltip-text {
+ -fx-text-fill: white;
+}
diff --git a/bin/main/view/HelpWindow.css b/bin/main/view/HelpWindow.css
new file mode 100644
index 00000000000..02c99d117b1
--- /dev/null
+++ b/bin/main/view/HelpWindow.css
@@ -0,0 +1,19 @@
+#copyButton, #helpMessage {
+ -fx-text-fill: black;
+}
+
+#copyButton {
+ -fx-background-color: #BBAB8C;
+}
+
+#copyButton:hover {
+ -fx-background-color: #BB9E83;
+}
+
+#copyButton:armed {
+ -fx-background-color: darkgray;
+}
+
+#helpMessageContainer {
+ -fx-background-color: derive(#FBF9F1, 20%);
+}
diff --git a/bin/main/view/HelpWindow.fxml b/bin/main/view/HelpWindow.fxml
new file mode 100644
index 00000000000..e01f330de33
--- /dev/null
+++ b/bin/main/view/HelpWindow.fxml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/MainWindow.fxml b/bin/main/view/MainWindow.fxml
new file mode 100644
index 00000000000..05c5e3b10ee
--- /dev/null
+++ b/bin/main/view/MainWindow.fxml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/PersonListCard.fxml b/bin/main/view/PersonListCard.fxml
new file mode 100644
index 00000000000..6a0fc737e05
--- /dev/null
+++ b/bin/main/view/PersonListCard.fxml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/PersonListPanel.fxml b/bin/main/view/PersonListPanel.fxml
new file mode 100644
index 00000000000..e675e861ead
--- /dev/null
+++ b/bin/main/view/PersonListPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/ResultDisplay.fxml b/bin/main/view/ResultDisplay.fxml
new file mode 100644
index 00000000000..01b691792a9
--- /dev/null
+++ b/bin/main/view/ResultDisplay.fxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/StatusBarFooter.fxml b/bin/main/view/StatusBarFooter.fxml
new file mode 100644
index 00000000000..7b430f9c6a2
--- /dev/null
+++ b/bin/main/view/StatusBarFooter.fxml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/test/seedu/address/AppParametersTest$ParametersStub.class b/bin/test/seedu/address/AppParametersTest$ParametersStub.class
new file mode 100644
index 00000000000..caf7e71c6c3
Binary files /dev/null and b/bin/test/seedu/address/AppParametersTest$ParametersStub.class differ
diff --git a/bin/test/seedu/address/AppParametersTest.class b/bin/test/seedu/address/AppParametersTest.class
new file mode 100644
index 00000000000..2b00df7e144
Binary files /dev/null and b/bin/test/seedu/address/AppParametersTest.class differ
diff --git a/bin/test/seedu/address/commons/core/ConfigTest.class b/bin/test/seedu/address/commons/core/ConfigTest.class
new file mode 100644
index 00000000000..f769d88eb6f
Binary files /dev/null and b/bin/test/seedu/address/commons/core/ConfigTest.class differ
diff --git a/bin/test/seedu/address/commons/core/GuiSettingsTest.class b/bin/test/seedu/address/commons/core/GuiSettingsTest.class
new file mode 100644
index 00000000000..1f05b09f0f1
Binary files /dev/null and b/bin/test/seedu/address/commons/core/GuiSettingsTest.class differ
diff --git a/bin/test/seedu/address/commons/core/VersionTest.class b/bin/test/seedu/address/commons/core/VersionTest.class
new file mode 100644
index 00000000000..b7401f47c8f
Binary files /dev/null and b/bin/test/seedu/address/commons/core/VersionTest.class differ
diff --git a/bin/test/seedu/address/commons/core/index/IndexTest.class b/bin/test/seedu/address/commons/core/index/IndexTest.class
new file mode 100644
index 00000000000..bed3326b43d
Binary files /dev/null and b/bin/test/seedu/address/commons/core/index/IndexTest.class differ
diff --git a/bin/test/seedu/address/commons/util/AppUtilTest.class b/bin/test/seedu/address/commons/util/AppUtilTest.class
new file mode 100644
index 00000000000..4c30db01656
Binary files /dev/null and b/bin/test/seedu/address/commons/util/AppUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/CollectionUtilTest.class b/bin/test/seedu/address/commons/util/CollectionUtilTest.class
new file mode 100644
index 00000000000..1ad31c77cf8
Binary files /dev/null and b/bin/test/seedu/address/commons/util/CollectionUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/ConfigUtilTest.class b/bin/test/seedu/address/commons/util/ConfigUtilTest.class
new file mode 100644
index 00000000000..dc536153ff2
Binary files /dev/null and b/bin/test/seedu/address/commons/util/ConfigUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/FileUtilTest.class b/bin/test/seedu/address/commons/util/FileUtilTest.class
new file mode 100644
index 00000000000..9b907a04983
Binary files /dev/null and b/bin/test/seedu/address/commons/util/FileUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/InvalidationListenerManagerTest.class b/bin/test/seedu/address/commons/util/InvalidationListenerManagerTest.class
new file mode 100644
index 00000000000..b7d57998cf7
Binary files /dev/null and b/bin/test/seedu/address/commons/util/InvalidationListenerManagerTest.class differ
diff --git a/bin/test/seedu/address/commons/util/JsonUtilTest.class b/bin/test/seedu/address/commons/util/JsonUtilTest.class
new file mode 100644
index 00000000000..35c622f570b
Binary files /dev/null and b/bin/test/seedu/address/commons/util/JsonUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/StringUtilTest.class b/bin/test/seedu/address/commons/util/StringUtilTest.class
new file mode 100644
index 00000000000..e70f07a6a6a
Binary files /dev/null and b/bin/test/seedu/address/commons/util/StringUtilTest.class differ
diff --git a/bin/test/seedu/address/logic/CommandHistoryTest.class b/bin/test/seedu/address/logic/CommandHistoryTest.class
new file mode 100644
index 00000000000..8eaab58bb36
Binary files /dev/null and b/bin/test/seedu/address/logic/CommandHistoryTest.class differ
diff --git a/bin/test/seedu/address/logic/LogicManagerTest$1.class b/bin/test/seedu/address/logic/LogicManagerTest$1.class
new file mode 100644
index 00000000000..ca8e35c89bf
Binary files /dev/null and b/bin/test/seedu/address/logic/LogicManagerTest$1.class differ
diff --git a/bin/test/seedu/address/logic/LogicManagerTest.class b/bin/test/seedu/address/logic/LogicManagerTest.class
new file mode 100644
index 00000000000..75ea4b47e90
Binary files /dev/null and b/bin/test/seedu/address/logic/LogicManagerTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandIntegrationTest.class b/bin/test/seedu/address/logic/commands/AddCommandIntegrationTest.class
new file mode 100644
index 00000000000..df6b64cd3aa
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandIntegrationTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStub.class b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStub.class
new file mode 100644
index 00000000000..317d565366a
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStub.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubAcceptingPersonAdded.class b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubAcceptingPersonAdded.class
new file mode 100644
index 00000000000..e7de7f38b2e
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubAcceptingPersonAdded.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubWithPerson.class b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubWithPerson.class
new file mode 100644
index 00000000000..ae345084ab9
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubWithPerson.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest.class b/bin/test/seedu/address/logic/commands/AddCommandTest.class
new file mode 100644
index 00000000000..d21d3efa7a4
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/AssignTaskCommandTest.class b/bin/test/seedu/address/logic/commands/AssignTaskCommandTest.class
new file mode 100644
index 00000000000..8e3761ed55c
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AssignTaskCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ClearCommandTest.class b/bin/test/seedu/address/logic/commands/ClearCommandTest.class
new file mode 100644
index 00000000000..bf6a5abb65f
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ClearCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/CommandResultTest.class b/bin/test/seedu/address/logic/commands/CommandResultTest.class
new file mode 100644
index 00000000000..ede1e9676ef
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/CommandResultTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/CommandTestUtil.class b/bin/test/seedu/address/logic/commands/CommandTestUtil.class
new file mode 100644
index 00000000000..1dd0018e32b
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/CommandTestUtil.class differ
diff --git a/bin/test/seedu/address/logic/commands/DeleteCommandTest.class b/bin/test/seedu/address/logic/commands/DeleteCommandTest.class
new file mode 100644
index 00000000000..fb5813aaafb
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/DeleteCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/EditCommandTest.class b/bin/test/seedu/address/logic/commands/EditCommandTest.class
new file mode 100644
index 00000000000..e1ae5cde9ae
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/EditCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/EditDeadlineCommandTest.class b/bin/test/seedu/address/logic/commands/EditDeadlineCommandTest.class
new file mode 100644
index 00000000000..7b97c502b6c
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/EditDeadlineCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/EditPersonDescriptorTest.class b/bin/test/seedu/address/logic/commands/EditPersonDescriptorTest.class
new file mode 100644
index 00000000000..cd99495cc27
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/EditPersonDescriptorTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ExitCommandTest.class b/bin/test/seedu/address/logic/commands/ExitCommandTest.class
new file mode 100644
index 00000000000..ad2df144228
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ExitCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/FilterCommandTest.class b/bin/test/seedu/address/logic/commands/FilterCommandTest.class
new file mode 100644
index 00000000000..fba459e318d
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/FilterCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/FilterEfficiencyCommandTest.class b/bin/test/seedu/address/logic/commands/FilterEfficiencyCommandTest.class
new file mode 100644
index 00000000000..c18cb424b11
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/FilterEfficiencyCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/FindCommandTest.class b/bin/test/seedu/address/logic/commands/FindCommandTest.class
new file mode 100644
index 00000000000..7febfe7a371
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/FindCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/HelpCommandTest.class b/bin/test/seedu/address/logic/commands/HelpCommandTest.class
new file mode 100644
index 00000000000..1132bfd0e43
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/HelpCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/HistoryCommandTest.class b/bin/test/seedu/address/logic/commands/HistoryCommandTest.class
new file mode 100644
index 00000000000..e9ef0474ca8
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/HistoryCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ListCommandTest.class b/bin/test/seedu/address/logic/commands/ListCommandTest.class
new file mode 100644
index 00000000000..be93cc4a783
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ListCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/MarkTaskCommandTest.class b/bin/test/seedu/address/logic/commands/MarkTaskCommandTest.class
new file mode 100644
index 00000000000..9ffa831170e
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/MarkTaskCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ReassignTaskCommandTest.class b/bin/test/seedu/address/logic/commands/ReassignTaskCommandTest.class
new file mode 100644
index 00000000000..ecc549cafd6
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ReassignTaskCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/RedoCommandTest.class b/bin/test/seedu/address/logic/commands/RedoCommandTest.class
new file mode 100644
index 00000000000..c67e05df26b
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/RedoCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/UndoCommandTest.class b/bin/test/seedu/address/logic/commands/UndoCommandTest.class
new file mode 100644
index 00000000000..f62007f9427
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/UndoCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/AddCommandParserTest.class b/bin/test/seedu/address/logic/parser/AddCommandParserTest.class
new file mode 100644
index 00000000000..8444ce5ee1e
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/AddCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/AddressBookParserTest.class b/bin/test/seedu/address/logic/parser/AddressBookParserTest.class
new file mode 100644
index 00000000000..59f245fb101
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/AddressBookParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/ArgumentTokenizerTest.class b/bin/test/seedu/address/logic/parser/ArgumentTokenizerTest.class
new file mode 100644
index 00000000000..5db1d6b0119
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/ArgumentTokenizerTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/CommandParserTestUtil.class b/bin/test/seedu/address/logic/parser/CommandParserTestUtil.class
new file mode 100644
index 00000000000..3edb6d785f1
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/CommandParserTestUtil.class differ
diff --git a/bin/test/seedu/address/logic/parser/DeleteCommandParserTest.class b/bin/test/seedu/address/logic/parser/DeleteCommandParserTest.class
new file mode 100644
index 00000000000..a232fc07d23
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/DeleteCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/EditCommandParserTest.class b/bin/test/seedu/address/logic/parser/EditCommandParserTest.class
new file mode 100644
index 00000000000..20aaaa37e35
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/EditCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/EditDeadlineCommandParserTest.class b/bin/test/seedu/address/logic/parser/EditDeadlineCommandParserTest.class
new file mode 100644
index 00000000000..c5aafb0638b
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/EditDeadlineCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/FilterCommandParserTest.class b/bin/test/seedu/address/logic/parser/FilterCommandParserTest.class
new file mode 100644
index 00000000000..b3b065e551a
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/FilterCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/FilterEfficiencyCommandParserTest.class b/bin/test/seedu/address/logic/parser/FilterEfficiencyCommandParserTest.class
new file mode 100644
index 00000000000..d553dde09f8
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/FilterEfficiencyCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/FindCommandParserTest.class b/bin/test/seedu/address/logic/parser/FindCommandParserTest.class
new file mode 100644
index 00000000000..6889646d9fc
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/FindCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/ParserUtilTest.class b/bin/test/seedu/address/logic/parser/ParserUtilTest.class
new file mode 100644
index 00000000000..3176c4603a2
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/ParserUtilTest.class differ
diff --git a/bin/test/seedu/address/model/AddressBookTest$AddressBookStub.class b/bin/test/seedu/address/model/AddressBookTest$AddressBookStub.class
new file mode 100644
index 00000000000..89dbd44e10d
Binary files /dev/null and b/bin/test/seedu/address/model/AddressBookTest$AddressBookStub.class differ
diff --git a/bin/test/seedu/address/model/AddressBookTest.class b/bin/test/seedu/address/model/AddressBookTest.class
new file mode 100644
index 00000000000..e34ab0c821e
Binary files /dev/null and b/bin/test/seedu/address/model/AddressBookTest.class differ
diff --git a/bin/test/seedu/address/model/ModelManagerTest.class b/bin/test/seedu/address/model/ModelManagerTest.class
new file mode 100644
index 00000000000..8ae7b05f9c9
Binary files /dev/null and b/bin/test/seedu/address/model/ModelManagerTest.class differ
diff --git a/bin/test/seedu/address/model/UserPrefsTest.class b/bin/test/seedu/address/model/UserPrefsTest.class
new file mode 100644
index 00000000000..4a96a3f6681
Binary files /dev/null and b/bin/test/seedu/address/model/UserPrefsTest.class differ
diff --git a/bin/test/seedu/address/model/VersionedAddressBookTest.class b/bin/test/seedu/address/model/VersionedAddressBookTest.class
new file mode 100644
index 00000000000..8c7ab3058e3
Binary files /dev/null and b/bin/test/seedu/address/model/VersionedAddressBookTest.class differ
diff --git a/bin/test/seedu/address/model/person/AddressTest.class b/bin/test/seedu/address/model/person/AddressTest.class
new file mode 100644
index 00000000000..379501952d5
Binary files /dev/null and b/bin/test/seedu/address/model/person/AddressTest.class differ
diff --git a/bin/test/seedu/address/model/person/DepartmentTest.class b/bin/test/seedu/address/model/person/DepartmentTest.class
new file mode 100644
index 00000000000..b43fb201717
Binary files /dev/null and b/bin/test/seedu/address/model/person/DepartmentTest.class differ
diff --git a/bin/test/seedu/address/model/person/EmailTest.class b/bin/test/seedu/address/model/person/EmailTest.class
new file mode 100644
index 00000000000..46068ec2797
Binary files /dev/null and b/bin/test/seedu/address/model/person/EmailTest.class differ
diff --git a/bin/test/seedu/address/model/person/NameContainsKeywordsPredicateTest.class b/bin/test/seedu/address/model/person/NameContainsKeywordsPredicateTest.class
new file mode 100644
index 00000000000..66b983fbfb5
Binary files /dev/null and b/bin/test/seedu/address/model/person/NameContainsKeywordsPredicateTest.class differ
diff --git a/bin/test/seedu/address/model/person/NameTest.class b/bin/test/seedu/address/model/person/NameTest.class
new file mode 100644
index 00000000000..fdcb526dc37
Binary files /dev/null and b/bin/test/seedu/address/model/person/NameTest.class differ
diff --git a/bin/test/seedu/address/model/person/PersonContainsKeywordsPredicateTest.class b/bin/test/seedu/address/model/person/PersonContainsKeywordsPredicateTest.class
new file mode 100644
index 00000000000..47943c1fcd5
Binary files /dev/null and b/bin/test/seedu/address/model/person/PersonContainsKeywordsPredicateTest.class differ
diff --git a/bin/test/seedu/address/model/person/PersonLessThanEfficiencyPredicateTest.class b/bin/test/seedu/address/model/person/PersonLessThanEfficiencyPredicateTest.class
new file mode 100644
index 00000000000..a14b3b6504a
Binary files /dev/null and b/bin/test/seedu/address/model/person/PersonLessThanEfficiencyPredicateTest.class differ
diff --git a/bin/test/seedu/address/model/person/PersonTest.class b/bin/test/seedu/address/model/person/PersonTest.class
new file mode 100644
index 00000000000..44a792a9a32
Binary files /dev/null and b/bin/test/seedu/address/model/person/PersonTest.class differ
diff --git a/bin/test/seedu/address/model/person/PhoneTest.class b/bin/test/seedu/address/model/person/PhoneTest.class
new file mode 100644
index 00000000000..59498e481cd
Binary files /dev/null and b/bin/test/seedu/address/model/person/PhoneTest.class differ
diff --git a/bin/test/seedu/address/model/person/UniquePersonListTest.class b/bin/test/seedu/address/model/person/UniquePersonListTest.class
new file mode 100644
index 00000000000..c012b5f8a21
Binary files /dev/null and b/bin/test/seedu/address/model/person/UniquePersonListTest.class differ
diff --git a/bin/test/seedu/address/model/tag/TagTest.class b/bin/test/seedu/address/model/tag/TagTest.class
new file mode 100644
index 00000000000..f4fab2071ff
Binary files /dev/null and b/bin/test/seedu/address/model/tag/TagTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonAdaptedPersonTest.class b/bin/test/seedu/address/storage/JsonAdaptedPersonTest.class
new file mode 100644
index 00000000000..9fcf2ceba66
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonAdaptedPersonTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonAddressBookStorageTest.class b/bin/test/seedu/address/storage/JsonAddressBookStorageTest.class
new file mode 100644
index 00000000000..73f23ecabc4
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonAddressBookStorageTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonSerializableAddressBookTest.class b/bin/test/seedu/address/storage/JsonSerializableAddressBookTest.class
new file mode 100644
index 00000000000..a42262fdff3
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonSerializableAddressBookTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonUserPrefsStorageTest.class b/bin/test/seedu/address/storage/JsonUserPrefsStorageTest.class
new file mode 100644
index 00000000000..fd5531f6c69
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonUserPrefsStorageTest.class differ
diff --git a/bin/test/seedu/address/storage/StorageManagerTest.class b/bin/test/seedu/address/storage/StorageManagerTest.class
new file mode 100644
index 00000000000..fb86e52c57d
Binary files /dev/null and b/bin/test/seedu/address/storage/StorageManagerTest.class differ
diff --git a/bin/test/seedu/address/testutil/AddressBookBuilder.class b/bin/test/seedu/address/testutil/AddressBookBuilder.class
new file mode 100644
index 00000000000..89a4abc2755
Binary files /dev/null and b/bin/test/seedu/address/testutil/AddressBookBuilder.class differ
diff --git a/bin/test/seedu/address/testutil/Assert.class b/bin/test/seedu/address/testutil/Assert.class
new file mode 100644
index 00000000000..9eba3381576
Binary files /dev/null and b/bin/test/seedu/address/testutil/Assert.class differ
diff --git a/bin/test/seedu/address/testutil/EditPersonDescriptorBuilder.class b/bin/test/seedu/address/testutil/EditPersonDescriptorBuilder.class
new file mode 100644
index 00000000000..95930684344
Binary files /dev/null and b/bin/test/seedu/address/testutil/EditPersonDescriptorBuilder.class differ
diff --git a/bin/test/seedu/address/testutil/PersonBuilder.class b/bin/test/seedu/address/testutil/PersonBuilder.class
new file mode 100644
index 00000000000..a94a43b31e2
Binary files /dev/null and b/bin/test/seedu/address/testutil/PersonBuilder.class differ
diff --git a/bin/test/seedu/address/testutil/PersonUtil.class b/bin/test/seedu/address/testutil/PersonUtil.class
new file mode 100644
index 00000000000..01d2cdaa196
Binary files /dev/null and b/bin/test/seedu/address/testutil/PersonUtil.class differ
diff --git a/bin/test/seedu/address/testutil/SerializableTestClass.class b/bin/test/seedu/address/testutil/SerializableTestClass.class
new file mode 100644
index 00000000000..221e212d5d3
Binary files /dev/null and b/bin/test/seedu/address/testutil/SerializableTestClass.class differ
diff --git a/bin/test/seedu/address/testutil/TaskBuilder.class b/bin/test/seedu/address/testutil/TaskBuilder.class
new file mode 100644
index 00000000000..4aeac9ddc58
Binary files /dev/null and b/bin/test/seedu/address/testutil/TaskBuilder.class differ
diff --git a/bin/test/seedu/address/testutil/TaskUtil.class b/bin/test/seedu/address/testutil/TaskUtil.class
new file mode 100644
index 00000000000..5f492914f9a
Binary files /dev/null and b/bin/test/seedu/address/testutil/TaskUtil.class differ
diff --git a/bin/test/seedu/address/testutil/TestUtil.class b/bin/test/seedu/address/testutil/TestUtil.class
new file mode 100644
index 00000000000..148dc750bdc
Binary files /dev/null and b/bin/test/seedu/address/testutil/TestUtil.class differ
diff --git a/bin/test/seedu/address/testutil/TypicalAddressBook.class b/bin/test/seedu/address/testutil/TypicalAddressBook.class
new file mode 100644
index 00000000000..92a48140b26
Binary files /dev/null and b/bin/test/seedu/address/testutil/TypicalAddressBook.class differ
diff --git a/bin/test/seedu/address/testutil/TypicalIndexes.class b/bin/test/seedu/address/testutil/TypicalIndexes.class
new file mode 100644
index 00000000000..0fbc16b38a3
Binary files /dev/null and b/bin/test/seedu/address/testutil/TypicalIndexes.class differ
diff --git a/bin/test/seedu/address/testutil/TypicalPersons.class b/bin/test/seedu/address/testutil/TypicalPersons.class
new file mode 100644
index 00000000000..b9076eef4e9
Binary files /dev/null and b/bin/test/seedu/address/testutil/TypicalPersons.class differ
diff --git a/bin/test/seedu/address/testutil/TypicalTasks.class b/bin/test/seedu/address/testutil/TypicalTasks.class
new file mode 100644
index 00000000000..5893aa7c118
Binary files /dev/null and b/bin/test/seedu/address/testutil/TypicalTasks.class differ
diff --git a/bin/test/seedu/address/ui/TestFxmlObject.class b/bin/test/seedu/address/ui/TestFxmlObject.class
new file mode 100644
index 00000000000..0d516b76bbb
Binary files /dev/null and b/bin/test/seedu/address/ui/TestFxmlObject.class differ
diff --git a/bin/test/seedu/address/ui/UiPartTest$TestUiPart.class b/bin/test/seedu/address/ui/UiPartTest$TestUiPart.class
new file mode 100644
index 00000000000..49c70ef126a
Binary files /dev/null and b/bin/test/seedu/address/ui/UiPartTest$TestUiPart.class differ
diff --git a/bin/test/seedu/address/ui/UiPartTest.class b/bin/test/seedu/address/ui/UiPartTest.class
new file mode 100644
index 00000000000..ba407acd1bb
Binary files /dev/null and b/bin/test/seedu/address/ui/UiPartTest.class differ
diff --git a/bin/test/view/UiPartTest/invalidFile.fxml b/bin/test/view/UiPartTest/invalidFile.fxml
new file mode 100644
index 00000000000..67680946732
--- /dev/null
+++ b/bin/test/view/UiPartTest/invalidFile.fxml
@@ -0,0 +1 @@
+Not a valid FXML file
diff --git a/bin/test/view/UiPartTest/validFile.fxml b/bin/test/view/UiPartTest/validFile.fxml
new file mode 100644
index 00000000000..bab836af0db
--- /dev/null
+++ b/bin/test/view/UiPartTest/validFile.fxml
@@ -0,0 +1,4 @@
+
+
+
+Hello World!
diff --git a/bin/test/view/UiPartTest/validFileWithFxRoot.fxml b/bin/test/view/UiPartTest/validFileWithFxRoot.fxml
new file mode 100644
index 00000000000..1a8b2c9e4d3
--- /dev/null
+++ b/bin/test/view/UiPartTest/validFileWithFxRoot.fxml
@@ -0,0 +1,6 @@
+
+
+
+ Hello World!
+
diff --git a/build.gradle b/build.gradle
index a2951cc709e..171f08f9235 100644
--- a/build.gradle
+++ b/build.gradle
@@ -66,7 +66,11 @@ dependencies {
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'EffiTrack.jar'
+}
+
+run {
+ enableAssertions = true
}
defaultTasks 'clean', 'test'
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000000..1748e487fbd
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,23 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+_markbind/logs/
+
+# Dependency directories
+node_modules/
+
+# Production build files (change if you output the build to a different directory)
+_site/
+
+# Env
+.env
+.env.local
+
+# IDE configs
+.vscode/
+.idea/*
+*.iml
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..7bb6016fc58 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,59 +1,59 @@
---
-layout: page
-title: About Us
+ layout: default.md
+ title: "About Us"
---
-We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
+# About Us
-You can reach us at the email `seer[at]comp.nus.edu.sg`
+We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
## Project team
-### John Doe
+### Yap Ho Wen
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
+[[github](https://github.com/howen02)]
[[portfolio](team/johndoe.md)]
-* Role: Project Advisor
+* Role: Team Lead
+* Responsibilities: Git expert, Code Quality, Testing
-### Jane Doe
+### Yeo Zi Yi
-
+
-[[github](http://github.com/johndoe)]
+[[github](http://github.com/ziyi22)]
[[portfolio](team/johndoe.md)]
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Developer
+* Responsibilities: Code Quality, Deliverables and deadlines, UI
-### Johnny Doe
+### Tsui Yi Wern
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/yiwern5)] [[portfolio](team/yiwern5.md)]
* Role: Developer
-* Responsibilities: Data
+* Responsibilities: Scheduling and tracking, Deliverables and deadlines, UI
-### Jean Doe
+### Yong Li An
-
+
-[[github](http://github.com/johndoe)]
+[[github](http://github.com/wolffe88)]
[[portfolio](team/johndoe.md)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities: Task Management, Deliverables and deadlines, UI
-### James Doe
+### Khoo Kiat Lun
-
+
-[[github](http://github.com/johndoe)]
+[[github](http://github.com/KiatLun)]
[[portfolio](team/johndoe.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: Documentation, Deliverables and deadlines, UI
diff --git a/docs/Configuration.md b/docs/Configuration.md
index 13cf0faea16..32f6255f3b9 100644
--- a/docs/Configuration.md
+++ b/docs/Configuration.md
@@ -1,6 +1,8 @@
---
-layout: page
-title: Configuration guide
+ layout: default.md
+ title: "Configuration guide"
---
+# Configuration guide
+
Certain properties of the application can be controlled (e.g user preferences file location, logging level) through the configuration file (default: `config.json`).
diff --git a/docs/DevOps.md b/docs/DevOps.md
index d2fd91a6001..8228c845e86 100644
--- a/docs/DevOps.md
+++ b/docs/DevOps.md
@@ -1,12 +1,15 @@
---
-layout: page
-title: DevOps guide
+ layout: default.md
+ title: "DevOps guide"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+# DevOps guide
---------------------------------------------------------------------------------------------------------------------
+
+
+
+
## Build automation
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 1b56bb5d31b..c7def810a95 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,15 +1,20 @@
---
-layout: page
-title: Developer Guide
+ layout: default.md
+ title: "Developer Guide"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+
+# EffiTrack Developer Guide
+
+
+
--------------------------------------------------------------------------------------------------------------------
## **Acknowledgements**
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+Redo, undo and history commands are adapted from [AddressBook-Level4 project](https://github.com/se-edu/addressbook-level4/).
--------------------------------------------------------------------------------------------------------------------
@@ -21,14 +26,9 @@ Refer to the guide [_Setting up and getting started_](SettingUp.md).
## **Design**
-
-
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document `docs/diagrams` folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
-
-
### Architecture
-
+
The ***Architecture Diagram*** given above explains the high-level design of the App.
@@ -36,7 +36,7 @@ Given below is a quick overview of main components and how they interact with ea
**Main components of the architecture**
-**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down.
+**`Main`** (consisting of classes [`Main`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down.
* At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
* At shut down, it shuts down the other components and invokes cleanup methods where necessary.
@@ -53,7 +53,7 @@ The bulk of the app's work is done by the following four components:
The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`.
-
+
Each of the four main components (also shown in the diagram above),
@@ -62,19 +62,19 @@ Each of the four main components (also shown in the diagram above),
For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
-
+
The sections below give more details of each component.
### UI component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The **API** of this component is specified in [`Ui.java`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/java/seedu/address/ui/Ui.java)
-
+
The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
-The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
+The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/resources/view/MainWindow.fxml)
The `UI` component,
@@ -85,18 +85,20 @@ The `UI` component,
### Logic component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+**API** : [`Logic.java`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/java/seedu/address/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
-
+
The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example.
-
+
-
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
-
+
+
+**Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
+
How the `Logic` component works:
@@ -108,16 +110,16 @@ How the `Logic` component works:
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
-
+
How the parsing works:
* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
+**API** : [`Model.java`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/java/seedu/address/model/Model.java)
-
+
The `Model` component,
@@ -127,21 +129,23 @@ The `Model` component,
* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
-
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
+
+**Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
-
+
-
+
### Storage component
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+**API** : [`Storage.java`](https://github.com/AY2324S2-CS2103T-T14-1/tp/blob/master/src/main/java/seedu/address/storage/Storage.java)
-
+
The `Storage` component,
-* can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
+* can save both EffiTrack data and user preference data in JSON format, and read them back into corresponding objects.
* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
@@ -155,11 +159,11 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+### \[Implemented\] Undo/redo feature
-#### Proposed Implementation
+#### Current Implementation
-The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+The implemented undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
* `VersionedAddressBook#commit()` — Saves the current address book state in its history.
* `VersionedAddressBook#undo()` — Restores the previous address book state from its history.
@@ -171,58 +175,67 @@ Given below is an example usage scenario and how the undo/redo mechanism behaves
Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state.
-
+
Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state.
-
+
Step 3. The user executes `add n/David …` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`.
-
+
+
+
-
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`.
+**Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`.
-
+
Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state.
-
+
-
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather
+
+
+
+**Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
-
+
The following sequence diagram shows how an undo operation goes through the `Logic` component:
-
+
-
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
-
+**Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
+
Similarly, how an undo operation goes through the `Model` component is shown below:
-
+
The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state.
-
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
+
+
+**Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
-
+
Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged.
-
+
Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.
-
+
The following activity diagram summarizes what happens when a user executes a new command:
-
+
#### Design considerations:
@@ -239,10 +252,62 @@ The following activity diagram summarizes what happens when a user executes a ne
_{more aspects and alternatives to be added}_
-### \[Proposed\] Data archiving
-_{Explain here how the data archiving feature will be implemented}_
+### \[Implemented\] Assign task feature
+
+#### Current Implementation
+
+The implemented assign task mechanism is facilitated by `AddressBook`.
+
+* `AddressBook#UniquePersonList`: Represents the list of persons stored in the address book.
+* `AddressBook#UniqueTaskList`: Represents the list of tasks assigned within the address book.
+Given below is an example usage scenario and how the assign task features works.
+
+1. Ui
+ * The user executes the command `assign task/Proposal by/20-05-2024 2359 to/2` to assign a task named "Proposal" with a specified deadline to the 2nd person in the address book.
+
+2. Parser
+ * The input command is parsed by the `AddressBookParser` component.
+ * The `assign` command keyword triggers the `AssignTaskCommandParser` to extract task details (name, deadline) and the index of the person to assign the task to.
+ * By parsing in `AssignTaskCommandParser`, a `Task` object is created to encapsulate the task details and returns an `AssignTaskCommand` object representing the command to assign the task.
+
+3. Logic execution
+ * The Command object - `AssignTaskCommand` is executed in the `LogicManager`.
+ * The `AssignTaskCommand` invokes the `assignTask` method in the `Model` component.
+
+The following sequence diagram shows how an assign task operation goes through the `Logic` component:
+
+
+
+3. Model operation
+ * The `model#assignTask` internally triggers the `AddressBook#assignTask` to:
+ * a. The `Task` is added to the `UniqueTaskList` in the address book.
+ * b. Set the person in charge of the `Task` to the identified person.
+ * c. Set the `Person`'s task to the specified task.
+
+The following sequence diagram shows how an assign task operation goes through the `Model` component:
+
+
+
+#### Design considerations:
+**Aspect: How assign task executes:**
+
+* **Alternative 1 (current choice):** Saves all tasks in an additional task list.
+ * Pros: Provides a centralized task management system independent, making it easier to track and manage tasks across different persons..
+ * Cons: Each task need to store additional information, such as the person in charge, leading to redundancy if not managed efficiently.
+
+* **Alternative 2:** Add task list as a field for each person.
+ * Pros: Easy to implement.
+ * Cons: Increases complexity in managing and updating task lists, especially in scenarios involving task delegation or reassignment.
+
+
+### \[Proposed\] Efficiency Leaderboard
+HR will be able to view the top performing staff on a leaderboard
+
+#### Proposed Implementation
+1. List of unique people will be fetched and sorted based on efficiency
+2. Top 3/5/10 performing people will be showcased on the leaderboard
--------------------------------------------------------------------------------------------------------------------
@@ -262,28 +327,47 @@ _{Explain here how the data archiving feature will be implemented}_
**Target user profile**:
-* has a need to manage a significant number of contacts
-* prefer desktop apps over other types
-* can type fast
-* prefers typing to mouse interactions
-* is reasonably comfortable using CLI apps
+* has a need to manage all the employees in company.
+* can assign tasks to employees.
+* has a need to check employees' efficiency.
+* can generate a fire list to cut company costs.
+* prefers smooth and eye-catching GUI.
+* prefers typing to mouse interactions.
+* is reasonably comfortable using CLI apps.
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+**Value proposition**: EffiTrack simplifies the task of measuring and monitoring employee efficiency for
+HR departments. Instead of using time-consuming and error-prone methods like manual documentation or
+outdated systems, EffiTrack offers a centralized platform for easy and accurate monitoring of employee performance.
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
-
+| Priority | As a … | I can… | So that I can… |
+|----------|---------------|--------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
+| `* * *` | HR Manager | assign tasks to employees | effortlessly assign tasks to employees, ensuring clear communication of expectations and responsibilities. |
+| `* * *` | HR Manager | add or remove employees | maintain accurate and up-to-date employee records with ease. |
+| `* * *` | HR Manager | displays tasks with deadline within a week from now | efficiently plan and prioritize tasks based on their urgency. |
+| `* * *` | HR Manager | change person in charge of a task | easily change the person in charge of a task, ensuring smooth transition of responsibilities without disrupting workflow. |
+| `* * *` | HR Manager | change the deadline for an existing task | adjust deadlines as needed to accommodate changing priorities or unforeseen circumstances without any hassle. |
+| `* * *` | HR Manager | set deadlines for tasks | easily set deadlines for tasks, enabling precise scheduling and effective time management. |
+| `* * *` | HR Manager | assign employees to departments | organize teams effectively and foster better collaboration. |
+| `* * *` | HR Manager | view all employee information | establish communication in times of need |
+| `* *` | HR Manager | perform flexible searches | obtain search results even if one character matches. |
+| `* *` | HR Manager | sort the employee list based on their efficiency | quickly sort and identify employees based on efficiency metrics, such as productivity levels, task completion rates, or performance evaluations. |
+| `* *` | HR Manager | mark assigned task as done | efficiently mark tasks as done, providing a clear indication of progress and facilitating effective task tracking and management. |
+| `* *` | HR Manager | filter out poor performing employees | identify and filter out underperforming employees based on key performance indicators, allowing for targeted intervention and support. |
+| `* *` | HR Manager | set priority tags for assignments | assign priority levels to tasks, ensuring critical tasks receive appropriate attention and resources. |
+| `*` | HR Manager | generate efficiency reports highlighting significant changes | make informed decisions and strategic plans based on comprehensive performance insights. |
+| `*` | HR Manager | compare efficiency between departments | identify trends, best practices, and areas for improvement. |
+| `*` | HR Manager | access a simpler interface | navigate the system effortlessly and access key information without any complexity. |
+| `*` | HR Manager | track real time progress of assignments | monitor the progress of assignments, facilitating timely intervention and resource allocation as necessary. |
+| `*` | HR Manager | undo and redo my commands | easily correct mistakes or revert changes. |
+| `*` | HR Manager | view my command history | recall commands I have executed. |
+| `*` | HR Manager | add comments about employees | make notes |
+| `*` | HR Manager | find the person in charge for a task | keep accountability |
+| `*` | HR Manager | find employees without an active task | know who to assign task to |
*{More to be added}*
### Use cases
@@ -313,20 +397,168 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
Use case resumes at step 2.
-*{More to be added}*
+**Use case: Editing a person**
+
+**MSS**
+
+1. User requests to list persons
+2. AddressBook shows a list of persons
+3. User requests to edit a specific person in the list with the necessary edits
+4. AddressBook edits the person
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+
+* 3a. The given index is invalid.
+
+ * 3a1. AddressBook shows an error message.
+
+ Use case resumes at step 2.
+
+
+* 3b. The necessary edits are missing
+
+ * 3b1AddressBook shows an error message.
+
+ Use case resumes at step 2
+
+**Use case: Change deadline of a task**
+
+**MSS**
+
+1. User requests to list tasks
+2. AddressBook shows a list of tasks
+3. User requests to edit a specific task in the list with a new deadline
+4. AddressBook edits the task
+
+ Use case ends.
+
+**Extensions**
+
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. AddressBook shows an error message.
+
+ Use case resumes at step 2.
+
+* 3b. The new deadline is missing.
+
+ * 3b1. AddressBook shows an error message.
+
+ Use case resumes at step 2.
+
+* 3c. The new deadline is before the current date.
+ * 3c1. AddressBook shows an error message.
+
+ * Use case resumes at step 2.
+
+* 3d. The given index does not have a task assigned.
+
+ * 3d1. AddressBook shows an error message
+
+ * Use case resumes at step 2.
+
+
+**Use case: Assign a task**
+
+**MSS**
+
+1. User requests to list tasks
+2. AddressBook shows a list of tasks
+3. User requests to list persons
+4. AddressBook shows a list of people
+5. User requests to assign a task to a person
+6. AddressBook assigns the task to the person
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+
+* 4a. The list is empty.
+
+ Use case ends.
+
+
+* 5a. The given index is invalid.
+
+ * 5a1. AddressBook shows an error message.
+
+ Use case resumes at step 4.
+
+
+* 5b. The person already has a task.
+ * 5b1 AddressBook shows an error message.
+
+ Use case resumes at step 4.
+
+
+**Use case: Set priority tag for a task**
+
+**MSS**
+
+1. User requests to list tasks
+2. AddressBook shows a list of tasks
+3. User requests tag a task with a priority status
+4. AddressBook tags the task
+
+ Use case ends.
+
+**Extensions**
+* 2a. The list is empty.
+
+ Use case ends.
+
+
+* 3a. The given index is invalid.
+
+ * 3a1. AddressBook shows an error message.
+
+ Use case resumes at step 2
+
+* 3b. The given index is invalid.
+
+ * 3b1. AddressBook shows an error message.
+
+ Use case resumes at step 2
### Non-Functional Requirements
1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
+4. The respond time for any action should be less than 5 seconds.
+5. The app should have an uptime of at least 99.5%, ensuring data accessibility for managers.
+6. There should be at most 2 hours of downtime in a day for maintenance or updates.
+7. The app should efficiently store and manage data for at least 10 years of employee history.
+8. There should be a daily scheduled backup of the app's data.
+9. The app should allow data export in at least three common formats like CSV, XLSX and PDF.
*{More to be added}*
### Glossary
-* **Mainstream OS**: Windows, Linux, Unix, MacOS
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **Efficiency**: The employee's default efficiency score is 80% and capped at 100%. Efficiency will increase by 1% when the employee completes an assigned task within the deadline and decrease by 1% for each subsequent day the deadline is exceeded.
+* **Efficiency Threshold**: A user-defined benchmark in the app, classifying employee performance. For instance, a threshold below 20% indicates poor performance (colour coded in red), while 21-79% suggests problematic performance requiring attention (colour coded in yellow).
+* **Fire list**: List of employees who are below the efficiency threshold.
+* **Key Performance Indicators (KPIs)**: Quantifiable measures used to evaluate the success of an employee or a department in achieving specific objectives.
+* **Duplicate Person**: Person of the same name.
+* **Dupicate Task**: Task of the same task title.
--------------------------------------------------------------------------------------------------------------------
@@ -334,10 +566,12 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
Given below are instructions to test the app manually.
-
:information_source: **Note:** These instructions only provide a starting point for testers to work on;
+
+
+**Note:** These instructions only provide a starting point for testers to work on;
testers are expected to do more *exploratory* testing.
-
+
### Launch and shutdown
@@ -380,3 +614,13 @@ testers are expected to do more *exploratory* testing.
1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
1. _{ more test cases … }_
+
+--------------------------------------------------------------------------------------------------------------------
+
+## **Appendix: Planned Enhancements**
+
+Team size: 5
+
+1. Handle extreme inputs for name, address, department, tags, email, comment (e.g., a person name with 1000 characters, an index that exceeds the range of `int`). For this version the text will be truncated or not fully shown as handling extreme input is considered as a nice to have feature, which will be implemented in the future version.
+2. Simplify mark task command by only taking in index of the person in charge (e.g., `mark 1`)
+3. Fix collapsed task card when a new task is assigned.
diff --git a/docs/Documentation.md b/docs/Documentation.md
index 3e68ea364e7..082e652d947 100644
--- a/docs/Documentation.md
+++ b/docs/Documentation.md
@@ -1,29 +1,21 @@
---
-layout: page
-title: Documentation guide
+ layout: default.md
+ title: "Documentation guide"
+ pageNav: 3
---
-**Setting up and maintaining the project website:**
-
-* We use [**Jekyll**](https://jekyllrb.com/) to manage documentation.
-* The `docs/` folder is used for documentation.
-* To learn how set it up and maintain the project website, follow the guide [_[se-edu/guides] **Using Jekyll for project documentation**_](https://se-education.org/guides/tutorials/jekyll.html).
-* Note these points when adapting the documentation to a different project/product:
- * The 'Site-wide settings' section of the page linked above has information on how to update site-wide elements such as the top navigation bar.
- * :bulb: In addition to updating content files, you might have to update the config files `docs\_config.yml` and `docs\_sass\minima\_base.scss` (which contains a reference to `AB-3` that comes into play when converting documentation pages to PDF format).
-* If you are using Intellij for editing documentation files, you can consider enabling 'soft wrapping' for `*.md` files, as explained in [_[se-edu/guides] **Intellij IDEA: Useful settings**_](https://se-education.org/guides/tutorials/intellijUsefulSettings.html#enabling-soft-wrapping)
+# Documentation Guide
+* We use [**MarkBind**](https://markbind.org/) to manage documentation.
+* The `docs/` folder contains the source files for the documentation website.
+* To learn how set it up and maintain the project website, follow the guide [[se-edu/guides] Working with Forked MarkBind sites](https://se-education.org/guides/tutorials/markbind-forked-sites.html) for project documentation.
**Style guidance:**
* Follow the [**_Google developer documentation style guide_**](https://developers.google.com/style).
+* Also relevant is the [_se-edu/guides **Markdown coding standard**_](https://se-education.org/guides/conventions/markdown.html).
-* Also relevant is the [_[se-edu/guides] **Markdown coding standard**_](https://se-education.org/guides/conventions/markdown.html)
-
-**Diagrams:**
-
-* See the [_[se-edu/guides] **Using PlantUML**_](https://se-education.org/guides/tutorials/plantUml.html)
-**Converting a document to the PDF format:**
+**Converting to PDF**
-* See the guide [_[se-edu/guides] **Saving web documents as PDF files**_](https://se-education.org/guides/tutorials/savingPdf.html)
+* See the guide [_se-edu/guides **Saving web documents as PDF files**_](https://se-education.org/guides/tutorials/savingPdf.html).
diff --git a/docs/Gemfile b/docs/Gemfile
deleted file mode 100644
index c8385d85874..00000000000
--- a/docs/Gemfile
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-
-source "https://rubygems.org"
-
-git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
-
-gem 'jekyll'
-gem 'github-pages', group: :jekyll_plugins
-gem 'wdm', '~> 0.1.0' if Gem.win_platform?
-gem 'webrick'
diff --git a/docs/Logging.md b/docs/Logging.md
index 5e4fb9bc217..589644ad5c6 100644
--- a/docs/Logging.md
+++ b/docs/Logging.md
@@ -1,8 +1,10 @@
---
-layout: page
-title: Logging guide
+ layout: default.md
+ title: "Logging guide"
---
+# Logging guide
+
* We are using `java.util.logging` package for logging.
* The `LogsCenter` class is used to manage the logging levels and logging destinations.
* The `Logger` for a class can be obtained using `LogsCenter.getLogger(Class)` which will log messages according to the specified logging level.
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 275445bd551..03df0295bd2 100644
--- a/docs/SettingUp.md
+++ b/docs/SettingUp.md
@@ -1,27 +1,32 @@
---
-layout: page
-title: Setting up and getting started
+ layout: default.md
+ title: "Setting up and getting started"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+# Setting up and getting started
+
+
--------------------------------------------------------------------------------------------------------------------
## Setting up the project in your computer
-
:exclamation: **Caution:**
+
+**Caution:**
Follow the steps in the following guide precisely. Things will not work out if you deviate in some steps.
-
+
First, **fork** this repo, and **clone** the fork into your computer.
If you plan to use Intellij IDEA (highly recommended):
1. **Configure the JDK**: Follow the guide [_[se-edu/guides] IDEA: Configuring the JDK_](https://se-education.org/guides/tutorials/intellijJdk.html) to to ensure Intellij is configured to use **JDK 11**.
-1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
- :exclamation: Note: Importing a Gradle project is slightly different from importing a normal Java project.
+1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
+
+ Note: Importing a Gradle project is slightly different from importing a normal Java project.
+
1. **Verify the setup**:
1. Run the `seedu.address.Main` and try a few commands.
1. [Run the tests](Testing.md) to ensure they all pass.
@@ -34,10 +39,11 @@ If you plan to use Intellij IDEA (highly recommended):
If using IDEA, follow the guide [_[se-edu/guides] IDEA: Configuring the code style_](https://se-education.org/guides/tutorials/intellijCodeStyle.html) to set up IDEA's coding style to match ours.
-
:bulb: **Tip:**
+
+ **Tip:**
Optionally, you can follow the guide [_[se-edu/guides] Using Checkstyle_](https://se-education.org/guides/tutorials/checkstyle.html) to find how to use the CheckStyle within IDEA e.g., to report problems _as_ you write code.
-
+
1. **Set up CI**
diff --git a/docs/Testing.md b/docs/Testing.md
index 8a99e82438a..78ddc57e670 100644
--- a/docs/Testing.md
+++ b/docs/Testing.md
@@ -1,12 +1,15 @@
---
-layout: page
-title: Testing guide
+ layout: default.md
+ title: "Testing guide"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+# Testing guide
---------------------------------------------------------------------------------------------------------------------
+
+
+
+
## Running tests
@@ -19,8 +22,10 @@ There are two ways to run tests.
* **Method 2: Using Gradle**
* Open a console and run the command `gradlew clean test` (Mac/Linux: `./gradlew clean test`)
-
:link: **Link**: Read [this Gradle Tutorial from the se-edu/guides](https://se-education.org/guides/tutorials/gradle.html) to learn more about using Gradle.
-
+
+
+**Link**: Read [this Gradle Tutorial from the se-edu/guides](https://se-education.org/guides/tutorials/gradle.html) to learn more about using Gradle.
+
--------------------------------------------------------------------------------------------------------------------
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 7abd1984218..3533f6c5b31 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,12 +1,22 @@
---
-layout: page
-title: User Guide
+ layout: default.md
+ title: "User Guide"
+ pageNav: 3
---
-AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps.
+# EffiTrack User Guide
-* Table of Contents
-{:toc}
+## Introduction
+
+EffiTrack is a **desktop app for managing employees, tracking the efficiency of employees,
+optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, EffiTrack can get your contact management tasks done faster than traditional GUI apps.
+
+EffiTrack simplifies the task of measuring and monitoring employee efficiency for
+HR departments. Instead of using time-consuming and error-prone methods like manual documentation or
+outdated systems, EffiTrack offers a centralized platform for easy and accurate monitoring of employee performance.
+
+
+
--------------------------------------------------------------------------------------------------------------------
@@ -14,25 +24,44 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
1. Ensure you have Java `11` or above installed in your Computer.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+1. Download the latest `EffiTrack.jar` from [here](https://github.com/AY2324S2-CS2103T-T14-1/tp/releases).
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+1. Copy the file to the folder you want to use as the _home folder_ for EffiTrack.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
+1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar EffiTrack.jar` command to run the application.
A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- 
+
1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
Some example commands you can try:
-
- * `list` : Lists all contacts.
-
- * `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book.
-
- * `delete 3` : Deletes the 3rd contact shown in the current list.
-
- * `clear` : Deletes all contacts.
-
+ * `list` : Lists all employees.
+
+ * `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01 d/Finance eff/80` : Adds an employee named `John Doe` to EffiTrack.
+
+ * `edit 1 n/Colby Bryan` : Edits the name of the 1st employee shown in the current list to `Colby Bryan`.
+
+ * `delete 3` : Deletes the 3rd employee shown in the current list.
+
+ * `find john` : Finds all employees whose name contains `john`.
+
+ * `findtask report` : Finds all employees whose task contains `report`.
+
+ * `filter finance` : Filters the list to display employees who belong to `finance` department.
+
+ * `assign task/Complete Proposal by/20-05-2024 2359 to/1` :Assigns the task `Complete Proposal` with specific deadline to the 1st employee shown in the current list.
+
+ * `mark task/Complete Proposal o/1` : Mark the task `Complete Proposal` assigned to the 1st employee as done.
+
+ * `filter_efficiency 50` : Filters all employees and list those efficiency less than or equals to `50`.
+
+ * `clear` : Deletes all employees.
+
+ * `undo`: Undo the previous command.
+
+ * `redo`: Reverses the previous undo command.
+
+ * `history`: Displays the commands executed from most recent to earliest, inclusive of invalid commands.
+
* `exit` : Exits the app.
1. Refer to the [Features](#features) below for details of each command.
@@ -41,9 +70,9 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
## Features
-
+
-**:information_source: Notes about the command format:**
+**Notes about the command format:**
* Words in `UPPER_CASE` are the parameters to be supplied by the user.
e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`.
@@ -61,89 +90,254 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
* If you are using a PDF version of this document, be careful when copying and pasting commands that span multiple lines as space characters surrounding line-breaks may be omitted when copied over to the application.
-
+
+**Notes about the parameters:**
+
+* `NAME`: The name of the employee.
+ * Only alphanumeric names with spaces is allowed.
+ * Special characters are not allowed in names.
+ * Employee of the same name are not allowed to be added to EffiTrack, or edit an existing employee's name to the same name as another existing employee in EffiTrack.
+ * `NAME` is case-sensitive (e.g. `john Doe` is not the same as `John Doe`)
+ * `NAME` is space-sensitive (e.g. `John Doe` is not the same as `John Doe`)
+
+* `PHONE_NUMBER`: The phone number of the employee.
+ * Has a minimum limit of 3 digits and maximum limit of 15 digits.
+
+* `EMAIL`: The email address of the employee.
+ * Valid as long as it follows the format of `local-part@domain and should not include whitespace
+ * `local-part` should only contain alphanumeric characters and the following special characters `+`, `_`, `.` and `-` is allowed.
+ * `local-part` may not start or end with any special characters.
+ * `local-part` must be followed with an `@`.
+ * `domain` is made up of one or more `domain label`.
+ * Each `domain label` is separated by a `.`.
+ * Last `domain label` must be at least 2 characters long.
+ * Each `domain label` must start and end with alphanumeric characters.
+ * Each `domain label` contains alphanumeric characters, separated only by `-`, if any.
+
+* `ADDRESS`: The home address of the employee.
+ * Can take any values, but should not be blank.
+
+* `DEPARTMENT`: The department of the employee.
+ * Only alphanumeric department names with spaces is allowed.
+ * Special characters are not allowed in department names.
+
+* `EFFICIENCY`: The efficiency score of the employee.
+ * Takes in integer values in the range 0 to 100.
+
+* `TAG`: The tag of the employee.
+ * Should be alphanumeric without any whitespace. e.g: SisterBrother
+
+* `INDEX`: The index refers to the index number shown in the displayed employee list.
+ * Assigned to employee based on the order added into employee list.
+ * Must be a **positive integer** (e.g. 1, 2, 3, …) and should not be out of bound of the employee list.
+ * Can only take integer within the maximum bound of `int` data type (up to 2147483647), otherwise it will not be considered as a positive integer.
+
+* `TASK`: The task title of task.
+ * Only alphanumeric task titles with spaces is allowed.
+ * Special characters are not allowed in task titles.
+ * Task of the same task title are not allowed to be assigned to different employees.
+ * `TASK` is case-sensitive (e.g. `project` is not the same as `Project`)
+ * `TASK` is space-sensitive (e.g. `Project A` is not the same as `Project A`)
+
+* `KEYWORD`: The keyword of the query.
+ * `KEYWORD` is case-insensitive.
+
+* `THRESHOLD`: The threshold of efficiency score of the employee.
+ * Takes in integer values in the range 0 to 100.
+
+* `COMMENT`: The comment about the employee.
+ * Can take in any values.
+
+>
### Viewing help : `help`
-Shows a message explaning how to access the help page.
+Shows a message explaining how to access the help page.

Format: `help`
-### Adding a person: `add`
+### Adding an employee: `add`
-Adds a person to the address book.
+Adds an employee to EffiTrack.
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS d/DEPARTMENT eff/EFFICIENCY [t/TAG]…`
+
+
+
+**Tip:**
+* An employee can have any number of tags (including 0).
+* Tags should be alphanumeric without any whitespace. e.g: SisterBrother
+* Adding a new person with the same name (case-sensitive) with an existing person is not possible even if other fields are different
+
Examples:
-* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01`
-* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal`
+* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01 d/Finance eff/80`
+* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 d/Murder eff/10 t/criminal`
-### Listing all persons : `list`
+### Listing all employees : `list`
-Shows a list of all persons in the address book.
+Shows a list of all employees in EffiTrack.
Format: `list`
-### Editing a person : `edit`
+### Editing an employee : `edit`
-Edits an existing person in the address book.
+Edits an existing employee in EffiTrack.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [d/DEPARTMENT] [t/TAG]…`
-* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …
+* Edits the employee at the specified `INDEX`. The index refers to the index number shown in the displayed employee list. The index **must be a positive integer** 1, 2, 3, …
* At least one of the optional fields must be provided.
* Existing values will be updated to the input values.
-* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-* You can remove all the person’s tags by typing `t/` without
+* Name of employee cannot be edited to a name that already exists even if other fields are different.
+* When editing tags, the existing tags of the employee will be removed i.e adding of tags is not cumulative.
+* You can remove all the employee’s tags by typing `t/` without
specifying any tags after it.
Examples:
-* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively.
-* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
+* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st employee to be `91234567` and `johndoe@example.com` respectively.
+* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd employee to be `Betsy Crower` and clears all existing tags.
+
+### Edit deadline of a task : `edit_deadline`
+
+Edit the deadline of an employee's task
+
+Format: `edit_deadline INDEX by/dd-MM-yyyy HHmm`
-### Locating persons by name: `find`
+Example:
+* `edit_deadline 1 by/22-04-2024 2359`
-Finds persons whose names contain any of the given keywords.
+### Locating employees by name: `find`
+
+Finds employees whose names contain any of the given keywords.
Format: `find KEYWORD [MORE_KEYWORDS]`
* The search is case-insensitive. e.g `hans` will match `Hans`
* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
* Only the name is searched.
-* Only full words will be matched e.g. `Han` will not match `Hans`
+* Partial words will be matched e.g. `Han` will match `Hans`
* Persons matching at least one keyword will be returned (i.e. `OR` search).
e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
Examples:
* `find John` returns `john` and `John Doe`
* `find alex david` returns `Alex Yeoh`, `David Li`
- 
-### Deleting a person : `delete`
+
+
+
+### Locating employees by department: `filter`
-Deletes the specified person from the address book.
+Filters employees by their department or tags
+
+Format: `filter KEYWORD [MORE_KEYWORDS]`
+
+* The search is case-insensitive. e.g `finance` will match `Finance`
+* The order of the keywords does not matter. e.g. `Quantitative Finance` will match `Finance Quantitative`
+* Only the departments and tags are searched.
+* Partial words will be matched e.g. `Fin` will match `Finance`
+* Persons matching at least one keyword will be returned (i.e. `OR` search).
+ e.g. `Marketing Fiance` will return `Quantitative Finance`, `Marketing`
+
+Examples:
+* `filter Finance` returns `Finance` and `Quantitative Finance`
+* `filter resource` returns `Human Resource`, `Resource Management`
+
+
+
+### Deleting an employee : `delete`
+
+Deletes the specified employee from EffiTrack.
Format: `delete INDEX`
-* Deletes the person at the specified `INDEX`.
+* Deletes the employee at the specified `INDEX`.
+* The index refers to the index number shown in the displayed employee list.
+* The index **must be a positive integer** 1, 2, 3, …
+
+Examples:
+* `list` followed by `delete 2` deletes the 2nd employee in EffiTrack.
+* `find Betsy` followed by `delete 1` deletes the 1st employee in the results of the `find` command.
+
+### Assign a task: `assign`
+
+Assign a task to a specific person.
+
+Format: `assign task/TASK_TITLE by/dd-MM-yyyy HHmm to/INDEX`
+
+* Assigns the task to the person at the specified `INDEX`
* The index refers to the index number shown in the displayed person list.
* The index **must be a positive integer** 1, 2, 3, …
+* The deadline **must be in the correct format**
+* Task box might be displayed in a collapsed form but could be clicked on to expand for full details
+
+Examples:
+* `assign task/Complete Project Proposal by/20-04-2024 2359 to/1` Assign the 'Complete Project Proposal' task to the first person in the address book.
+
+### Reassigning a task: `reassign`
+
+Reassign a specific task from one person to another.
+
+Format `reassign from/FROMINDEX to/TOINDEX`
+
+* Assigns the task, which was previously assigned to person at the specified `FROMINDEX`, to the person at the specified `TOINDEX`
+* The index refers to the index number shown in the displayed employee list.
+* The index **must be a positive integer** 1, 2, 3, …
+
+### Marking a task : `mark`
+
+Mark the specified task as done.
+
+Format: `mark task/TASKNAME o/INDEX`
+
+* Mark the specified task with `TASKNAME` as done.
+* The index refers to the index number shown in the displayed employee list.
+* The index **must be a positive integer** 1, 2, 3, …
+* Updates the person in charge's efficiency as such:
+ * Completed on the deadline: efficiency + 1
+ * Completed N days early: efficiency + N
+ * Completed N days late: efficiency - 2N
Examples:
-* `list` followed by `delete 2` deletes the 2nd person in the address book.
-* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+* `mark task/Submit Project o/1` mark the task Submit Project assigned to the first employee in EffiTrack as done.
+
+### Finding a task : `findtask`
+
+Finds the person(s) in charge of the task. Note that this only updates the person list on the right side of the UI,
+and not the task list and the bottom left corner.
+
+Format `findtask KEYWORD`
+
+* The search is case-insensitive. e.g `report` will match `Report`
+* The order of the keywords do not matter. e.g. `report submit` will match `submit report`
+* Only the task name is searched.
+* Partial words will be matched e.g. `report` will match `reports`
+
+### Finding a free person : `findfree`
+
+Finds the person(s) who has no current task.
+
+Format `findfree`
+
+### Filtering employees by efficiency: `filter_efficiency`
+
+Filters employees with efficiency less than or equals to a given threshold.
+
+Format: `filter_efficiency THRESHOLD`
+
+* The threshold **must be an integer in the range 0 to 100**.
+
+Examples:
+* `filter_efficiency 30` returns employees with efficiency 0 to 30.
### Clearing all entries : `clear`
-Clears all entries from the address book.
+Clears all entries from EffiTrack.
Format: `clear`
@@ -153,18 +347,47 @@ Exits the program.
Format: `exit`
+### Undoing the previous command : `undo`
+
+Undo the previous command.
+
+Format: `undo`
+
+### Redoing the previous command : `redo`
+
+Reverts the latest undo command.
+
+Format: `redo`
+
+### Displaying the command history : `history`
+
+Displays the commands executed from most recent to earliest, inclusive of invalid commands. It only stores commands used in a single session of usage of the program and is cleared if the app is restarted.
+
+Format: `history`
+
+### Adding a comment to an employee : `comment`
+
+Adds comment to an employee
+
+Format: `comment INDEX c/COMMENT`
+
+Example:
+* `comment 1 c/Good at database management.`
+
### Saving the data
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+EffiTrack data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
### Editing the data file
-AddressBook data are saved automatically as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+EffiTrack data are saved automatically as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+
+
-
:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it.
-Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside of the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
-
+**Caution:**
+If your changes to the data file makes its format invalid, EffiTrack will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it.
+Furthermore, certain edits can cause the EffiTrack to behave in unexpected ways (e.g., if a value entered is outside the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
+
### Archiving data files `[coming in v2.0]`
@@ -175,7 +398,7 @@ _Details coming soon ..._
## FAQ
**Q**: How do I transfer my data to another Computer?
-**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder.
+**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous EffiTrack home folder.
--------------------------------------------------------------------------------------------------------------------
@@ -187,12 +410,25 @@ _Details coming soon ..._
## Command summary
-Action | Format, Examples
---------|------------------
-**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…` e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague`
-**Clear** | `clear`
+Action | Format, Examples
+-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS d/DEPARTMENT eff/EFFICIENCY [t/TAG]…` e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 d/IT eff/80 t/friend t/colleague`
**Delete** | `delete INDEX` e.g., `delete 3`
-**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…` e.g.,`edit 2 n/James Lee e/jameslee@example.com`
-**Find** | `find KEYWORD [MORE_KEYWORDS]` e.g., `find James Jake`
-**List** | `list`
-**Help** | `help`
+**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [d/DEPARTMENT] [t/TAG]…` e.g.,`edit 2 n/James Lee e/jameslee@example.com`
+**Assign Task** | `assign task/TASK by/dd-MM-yyyy to/INDEX` e.g., `assign task/Complete Project Proposal by/22-05-2023 2359 to/1`
+**Reassign Task** | `reassign from/FROMINDEX to/TOINDEX` e.g., `reassign from/2 to/1`
+**Mark Task** | `mark task/TASK o/INDEX` e.g. `mark task/Complete Project Proposal o/1`
+**Edit Deadline** | `edit_deadline INDEX by/dd-MM-yyyy HHmm`
+**Find Name** | `find KEYWORD [MORE_KEYWORDS]` e.g., `find James Jake`
+**Filter Department** | `filter KEYWORD [MORE_KEYWORDS]` e.g., `filter Finance`
+**Filter Efficiency** | `filter_efficiency THRESHOLD` e.g., `filter_efficiency 40`
+**Find Task** | `findtask KEYWORD` e.g., `findtask Project`
+**Find Free Person** | `findfree`
+**Comment** | `comment INDEX c/COMMENT` e.g., `comment 1 c/Good at database management.`
+**List** | `list`
+**Clear** | `clear`
+**Undo** | `undo`
+**Redo** | `redo`
+**History** | `history`
+**Help** | `help`
+**Exit** | `exit`
diff --git a/docs/_config.yml b/docs/_config.yml
deleted file mode 100644
index 6bd245d8f4e..00000000000
--- a/docs/_config.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-title: "AB-3"
-theme: minima
-
-header_pages:
- - UserGuide.md
- - DeveloperGuide.md
- - AboutUs.md
-
-markdown: kramdown
-
-repository: "se-edu/addressbook-level3"
-github_icon: "images/github-icon.png"
-
-plugins:
- - jemoji
diff --git a/docs/_data/projects.yml b/docs/_data/projects.yml
deleted file mode 100644
index 8f3e50cb601..00000000000
--- a/docs/_data/projects.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-- name: "AB-1"
- url: https://se-edu.github.io/addressbook-level1
-
-- name: "AB-2"
- url: https://se-edu.github.io/addressbook-level2
-
-- name: "AB-3"
- url: https://se-edu.github.io/addressbook-level3
-
-- name: "AB-4"
- url: https://se-edu.github.io/addressbook-level4
-
-- name: "Duke"
- url: https://se-edu.github.io/duke
-
-- name: "Collate"
- url: https://se-edu.github.io/collate
-
-- name: "Book"
- url: https://se-edu.github.io/se-book
-
-- name: "Resources"
- url: https://se-edu.github.io/resources
diff --git a/docs/_includes/custom-head.html b/docs/_includes/custom-head.html
deleted file mode 100644
index 8559a67ffad..00000000000
--- a/docs/_includes/custom-head.html
+++ /dev/null
@@ -1,6 +0,0 @@
-{% comment %}
- Placeholder to allow defining custom head, in principle, you can add anything here, e.g. favicons:
-
- 1. Head over to https://realfavicongenerator.net/ to add your own favicons.
- 2. Customize default _includes/custom-head.html in your source directory and insert the given code snippet.
-{% endcomment %}
diff --git a/docs/_includes/head.html b/docs/_includes/head.html
deleted file mode 100644
index 83ac5326933..00000000000
--- a/docs/_includes/head.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
- {%- include custom-head.html -%}
-
- {{page.title}}
-
-
diff --git a/docs/_includes/header.html b/docs/_includes/header.html
deleted file mode 100644
index 33badcd4f99..00000000000
--- a/docs/_includes/header.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
+
-:information_source: Don’t forget to update `AddressBookParser` to use our new `RemarkCommandParser`!
+Don’t forget to update `AddressBookParser` to use our new `RemarkCommandParser`!
-
+
If you are stuck, check out the sample
[here](https://github.com/se-edu/addressbook-level3/commit/dc6d5139d08f6403da0ec624ea32bd79a2ae0cbf#diff-8bf239e8e9529369b577701303ddd96af93178b4ed6735f91c2d8488b20c6b4a).
@@ -244,7 +247,7 @@ Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/s
**`PersonCard.java`:**
-``` java
+```java
@FXML
private Label remark;
```
@@ -276,11 +279,11 @@ We change the constructor of `Person` to take a `Remark`. We will also need to d
Unfortunately, a change to `Person` will cause other commands to break, you will have to modify these commands to use the updated `Person`!
-
+
-:bulb: Use the `Find Usages` feature in IntelliJ IDEA on the `Person` class to find these commands.
+Use the `Find Usages` feature in IntelliJ IDEA on the `Person` class to find these commands.
-
+
Refer to [this commit](https://github.com/se-edu/addressbook-level3/commit/ce998c37e65b92d35c91d28c7822cd139c2c0a5c) and check that you have got everything in order!
@@ -291,11 +294,11 @@ AddressBook stores data by serializing `JsonAdaptedPerson` into `json` with the
While the changes to code may be minimal, the test data will have to be updated as well.
-
+
-:exclamation: You must delete AddressBook’s storage file located at `/data/addressbook.json` before running it! Not doing so will cause AddressBook to default to an empty address book!
+You must delete AddressBook’s storage file located at `/data/addressbook.json` before running it! Not doing so will cause AddressBook to default to an empty address book!
-
+
Check out [this commit](https://github.com/se-edu/addressbook-level3/commit/556cbd0e03ff224d7a68afba171ad2eb0ce56bbf)
to see what the changes entail.
@@ -308,7 +311,7 @@ Just add [this one line of code!](https://github.com/se-edu/addressbook-level3/c
**`PersonCard.java`:**
-``` java
+```java
public PersonCard(Person person, int displayedIndex) {
//...
remark.setText(person.getRemark().value);
@@ -328,7 +331,7 @@ save it with `Model#setPerson()`.
**`RemarkCommand.java`:**
-``` java
+```java
//...
public static final String MESSAGE_ADD_REMARK_SUCCESS = "Added remark to Person: %1$s";
public static final String MESSAGE_DELETE_REMARK_SUCCESS = "Removed remark from Person: %1$s";
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index f29169bc924..c73bd379e5e 100644
--- a/docs/tutorials/RemovingFields.md
+++ b/docs/tutorials/RemovingFields.md
@@ -1,8 +1,11 @@
---
-layout: page
-title: "Tutorial: Removing Fields"
+ layout: default.md
+ title: "Tutorial: Removing Fields"
+ pageNav: 3
---
+# Tutorial: Removing Fields
+
> Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
>
> — Antoine de Saint-Exupery
@@ -10,17 +13,17 @@ title: "Tutorial: Removing Fields"
When working on an existing code base, you will most likely find that some features that are no longer necessary.
This tutorial aims to give you some practice on such a code 'removal' activity by removing the `address` field from `Person` class.
-
+
**If you have done the [Add `remark` command tutorial](AddRemark.html) already**, you should know where the code had to be updated to add the field `remark`. From that experience, you can deduce where the code needs to be changed to _remove_ that field too. The removing of the `address` field can be done similarly.
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.**
-
+
-* Table of Contents
-{:toc}
+
+
## Safely deleting `Address`
@@ -50,10 +53,10 @@ Let’s try removing references to `Address` in `EditPersonDescriptor`.
1. Remove the usages of `address` and select `Do refactor` when you are done.
-
+
- :bulb: **Tip:** Removing usages may result in errors. Exercise discretion and fix them. For example, removing the `address` field from the `Person` class will require you to modify its constructor.
-
+ **Tip:** Removing usages may result in errors. Exercise discretion and fix them. For example, removing the `address` field from the `Person` class will require you to modify its constructor.
+
1. Repeat the steps for the remaining usages of `Address`
@@ -71,7 +74,7 @@ A quick look at the `PersonCard` class and its `fxml` file quickly reveals why i
**`PersonCard.java`**
-``` java
+```java
...
@FXML
private Label address;
diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md
index 4fb62a83ef6..2b1b0f2d6b7 100644
--- a/docs/tutorials/TracingCode.md
+++ b/docs/tutorials/TracingCode.md
@@ -1,26 +1,30 @@
---
-layout: page
-title: "Tutorial: Tracing code"
+ layout: default.md
+ title: "Tutorial: Tracing code"
+ pageNav: 3
---
+# Tutorial: Tracing code
+
+
> Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. …\[Therefore,\] making it easy to read makes it easier to write.
>
> — Robert C. Martin Clean Code: A Handbook of Agile Software Craftsmanship
When trying to understand an unfamiliar code base, one common strategy used is to trace some representative execution path through the code base. One easy way to trace an execution path is to use a debugger to step through the code. In this tutorial, you will be using the IntelliJ IDEA’s debugger to trace the execution path of a specific user command.
-* Table of Contents
-{:toc}
+
+
## Before we start
Before we jump into the code, it is useful to get an idea of the overall structure and the high-level behavior of the application. This is provided in the 'Architecture' section of the developer guide. In particular, the architecture diagram (reproduced below), tells us that the App consists of several components.
-
+
It also has a sequence diagram (reproduced below) that tells us how a command propagates through the App.
-
+
Note how the diagram shows only the execution flows _between_ the main components. That is, it does not show details of the execution path *inside* each component. By hiding those details, the diagram aims to inform the reader about the overall execution path of a command without overwhelming the reader with too much details. In this tutorial, you aim to find those omitted details so that you get a more in-depth understanding of how the code works.
@@ -37,16 +41,16 @@ As you know, the first step of debugging is to put in a breakpoint where you wan
In our case, we would want to begin the tracing at the very point where the App start processing user input (i.e., somewhere in the UI component), and then trace through how the execution proceeds through the UI component. However, the execution path through a GUI is often somewhat obscure due to various *event-driven mechanisms* used by GUI frameworks, which happens to be the case here too. Therefore, let us put the breakpoint where the `UI` transfers control to the `Logic` component.
-
+
According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `seedu.address.logic.Logic`.
-
+
-:bulb: **Intellij Tip:** The ['**Search Everywhere**' feature](https://www.jetbrains.com/help/idea/searching-everywhere.html) can be used here. In particular, the '**Find Symbol**' ('Symbol' here refers to methods, variables, classes etc.) variant of that feature is quite useful here as we are looking for a _method_ named `execute`, not simply the text `execute`.
-
+**Intellij Tip:** The ['**Search Everywhere**' feature](https://www.jetbrains.com/help/idea/searching-everywhere.html) can be used here. In particular, the '**Find Symbol**' ('Symbol' here refers to methods, variables, classes etc.) variant of that feature is quite useful here as we are looking for a _method_ named `execute`, not simply the text `execute`.
+
A quick look at the `seedu.address.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for.
@@ -67,14 +71,14 @@ public interface Logic {
But apparently, this is an interface, not a concrete implementation.
That should be fine because the [Architecture section of the Developer Guide](../DeveloperGuide.html#architecture) tells us that components interact through interfaces. Here's the relevant diagram:
-
+
Next, let's find out which statement(s) in the `UI` code is calling this method, thus transferring control from the `UI` to the `Logic`.
-
+
-:bulb: **Intellij Tip:** The ['**Find Usages**' feature](https://www.jetbrains.com/help/idea/find-highlight-usages.html#find-usages) can find from which parts of the code a class/method/variable is being used.
-
+**Intellij Tip:** The ['**Find Usages**' feature](https://www.jetbrains.com/help/idea/find-highlight-usages.html#find-usages) can find from which parts of the code a class/method/variable is being used.
+

@@ -87,10 +91,10 @@ Now let’s set the breakpoint. First, double-click the item to reach the corres
Recall from the User Guide that the `edit` command has the format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…` For this tutorial we will be issuing the command `edit 1 n/Alice Yeoh`.
-
+
-:bulb: **Tip:** Over the course of the debugging session, you will encounter every major component in the application. Try to keep track of what happens inside the component and where the execution transfers to another component.
-
+**Tip:** Over the course of the debugging session, you will encounter every major component in the application. Try to keep track of what happens inside the component and where the execution transfers to another component.
+
1. To start the debugging session, simply `Run` \> `Debug Main`
@@ -110,7 +114,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
**LogicManager\#execute().**
- ``` java
+ ```java
@Override
public CommandResult execute(String commandText)
throws CommandException, ParseException {
@@ -142,7 +146,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [

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
+ ```java
public Command parseCommand(String userInput) throws ParseException {
...
final String commandWord = matcher.group("commandWord");
@@ -157,7 +161,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
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
+ ```java
...
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
@@ -166,8 +170,10 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
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()`.
-
:bulb: **Intellij Tip:** Sometimes, you might end up stepping into functions that are not of interest. Simply use the `step out` button to get out of them!
-
+
+
+ **Intellij Tip:** Sometimes, you might end up stepping into functions that are not of interest. Simply use the `step out` button to get out of them!
+
1. Stepping through the method shows that it calls `ArgumentTokenizer#tokenize()` and `ParserUtil#parseIndex()` to obtain the arguments and index required.
@@ -175,17 +181,17 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [

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?
- 
+
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
+ ```java
@Override
public CommandResult execute(Model model) throws CommandException {
...
@@ -205,25 +211,28 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
* 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: **Intellij Tip:** When trying to step into a statement such as `storage.saveAddressBook(model.getAddressBook())` which contains multiple method calls, Intellij will let you choose (by clicking) which one you want to step into.
-
+
+
+ **Intellij Tip:** When trying to step into a statement such as `storage.saveAddressBook(model.getAddressBook())` which contains multiple method calls, Intellij will let you choose (by clicking) which one you want to step into.
+
-1. As you step through the code inside the `Storage` component, you will eventually arrive at the `JsonAddressBook#saveAddressBook()` method which calls the `JsonSerializableAddressBook` constructor, to create an object that can be _serialized_ (i.e., stored in storage medium) in JSON format. That constructor is given below (with added line breaks for easier readability):
+1. As you step through the code inside the `Storage` component, you will eventually arrive at the `JsonAddressBook#saveAddressBook()` method which calls the `JsonSerializableAddressBook` constructor, to create an object that can be _serialized_ (i.e., stored in storage medium) in JSON format. That constructor is given below (with added line breaks for easier readability):
**`JsonSerializableAddressBook` constructor:**
- ``` java
+ ```java
/**
* Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
*
@@ -243,7 +252,8 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
This is because regular Java objects need to go through an _adaptation_ for them to be suitable to be saved in JSON format.
1. While you are stepping through the classes in the `Storage` component, here is the component's class diagram to help you understand how those classes fit into the structure of the 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).
@@ -251,7 +261,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
1. Stepping into `resultDisplay.setFeedbackToUser(commandResult.getFeedbackToUser());`, we end up in:
**`ResultDisplay#setFeedbackToUser()`**
- ``` java
+ ```java
public void setFeedbackToUser(String feedbackToUser) {
requireNonNull(feedbackToUser);
resultDisplay.setText(feedbackToUser);
diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/seedu/address/Main.java
index ec1b7958746..eb6216546c8 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/address/Main.java
@@ -34,7 +34,6 @@ public static void main(String[] args) {
// The warning however, can be safely ignored. Thus, the following log informs
// the user (if looking at the log output) that the said warning appearing in the log
// can be ignored.
-
logger.warning("The warning about Unsupported JavaFX configuration below can be ignored.");
Application.launch(MainApp.class, args);
}
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/address/commons/core/GuiSettings.java
index a97a86ee8d7..9141278f460 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/address/commons/core/GuiSettings.java
@@ -13,7 +13,7 @@
public class GuiSettings implements Serializable {
private static final double DEFAULT_HEIGHT = 600;
- private static final double DEFAULT_WIDTH = 740;
+ private static final double DEFAULT_WIDTH = 750;
private final double windowWidth;
private final double windowHeight;
diff --git a/src/main/java/seedu/address/commons/util/InvalidationListenerManager.java b/src/main/java/seedu/address/commons/util/InvalidationListenerManager.java
new file mode 100644
index 00000000000..70165336db6
--- /dev/null
+++ b/src/main/java/seedu/address/commons/util/InvalidationListenerManager.java
@@ -0,0 +1,52 @@
+package seedu.address.commons.util;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.ArrayList;
+
+import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
+
+/**
+ * Manages a list of {@link InvalidationListener}.
+ */
+public class InvalidationListenerManager {
+ private final ArrayList listeners = new ArrayList<>();
+
+ /**
+ * Calls {@link InvalidationListener#invalidated(Observable)} on all added listeners.
+ * Any modifications to the listeners list during the invocation of this method
+ * will only take effect on the next invocation of this method.
+ *
+ * @param observable The {@code Observable} that became invalid.
+ */
+ public void callListeners(Observable observable) {
+ // Make a copy of listeners such that any modifications to the listeners list during
+ // the invocation of this method will only take effect on the next invocation of this method.
+ ArrayList listenersCopy = new ArrayList<>(listeners);
+
+ for (InvalidationListener listener : listenersCopy) {
+ listener.invalidated(observable);
+ }
+ }
+
+ /**
+ * Adds {@code listener} to the list of listeners.
+ * If the same listener is added more that once, then it will be notified more than once.
+ */
+ public void addListener(InvalidationListener listener) {
+ requireNonNull(listener);
+ listeners.add(listener);
+ }
+
+ /**
+ * Removes {@code listener} from the list of listeners.
+ * If the given listener was not previously added, then this method call is a no-op.
+ * If the given listener was added more than once, then only the first occurrence in the list will be removed.
+ */
+ public void removeListener(InvalidationListener listener) {
+ requireNonNull(listener);
+ listeners.remove(listener);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/CommandHistory.java b/src/main/java/seedu/address/logic/CommandHistory.java
new file mode 100644
index 00000000000..e8b8abae229
--- /dev/null
+++ b/src/main/java/seedu/address/logic/CommandHistory.java
@@ -0,0 +1,60 @@
+package seedu.address.logic;
+
+import static java.util.Objects.requireNonNull;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+
+/**
+ * @@author yiwern5-reused
+ * Reused from AB4 https://github.com/se-edu/addressbook-level4/
+ * Stores the history of commands executed.
+ */
+public class CommandHistory {
+ private final ObservableList userInputHistory = FXCollections.observableArrayList();
+ private final ObservableList unmodifiableUserInputHistory =
+ FXCollections.unmodifiableObservableList(userInputHistory);
+
+ public CommandHistory() {}
+
+ public CommandHistory(CommandHistory commandHistory) {
+ userInputHistory.addAll(commandHistory.userInputHistory);
+ }
+
+ /**
+ * Appends {@code userInput} to the list of user input entered.
+ */
+ public void add(String userInput) {
+ requireNonNull(userInput);
+ userInputHistory.add(userInput);
+ }
+
+ /**
+ * Returns an unmodifiable view of {@code userInputHistory}.
+ */
+ public ObservableList getHistory() {
+ return unmodifiableUserInputHistory;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // short circuit if same object
+ if (obj == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(obj instanceof CommandHistory)) {
+ return false;
+ }
+
+ // state check
+ CommandHistory other = (CommandHistory) obj;
+ return userInputHistory.equals(other.userInputHistory);
+ }
+
+ @Override
+ public int hashCode() {
+ return userInputHistory.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..7d6abde6277 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -9,6 +9,7 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
/**
* API of the Logic component
@@ -33,6 +34,8 @@ public interface Logic {
/** Returns an unmodifiable view of the filtered list of persons */
ObservableList getFilteredPersonList();
+ ObservableList getTaskList();
+
/**
* Returns the user prefs' address book file path.
*/
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 5aa3b91c7d0..c0a60bd9c36 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -16,6 +16,7 @@
import seedu.address.model.Model;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
import seedu.address.storage.Storage;
/**
@@ -31,7 +32,9 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
+ private final CommandHistory history;
private final AddressBookParser addressBookParser;
+ private boolean addressBookModified;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
@@ -39,23 +42,42 @@ public class LogicManager implements Logic {
public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
+ history = new CommandHistory();
addressBookParser = new AddressBookParser();
+ model.getAddressBook().addListener(observable -> addressBookModified = true);
+
}
+ /**
+ * @@author yiwern5-reused
+ * Reused from AB4 https://github.com/se-edu/addressbook-level4/ with minor modifications
+ * @param commandText The command as entered by the user.
+ * @return {@code CommandResult}
+ * @throws CommandException
+ * @throws ParseException
+ */
@Override
public CommandResult execute(String commandText) throws CommandException, ParseException {
logger.info("----------------[USER COMMAND][" + commandText + "]");
+ addressBookModified = false;
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
- commandResult = command.execute(model);
-
try {
- storage.saveAddressBook(model.getAddressBook());
- } catch (AccessDeniedException e) {
- throw new CommandException(String.format(FILE_OPS_PERMISSION_ERROR_FORMAT, e.getMessage()), e);
- } catch (IOException ioe) {
- throw new CommandException(String.format(FILE_OPS_ERROR_FORMAT, ioe.getMessage()), ioe);
+ Command command = addressBookParser.parseCommand(commandText);
+ commandResult = command.execute(model, history);
+ } finally {
+ history.add(commandText);
+ }
+
+ if (addressBookModified) {
+ logger.info("Address book modified, saving to file.");
+ try {
+ storage.saveAddressBook(model.getAddressBook());
+ } catch (AccessDeniedException e) {
+ throw new CommandException(String.format(FILE_OPS_PERMISSION_ERROR_FORMAT, e.getMessage()), e);
+ } catch (IOException ioe) {
+ throw new CommandException(String.format(FILE_OPS_ERROR_FORMAT, ioe.getMessage()), ioe);
+ }
}
return commandResult;
@@ -71,6 +93,11 @@ public ObservableList getFilteredPersonList() {
return model.getFilteredPersonList();
}
+ @Override
+ public ObservableList getTaskList() {
+ return model.getFilteredTaskList();
+ }
+
@Override
public Path getAddressBookFilePath() {
return model.getAddressBookFilePath();
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index ecd32c31b53..62269d9458b 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -6,6 +6,7 @@
import seedu.address.logic.parser.Prefix;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
/**
* Container for user visible messages.
@@ -43,9 +44,32 @@ public static String format(Person person) {
.append(person.getEmail())
.append("; Address: ")
.append(person.getAddress())
+ .append("; Department: ")
+ .append(person.getDepartment())
.append("; Tags: ");
person.getTags().forEach(builder::append);
return builder.toString();
}
+ /**
+ * Returns the full name of a person given.
+ */
+ public static String printName(Person person) {
+ return person.getName().toString();
+ }
+
+ /**
+ * Returns the task name of a task.
+ */
+ public static String printTask(Task task) {
+ return task.getTaskTitle().toString();
+ }
+
+ /**
+ * Returns the deadline of a task.
+ */
+ public static String printDeadline(Task task) {
+ return task.getDeadline().toString();
+ }
+
}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 5d7185a9680..635ff6cd800 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -2,12 +2,15 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEPARTMENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EFFICIENCY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
@@ -26,14 +29,18 @@ public class AddCommand extends Command {
+ PREFIX_PHONE + "PHONE "
+ PREFIX_EMAIL + "EMAIL "
+ PREFIX_ADDRESS + "ADDRESS "
+ + PREFIX_DEPARTMENT + "DEPARTMENT "
+ + PREFIX_EFFICIENCY + "EFFICIENCY "
+ "[" + PREFIX_TAG + "TAG]...\n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_NAME + "John Doe "
+ PREFIX_PHONE + "98765432 "
+ PREFIX_EMAIL + "johnd@example.com "
+ PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
+ + PREFIX_DEPARTMENT + "Business Development "
+ PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
+ + PREFIX_TAG + "owesMoney "
+ + PREFIX_EFFICIENCY + "80";
public static final String MESSAGE_SUCCESS = "New person added: %1$s";
public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
@@ -49,7 +56,7 @@ public AddCommand(Person person) {
}
@Override
- public CommandResult execute(Model model) throws CommandException {
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
requireNonNull(model);
if (model.hasPerson(toAdd)) {
@@ -57,6 +64,7 @@ public CommandResult execute(Model model) throws CommandException {
}
model.addPerson(toAdd);
+ model.commitAddressBook();
return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(toAdd)));
}
diff --git a/src/main/java/seedu/address/logic/commands/AssignTaskCommand.java b/src/main/java/seedu/address/logic/commands/AssignTaskCommand.java
new file mode 100644
index 00000000000..f9a2bc8bc0c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AssignTaskCommand.java
@@ -0,0 +1,105 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEADLINE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TO;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
+
+/**
+ * Assign Task to Employees
+ */
+public class AssignTaskCommand extends Command {
+
+ public static final String COMMAND_WORD = "assign";
+ public static final String MESSAGE_ASSIGN_TASK_SUCCESS = "Assigned task %1$s to %2$s successfully";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Assigns a task to a person identified by index number.\n"
+ + "Parameters: "
+ + PREFIX_TASK + "TASK "
+ + PREFIX_DEADLINE + "dd-MM-yyyy HHmm "
+ + PREFIX_TO + "INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_TASK + "Complete Project Proposal "
+ + PREFIX_DEADLINE + "22-04-2024 2359 "
+ + PREFIX_TO + "1";
+
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already existed. \n"
+ + "Please use a different task name.";
+ public static final String MESSAGE_PERSON_IS_BUSY = "A task has already been assigned for %1$s.\n"
+ + "Please select another person.";
+ private final Index index;
+ private final Task task;
+
+ /**
+ * Assign task to a existing person in the address book.
+ * @param task
+ * @param index
+ */
+ public AssignTaskCommand(Task task, Index index) {
+ requireNonNull(index);
+ this.task = task;
+ this.index = index;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
+ requireNonNull(model);
+ if (model.hasTask(task)) {
+ throw new CommandException(String.format(MESSAGE_DUPLICATE_TASK));
+ }
+
+ List personList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= personList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person assignedTo = personList.get(index.getZeroBased());
+
+ if (assignedTo.isBusy()) {
+ throw new CommandException(String.format(MESSAGE_PERSON_IS_BUSY, Messages.printName(assignedTo)));
+ }
+
+ model.assignTask(task, assignedTo);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ model.commitAddressBook();
+ return new CommandResult(String.format(MESSAGE_ASSIGN_TASK_SUCCESS,
+ Messages.printTask(task), Messages.printName(assignedTo)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AssignTaskCommand)) {
+ return false;
+ }
+
+ AssignTaskCommand otherAssignCommand = (AssignTaskCommand) other;
+ return task.equals(otherAssignCommand.task) && index.equals(otherAssignCommand.index);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("task", task)
+ .add("index", index)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
index 9c86b1fa6e4..a22219ad76a 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java
@@ -2,6 +2,7 @@
import static java.util.Objects.requireNonNull;
+import seedu.address.logic.CommandHistory;
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
@@ -15,9 +16,10 @@ public class ClearCommand extends Command {
@Override
- public CommandResult execute(Model model) {
+ public CommandResult execute(Model model, CommandHistory history) {
requireNonNull(model);
model.setAddressBook(new AddressBook());
+ model.commitAddressBook();
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/address/logic/commands/Command.java
index 64f18992160..3e072fa75b6 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/address/logic/commands/Command.java
@@ -1,5 +1,6 @@
package seedu.address.logic.commands;
+import seedu.address.logic.CommandHistory;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
@@ -15,6 +16,6 @@ public abstract class Command {
* @return feedback message of the operation result for display
* @throws CommandException If an error occurs during command execution.
*/
- public abstract CommandResult execute(Model model) throws CommandException;
+ public abstract CommandResult execute(Model model, CommandHistory history) throws CommandException;
}
diff --git a/src/main/java/seedu/address/logic/commands/CommentCommand.java b/src/main/java/seedu/address/logic/commands/CommentCommand.java
new file mode 100644
index 00000000000..38e747d12b2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/CommentCommand.java
@@ -0,0 +1,90 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Comment;
+import seedu.address.model.person.Person;
+
+
+
+/**
+ * Changes the comment of an existing person in the address book.
+ */
+public class CommentCommand extends Command {
+
+ public static final String MESSAGE_ARGUMENTS = "Index: %1$d, Comment: %2$s";
+
+ public static final String COMMAND_WORD = "comment";
+
+ public static final String MESSAGE_ADD_COMMENT_SUCCESS = "Added comment to Person: %1$s";
+ public static final String MESSAGE_DELETE_COMMENT_SUCCESS = "Removed comment from Person: %1$s";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Edits the comment of the person identified "
+ + "by the index number used in the last person listing. "
+ + "Existing comment will be overwritten by the input.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "c/[COMMENT]\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + "c/Good at database management.";
+
+ private final Index index;
+ private final Comment comment;
+
+ /**
+ * @param index of the person in the filtered person list to edit the comment
+ * @param comment of the person to be updated to
+ */
+ public CommentCommand(Index index, Comment comment) {
+ requireAllNonNull(index, comment);
+
+ this.index = index;
+ this.comment = comment;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
+ List lastShownList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToEdit = lastShownList.get(index.getZeroBased());
+ Person editedPerson = new Person(
+ personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(),
+ personToEdit.getAddress(), personToEdit.getDepartment(), personToEdit.getTags(),
+ personToEdit.getEfficiency(), this.comment);
+
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.commitAddressBook();
+
+ return new CommandResult(String.format(MESSAGE_ADD_COMMENT_SUCCESS,
+ Messages.printName(personToEdit)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof CommentCommand)) {
+ return false;
+ }
+
+ CommentCommand e = (CommentCommand) other;
+ return index.equals(e.index)
+ && comment.equals(e.comment);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 1135ac19b74..8e684999047 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -6,6 +6,7 @@
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
@@ -32,7 +33,7 @@ public DeleteCommand(Index targetIndex) {
}
@Override
- public CommandResult execute(Model model) throws CommandException {
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
requireNonNull(model);
List lastShownList = model.getFilteredPersonList();
@@ -42,6 +43,7 @@ public CommandResult execute(Model model) throws CommandException {
Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
model.deletePerson(personToDelete);
+ model.commitAddressBook();
return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, Messages.format(personToDelete)));
}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 4b581c7331e..fd7f77d64f7 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -2,11 +2,13 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEPARTMENT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
import java.util.Collections;
import java.util.HashSet;
@@ -18,15 +20,20 @@
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.CollectionUtil;
import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Comment;
+import seedu.address.model.person.Department;
+import seedu.address.model.person.Efficiency;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
import seedu.address.model.tag.Tag;
+import seedu.address.model.task.Task;
/**
* Edits the details of an existing person in the address book.
@@ -43,6 +50,7 @@ public class EditCommand extends Command {
+ "[" + PREFIX_PHONE + "PHONE] "
+ "[" + PREFIX_EMAIL + "EMAIL] "
+ "[" + PREFIX_ADDRESS + "ADDRESS] "
+ + "[" + PREFIX_DEPARTMENT + "DEPARTMENT] "
+ "[" + PREFIX_TAG + "TAG]...\n"
+ "Example: " + COMMAND_WORD + " 1 "
+ PREFIX_PHONE + "91234567 "
@@ -54,6 +62,7 @@ public class EditCommand extends Command {
private final Index index;
private final EditPersonDescriptor editPersonDescriptor;
+ private Task editedTask;
/**
* @param index of the person in the filtered person list to edit
@@ -68,9 +77,10 @@ public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
}
@Override
- public CommandResult execute(Model model) throws CommandException {
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
requireNonNull(model);
List lastShownList = model.getFilteredPersonList();
+ List taskList = model.getFilteredTaskList();
if (index.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
@@ -78,6 +88,15 @@ public CommandResult execute(Model model) throws CommandException {
Person personToEdit = lastShownList.get(index.getZeroBased());
Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ for (Task taskToEdit : taskList) {
+ if (taskToEdit.getPersonInCharge().getName() == personToEdit.getName()) {
+ editedTask = new Task(taskToEdit.getTaskTitle(), taskToEdit.getDeadline(), taskToEdit.isDone());
+ editedTask.setPersonInCharge(editedPerson);
+ editedPerson.setTask(editedTask);
+ model.setTask(taskToEdit, editedTask);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ }
+ }
if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
@@ -85,6 +104,7 @@ public CommandResult execute(Model model) throws CommandException {
model.setPerson(personToEdit, editedPerson);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.commitAddressBook();
return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson)));
}
@@ -99,9 +119,12 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript
Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
+ Department updatedDepartment = editPersonDescriptor.getDepartment().orElse(personToEdit.getDepartment());
Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ Efficiency updatedEfficiency = editPersonDescriptor.getEfficiency().orElse(personToEdit.getEfficiency());
+ Comment updatedComment = personToEdit.getComment();
+ return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedDepartment, updatedTags,
+ updatedEfficiency, updatedComment);
}
@Override
@@ -137,7 +160,9 @@ public static class EditPersonDescriptor {
private Phone phone;
private Email email;
private Address address;
+ private Department department;
private Set tags;
+ private Efficiency efficiency;
public EditPersonDescriptor() {}
@@ -150,6 +175,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) {
setPhone(toCopy.phone);
setEmail(toCopy.email);
setAddress(toCopy.address);
+ setDepartment(toCopy.department);
setTags(toCopy.tags);
}
@@ -157,7 +183,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) {
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(name, phone, email, address, department, tags);
}
public void setName(Name name) {
@@ -192,6 +218,14 @@ public Optional getAddress() {
return Optional.ofNullable(address);
}
+ public void setDepartment(Department department) {
+ this.department = department;
+ }
+
+ public Optional getDepartment() {
+ return Optional.ofNullable(department);
+ }
+
/**
* Sets {@code tags} to this object's {@code tags}.
* A defensive copy of {@code tags} is used internally.
@@ -209,6 +243,14 @@ public Optional> getTags() {
return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
}
+ public void setEfficiency(Efficiency efficiency) {
+ this.efficiency = efficiency;
+ }
+
+ public Optional getEfficiency() {
+ return Optional.ofNullable(efficiency);
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -225,6 +267,7 @@ public boolean equals(Object other) {
&& Objects.equals(phone, otherEditPersonDescriptor.phone)
&& Objects.equals(email, otherEditPersonDescriptor.email)
&& Objects.equals(address, otherEditPersonDescriptor.address)
+ && Objects.equals(department, otherEditPersonDescriptor.department)
&& Objects.equals(tags, otherEditPersonDescriptor.tags);
}
@@ -235,6 +278,7 @@ public String toString() {
.add("phone", phone)
.add("email", email)
.add("address", address)
+ .add("department", department)
.add("tags", tags)
.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/EditDeadlineCommand.java b/src/main/java/seedu/address/logic/commands/EditDeadlineCommand.java
new file mode 100644
index 00000000000..df5f310c9fa
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/EditDeadlineCommand.java
@@ -0,0 +1,97 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEADLINE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.task.Deadline;
+import seedu.address.model.task.Task;
+
+/**
+ * Mark tasks done by employees
+ */
+public class EditDeadlineCommand extends Command {
+
+ public static final String COMMAND_WORD = "edit_deadline";
+ public static final String MESSAGE_MARK_TASK_SUCCESS = "Deadline for %1$s's task changed to %2$s";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Change the deadline of the task of a user.\n"
+ + "Parameters: "
+ + "INDEX (must be a positive integer)\n"
+ + PREFIX_DEADLINE + "dd-MM-yyyy HHmm \n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_DEADLINE + "22-04-2024 2359 ";
+
+ public static final String MESSAGE_TASK_DOES_NOT_EXIST = "%s does not have a Task. "
+ + "Please select another Task";
+ private final Index index;
+
+ private final Deadline deadline;
+
+ /**
+ * Change the deadline of the task of a user.
+ */
+ public EditDeadlineCommand(Index index, Deadline deadline) {
+ requireAllNonNull(index, deadline);
+ this.index = index;
+ this.deadline = deadline;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
+ requireNonNull(model);
+ List personList = model.getFilteredPersonList();
+
+ if (index.getOneBased() > personList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person taskOwner = personList.get(index.getZeroBased());
+
+ if (!taskOwner.isBusy()) {
+ throw new CommandException(String.format(MESSAGE_TASK_DOES_NOT_EXIST, taskOwner.getName()));
+ }
+
+ Task task = taskOwner.getTask();
+ Task editedTask = task.editDeadline(deadline);
+
+ Person editedPerson = new Person(taskOwner.getName(), taskOwner.getPhone(),
+ taskOwner.getEmail(), taskOwner.getAddress(),
+ taskOwner.getDepartment(), taskOwner.getTags(),
+ taskOwner.getEfficiency(), taskOwner.getComment());
+ editedPerson.setTask(editedTask);
+ model.setPerson(taskOwner, editedPerson);
+ model.setTask(task, editedTask);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ model.commitAddressBook();
+ return new CommandResult(String.format(MESSAGE_MARK_TASK_SUCCESS,
+ Messages.printName(taskOwner), deadline.toString()));
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditDeadlineCommand)) {
+ return false;
+ }
+
+ EditDeadlineCommand otherEditDeadlineCommand = (EditDeadlineCommand) other;
+ return index.equals(otherEditDeadlineCommand.index)
+ && this.deadline.equals(otherEditDeadlineCommand.deadline);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..2240a3e4be1 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -1,5 +1,6 @@
package seedu.address.logic.commands;
+import seedu.address.logic.CommandHistory;
import seedu.address.model.Model;
/**
@@ -12,7 +13,7 @@ public class ExitCommand extends Command {
public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
@Override
- public CommandResult execute(Model model) {
+ public CommandResult execute(Model model, CommandHistory history) {
return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
}
diff --git a/src/main/java/seedu/address/logic/commands/FilterCommand.java b/src/main/java/seedu/address/logic/commands/FilterCommand.java
new file mode 100644
index 00000000000..16a83a9571f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FilterCommand.java
@@ -0,0 +1,59 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.PersonContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all persons in address book whose name contains any of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FilterCommand extends Command {
+
+ public static final String COMMAND_WORD = "filter";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all persons by the given departments or tags"
+ + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " alice bob charlie";
+
+ private final PersonContainsKeywordsPredicate predicate;
+
+ public FilterCommand(PersonContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FilterCommand)) {
+ return false;
+ }
+
+ FilterCommand otherFilterCommand = (FilterCommand) other;
+ return predicate.equals(otherFilterCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FilterEfficiencyCommand.java b/src/main/java/seedu/address/logic/commands/FilterEfficiencyCommand.java
new file mode 100644
index 00000000000..6f3b8340fea
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FilterEfficiencyCommand.java
@@ -0,0 +1,61 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.PersonLessThanEfficiencyPredicate;
+
+/**
+ * Finds and lists all persons in address book whose efficiency below the argument threshold.
+ */
+public class FilterEfficiencyCommand extends Command {
+
+ public static final String COMMAND_WORD = "filter_efficiency";
+
+ public static final String MESSAGE_SUCCESS = "Filtered out poor performing employees with efficiency less than %d";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Filters employees with efficiency less than or equals to threshold given.\n"
+ + "Parameters: integer (MUST within the range: 0 to 100)\n"
+ + "Example: " + COMMAND_WORD + " 30";
+ public static final String MESSAGE_INTEGER_OUT_OF_RANGE = "The input efficiency is out of range (0-100)";
+ private final PersonLessThanEfficiencyPredicate predicate;
+
+ public FilterEfficiencyCommand(PersonLessThanEfficiencyPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FilterEfficiencyCommand)) {
+ return false;
+ }
+
+ FilterEfficiencyCommand otherFilterEfficiencyCommand = (FilterEfficiencyCommand) other;
+ return predicate.equals(otherFilterEfficiencyCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index 72b9eddd3a7..85db113606d 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -3,6 +3,7 @@
import static java.util.Objects.requireNonNull;
import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.person.NameContainsKeywordsPredicate;
@@ -15,7 +16,7 @@ public class FindCommand extends Command {
public static final String COMMAND_WORD = "find";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names or tags contain any of "
+ "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ "Example: " + COMMAND_WORD + " alice bob charlie";
@@ -27,7 +28,7 @@ public FindCommand(NameContainsKeywordsPredicate predicate) {
}
@Override
- public CommandResult execute(Model model) {
+ public CommandResult execute(Model model, CommandHistory history) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);
return new CommandResult(
diff --git a/src/main/java/seedu/address/logic/commands/FindFreePersonCommand.java b/src/main/java/seedu/address/logic/commands/FindFreePersonCommand.java
new file mode 100644
index 00000000000..354428d06e0
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindFreePersonCommand.java
@@ -0,0 +1,48 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.PersonHasNoTaskPredicate;
+
+/**
+ * Finds and lists all persons in address book who does not have an active task.
+ */
+public class FindFreePersonCommand extends Command {
+
+ public static final String COMMAND_WORD = "findfree";
+
+ public static final String MESSAGE_SUCCESS = "Listed all persons without an active task";
+ private final PersonHasNoTaskPredicate predicate = new PersonHasNoTaskPredicate();
+
+ public FindFreePersonCommand() {
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(new PersonHasNoTaskPredicate());
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ return other instanceof FindFreePersonCommand;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindTaskCommand.java b/src/main/java/seedu/address/logic/commands/FindTaskCommand.java
new file mode 100644
index 00000000000..5567c7e74c6
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindTaskCommand.java
@@ -0,0 +1,57 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.TaskContainsKeywordsPredicate;
+
+/**
+ * Finds and lists persons in address book whose task name contains any of the argument keywords.
+ * Keyword matching is case-insensitive.
+ */
+public class FindTaskCommand extends Command {
+ public static final String COMMAND_WORD = "findtask";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds person in charge of searched task. "
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " create project report";
+
+ private final TaskContainsKeywordsPredicate predicate;
+
+ public FindTaskCommand(TaskContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindTaskCommand)) {
+ return false;
+ }
+
+ FindTaskCommand otherFindTaskCommand = (FindTaskCommand) other;
+ return predicate.equals(otherFindTaskCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..f0ef78dddde 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -1,5 +1,6 @@
package seedu.address.logic.commands;
+import seedu.address.logic.CommandHistory;
import seedu.address.model.Model;
/**
@@ -15,7 +16,7 @@ public class HelpCommand extends Command {
public static final String SHOWING_HELP_MESSAGE = "Opened help window.";
@Override
- public CommandResult execute(Model model) {
+ public CommandResult execute(Model model, CommandHistory history) {
return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/HistoryCommand.java b/src/main/java/seedu/address/logic/commands/HistoryCommand.java
new file mode 100644
index 00000000000..a95eb19a9de
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/HistoryCommand.java
@@ -0,0 +1,35 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import seedu.address.logic.CommandHistory;
+import seedu.address.model.Model;
+
+/**
+ * @@author yiwern5-reused
+ * Reused from AB4 https://github.com/se-edu/addressbook-level4/
+ * Lists all the commands entered by user from the start of app launch.
+ */
+public class HistoryCommand extends Command {
+
+ public static final String COMMAND_WORD = "history";
+ public static final String MESSAGE_SUCCESS = "Entered commands (from most recent to earliest):\n%1$s";
+ public static final String MESSAGE_NO_HISTORY = "You have not yet entered any commands.";
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) {
+ requireNonNull(history);
+ ArrayList previousCommands = new ArrayList<>(history.getHistory());
+
+ if (previousCommands.isEmpty()) {
+ return new CommandResult(MESSAGE_NO_HISTORY);
+ }
+
+ Collections.reverse(previousCommands);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, String.join("\n", previousCommands)));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..4950e90194a 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -2,7 +2,9 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+import seedu.address.logic.CommandHistory;
import seedu.address.model.Model;
/**
@@ -16,9 +18,10 @@ public class ListCommand extends Command {
@Override
- public CommandResult execute(Model model) {
+ public CommandResult execute(Model model, CommandHistory history) {
requireNonNull(model);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/MarkTaskCommand.java b/src/main/java/seedu/address/logic/commands/MarkTaskCommand.java
new file mode 100644
index 00000000000..895cc273b0c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/MarkTaskCommand.java
@@ -0,0 +1,92 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_OWNER;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
+
+/**
+ * Mark tasks done by employees
+ */
+public class MarkTaskCommand extends Command {
+
+ public static final String COMMAND_WORD = "mark";
+ public static final String MESSAGE_MARK_TASK_SUCCESS = "Marked %1$s's task %2$s as done";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Mark the task assigned to the identified person as done.\n"
+ + "Parameters: "
+ + PREFIX_TASK + "TASK "
+ + PREFIX_TASK_OWNER + "INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_TASK + "Complete Project Proposal "
+ + PREFIX_TASK_OWNER + "1";
+
+ public static final String MESSAGE_TASK_DOES_NOT_EXIST = "%s has not been assigned this Task. "
+ + "Please select another Task";
+ private final String taskName;
+ private final Index index;
+
+ /**
+ * Mark task of a existing person in the address book as done.
+ * @param taskName
+ * @param index
+ */
+ public MarkTaskCommand(String taskName, Index index) {
+ requireAllNonNull(index, taskName);
+ this.taskName = taskName;
+ this.index = index;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
+ requireNonNull(model);
+ List personList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= personList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person taskOwner = personList.get(index.getZeroBased());
+
+ if (!taskOwner.hasTask(taskName)) {
+ throw new CommandException(String.format(MESSAGE_TASK_DOES_NOT_EXIST, Messages.printName(taskOwner)));
+ }
+ Task task = taskOwner.getTask();
+
+ model.markTask(task);
+ model.commitAddressBook();
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ return new CommandResult(String.format(MESSAGE_MARK_TASK_SUCCESS,
+ Messages.printName(taskOwner), Messages.printTask(task)));
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof MarkTaskCommand)) {
+ return false;
+ }
+
+ MarkTaskCommand otherMarkTaskCommand = (MarkTaskCommand) other;
+ return this.index.equals(otherMarkTaskCommand.index)
+ && this.taskName.equals(otherMarkTaskCommand.taskName);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ReassignTaskCommand.java b/src/main/java/seedu/address/logic/commands/ReassignTaskCommand.java
new file mode 100644
index 00000000000..93979d39595
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ReassignTaskCommand.java
@@ -0,0 +1,99 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FROM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TO;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
+
+/**
+ * Reassigns task to another person
+ */
+public class ReassignTaskCommand extends Command {
+
+ public static final String COMMAND_WORD = "reassign";
+
+ public static final String MESSAGE_REASSIGN_TASK_SUCCESS = "Reassigned task %1$s from %2$s to %3$s successfully";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Reassigns a task to a person identified by index number.\n"
+ + "Parameters: "
+ + PREFIX_FROM + "INDEX (must be a positive integer) "
+ + PREFIX_TO + "INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_FROM + "2 "
+ + PREFIX_TO + "1";
+ public static final String MESSAGE_PERSON_IS_BUSY = "A task has already been assigned for %1$s. "
+ + "Please select another person.";
+ public static final String MESSAGE_TASK_DOES_NOT_EXIST = "%s has not been assigned a task. "
+ + "Please select another Task";
+ private final Index fromIndex;
+ private final Index toIndex;
+
+ /**
+ * Reassigns a task from one person to another.
+ * @param fromIndex
+ * @param toIndex
+ */
+ public ReassignTaskCommand(Index fromIndex, Index toIndex) {
+ requireAllNonNull(fromIndex, toIndex);
+ this.fromIndex = fromIndex;
+ this.toIndex = toIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory commandHistory) throws CommandException {
+ requireNonNull(model);
+ List personList = model.getFilteredPersonList();
+
+ if ((fromIndex.getZeroBased() >= personList.size() || toIndex.getZeroBased() >= personList.size())) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person assignedFrom = personList.get(fromIndex.getZeroBased());
+ Person assignedTo = personList.get(toIndex.getZeroBased());
+
+ if (assignedTo.isBusy()) {
+ throw new CommandException(String.format(MESSAGE_PERSON_IS_BUSY, Messages.printName(assignedTo)));
+ }
+ Task task = assignedFrom.getTask();
+ if (task == null) {
+ throw new CommandException(String.format(MESSAGE_TASK_DOES_NOT_EXIST, Messages.printName(assignedFrom)));
+ }
+
+ model.reassignTask(task, assignedFrom, assignedTo);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ model.commitAddressBook();
+
+ return new CommandResult(String.format(MESSAGE_REASSIGN_TASK_SUCCESS,
+ Messages.printTask(task), Messages.printName(assignedFrom), Messages.printName(assignedTo)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ReassignTaskCommand)) {
+ return false;
+ }
+
+ ReassignTaskCommand otherReassignCommand = (ReassignTaskCommand) other;
+ return fromIndex.equals(otherReassignCommand.fromIndex)
+ && toIndex.equals(otherReassignCommand.toIndex);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/RedoCommand.java b/src/main/java/seedu/address/logic/commands/RedoCommand.java
new file mode 100644
index 00000000000..00276649815
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/RedoCommand.java
@@ -0,0 +1,35 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+
+/**
+ * @@author yiwern5-reused
+ * Reused from AB4 https://github.com/se-edu/addressbook-level4/
+ * Reverts the {@code model}'s address book to its previously undone state.
+ */
+public class RedoCommand extends Command {
+
+ public static final String COMMAND_WORD = "redo";
+ public static final String MESSAGE_SUCCESS = "Redo success!";
+ public static final String MESSAGE_FAILURE = "No more commands to redo!";
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
+ requireNonNull(model);
+
+ if (!model.canRedoAddressBook()) {
+ throw new CommandException(MESSAGE_FAILURE);
+ }
+
+ model.redoAddressBook();
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/UndoCommand.java b/src/main/java/seedu/address/logic/commands/UndoCommand.java
new file mode 100644
index 00000000000..19126caeb64
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/UndoCommand.java
@@ -0,0 +1,35 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS;
+
+import seedu.address.logic.CommandHistory;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+
+/**
+ * @@author yiwern5-reused
+ * Reused from AB4 https://github.com/se-edu/addressbook-level4/
+ * Reverts the {@code model}'s address book to its previous state.
+ */
+public class UndoCommand extends Command {
+
+ public static final String COMMAND_WORD = "undo";
+ public static final String MESSAGE_SUCCESS = "Undo success!";
+ public static final String MESSAGE_FAILURE = "No more commands to undo!";
+
+ @Override
+ public CommandResult execute(Model model, CommandHistory history) throws CommandException {
+ requireNonNull(model);
+
+ if (!model.canUndoAddressBook()) {
+ throw new CommandException(MESSAGE_FAILURE);
+ }
+
+ model.undoAddressBook();
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 4ff1a97ed77..0bc9eb70c97 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -1,11 +1,6 @@
package seedu.address.logic.parser;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import java.util.Set;
import java.util.stream.Stream;
@@ -13,6 +8,9 @@
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Comment;
+import seedu.address.model.person.Department;
+import seedu.address.model.person.Efficiency;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
@@ -31,21 +29,27 @@ public class AddCommandParser implements Parser {
*/
public AddCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, CliSyntax.PREFIX_NAME, CliSyntax.PREFIX_PHONE, CliSyntax.PREFIX_EMAIL,
+ CliSyntax.PREFIX_ADDRESS, CliSyntax.PREFIX_DEPARTMENT, CliSyntax.PREFIX_TAG,
+ CliSyntax.PREFIX_EFFICIENCY);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
+ if (!arePrefixesPresent(argMultimap, CliSyntax.PREFIX_NAME, CliSyntax.PREFIX_ADDRESS, CliSyntax.PREFIX_PHONE,
+ CliSyntax.PREFIX_EMAIL, CliSyntax.PREFIX_DEPARTMENT, CliSyntax.PREFIX_EFFICIENCY)
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
- Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
- Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
- Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
- Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
+ argMultimap.verifyNoDuplicatePrefixesFor(CliSyntax.PREFIX_NAME, CliSyntax.PREFIX_PHONE, CliSyntax.PREFIX_EMAIL,
+ CliSyntax.PREFIX_ADDRESS, CliSyntax.PREFIX_DEPARTMENT, CliSyntax.PREFIX_EFFICIENCY);
+ Name name = ParserUtil.parseName(argMultimap.getValue(CliSyntax.PREFIX_NAME).get());
+ Phone phone = ParserUtil.parsePhone(argMultimap.getValue(CliSyntax.PREFIX_PHONE).get());
+ Email email = ParserUtil.parseEmail(argMultimap.getValue(CliSyntax.PREFIX_EMAIL).get());
+ Address address = ParserUtil.parseAddress(argMultimap.getValue(CliSyntax.PREFIX_ADDRESS).get());
+ Department department = ParserUtil.parseDepartment(argMultimap.getValue(CliSyntax.PREFIX_DEPARTMENT).get());
+ Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(CliSyntax.PREFIX_TAG));
+ Efficiency efficiency = ParserUtil.parseEfficiency(argMultimap.getValue(CliSyntax.PREFIX_EFFICIENCY).get());
+ Comment comment = new Comment("");
+ Person person = new Person(name, phone, email, address, department, tagList, efficiency, comment);
return new AddCommand(person);
}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
index 3149ee07e0b..3ad98941429 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -9,14 +9,26 @@
import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AssignTaskCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommentCommand;
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.EditCommand;
+import seedu.address.logic.commands.EditDeadlineCommand;
import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FilterCommand;
+import seedu.address.logic.commands.FilterEfficiencyCommand;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindFreePersonCommand;
+import seedu.address.logic.commands.FindTaskCommand;
import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.HistoryCommand;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.MarkTaskCommand;
+import seedu.address.logic.commands.ReassignTaskCommand;
+import seedu.address.logic.commands.RedoCommand;
+import seedu.address.logic.commands.UndoCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
@@ -56,6 +68,9 @@ public Command parseCommand(String userInput) throws ParseException {
case AddCommand.COMMAND_WORD:
return new AddCommandParser().parse(arguments);
+ case AssignTaskCommand.COMMAND_WORD:
+ return new AssignTaskCommandParser().parse(arguments);
+
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
@@ -71,16 +86,48 @@ public Command parseCommand(String userInput) throws ParseException {
case ListCommand.COMMAND_WORD:
return new ListCommand();
+ case HistoryCommand.COMMAND_WORD:
+ return new HistoryCommand();
+
case ExitCommand.COMMAND_WORD:
return new ExitCommand();
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case FilterCommand.COMMAND_WORD:
+ return new FilterCommandParser().parse(arguments);
+
+ case MarkTaskCommand.COMMAND_WORD:
+ return new MarkTaskCommandParser().parse(arguments);
+
+ case UndoCommand.COMMAND_WORD:
+ return new UndoCommand();
+
+ case RedoCommand.COMMAND_WORD:
+ return new RedoCommand();
+
+ case FilterEfficiencyCommand.COMMAND_WORD:
+ return new FilterEfficiencyCommandParser().parse(arguments);
+
+ case ReassignTaskCommand.COMMAND_WORD:
+ return new ReassignTaskCommandParser().parse(arguments);
+
+ case EditDeadlineCommand.COMMAND_WORD:
+ return new EditDeadlineCommandParser().parse(arguments);
+
+ case FindTaskCommand.COMMAND_WORD:
+ return new FindTaskCommandParser().parse(arguments);
+
+ case FindFreePersonCommand.COMMAND_WORD:
+ return new FindFreePersonCommand();
+
+ case CommentCommand.COMMAND_WORD:
+ return new CommentCommandParser().parse(arguments);
+
default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/AssignTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/AssignTaskCommandParser.java
new file mode 100644
index 00000000000..2364841a4b2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AssignTaskCommandParser.java
@@ -0,0 +1,41 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEADLINE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TO;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AssignTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.task.Deadline;
+import seedu.address.model.task.Task;
+
+/**
+ * Parses input arguments and creates a new AssignTaskCommand object
+ */
+public class AssignTaskCommandParser implements Parser {
+
+ @Override
+ public AssignTaskCommand parse(String userInput) throws ParseException {
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_TASK, PREFIX_DEADLINE, PREFIX_TO);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_TASK, PREFIX_DEADLINE, PREFIX_TO)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AssignTaskCommand.MESSAGE_USAGE));
+ }
+
+ String taskName = ParserTaskUtil.parseTaskName(argMultimap.getValue(PREFIX_TASK).get());
+ Deadline deadline = ParserTaskUtil.parseDeadline(argMultimap.getValue(PREFIX_DEADLINE).get());
+ Index personIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_TO).get());
+
+ Task task = new Task(taskName, deadline);
+ return new AssignTaskCommand(task, personIndex);
+ }
+
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
index 75b1a9bf119..a7a430e10de 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -10,6 +10,15 @@ public class CliSyntax {
public static final Prefix PREFIX_PHONE = new Prefix("p/");
public static final Prefix PREFIX_EMAIL = new Prefix("e/");
public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
+ public static final Prefix PREFIX_DEPARTMENT = new Prefix("d/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
+ public static final Prefix PREFIX_TASK = new Prefix("task/");
+ public static final Prefix PREFIX_DEADLINE = new Prefix("by/");
+ public static final Prefix PREFIX_TO = new Prefix("to/");
+ public static final Prefix PREFIX_FROM = new Prefix("from/");
+ public static final Prefix PREFIX_EFFICIENCY = new Prefix("eff/");
+ public static final Prefix PREFIX_TASK_OWNER = new Prefix("o/");
+
+ public static final Prefix PREFIX_COMMENT = new Prefix("c/");
}
diff --git a/src/main/java/seedu/address/logic/parser/CommentCommandParser.java b/src/main/java/seedu/address/logic/parser/CommentCommandParser.java
new file mode 100644
index 00000000000..8e8f5114a48
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/CommentCommandParser.java
@@ -0,0 +1,37 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMMENT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.logic.commands.CommentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Comment;
+
+/**
+ * Parses input arguments and creates a new {@code CommentCommand} object
+ */
+public class CommentCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the {@code CommentCommand}
+ * and returns a {@code CommentCommand} object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public CommentCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_COMMENT);
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CommentCommand.MESSAGE_USAGE), ive);
+ }
+
+ Comment comment = new Comment(argMultimap.getValue(PREFIX_COMMENT).orElse(""));
+
+ return new CommentCommand(index, comment);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 46b3309a78b..883e9d4b774 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -3,6 +3,7 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEPARTMENT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
@@ -32,7 +33,8 @@ public class EditCommandParser implements Parser {
public EditCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DEPARTMENT, PREFIX_TAG);
Index index;
@@ -42,7 +44,8 @@ public EditCommand parse(String args) throws ParseException {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_ADDRESS, PREFIX_DEPARTMENT);
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
@@ -58,6 +61,10 @@ public EditCommand parse(String args) throws ParseException {
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
}
+ if (argMultimap.getValue(PREFIX_DEPARTMENT).isPresent()) {
+ editPersonDescriptor.setDepartment(ParserUtil.parseDepartment(
+ argMultimap.getValue(PREFIX_DEPARTMENT).get()));
+ }
parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
if (!editPersonDescriptor.isAnyFieldEdited()) {
diff --git a/src/main/java/seedu/address/logic/parser/EditDeadlineCommandParser.java b/src/main/java/seedu/address/logic/parser/EditDeadlineCommandParser.java
new file mode 100644
index 00000000000..aca4898809e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/EditDeadlineCommandParser.java
@@ -0,0 +1,52 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEADLINE;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.EditDeadlineCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.task.Deadline;
+
+/**
+ * Parses input arguments and creates a new EditDeadlineTaskCommand object
+ */
+public class EditDeadlineCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditDeadlineCommand
+ * and returns an EditDeadlineCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ @Override
+ public EditDeadlineCommand parse(String userInput) throws ParseException {
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_DEADLINE);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String
+ .format(MESSAGE_INVALID_COMMAND_FORMAT, EditDeadlineCommand.MESSAGE_USAGE), pe);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_DEADLINE)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditDeadlineCommand.MESSAGE_USAGE));
+ }
+
+ Deadline deadline = ParserTaskUtil.parseDeadline(argMultimap.getValue(PREFIX_DEADLINE).get());
+
+ return new EditDeadlineCommand(index, deadline);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FilterCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterCommandParser.java
new file mode 100644
index 00000000000..b40b958e545
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FilterCommandParser.java
@@ -0,0 +1,33 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.address.logic.commands.FilterCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.PersonContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FilterCommand object
+ */
+public class FilterCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterCommand
+ * and returns a FilterCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FilterCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
+ }
+
+ String[] nameKeywords = trimmedArgs.split("\\s+");
+
+ return new FilterCommand(new PersonContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/FilterEfficiencyCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterEfficiencyCommandParser.java
new file mode 100644
index 00000000000..692c32618e7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FilterEfficiencyCommandParser.java
@@ -0,0 +1,44 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.FilterEfficiencyCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Efficiency;
+import seedu.address.model.person.PersonLessThanEfficiencyPredicate;
+
+
+/**
+ * Parses input arguments and creates a new FilterEfficiencyCommand object
+ */
+public class FilterEfficiencyCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterEfficiencyCommand
+ * and returns a FilterEfficiencyCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FilterEfficiencyCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+
+ //check if it is an empty input
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterEfficiencyCommand.MESSAGE_USAGE));
+ }
+
+ try {
+ //check if the input is an integer
+ int threshold = Integer.parseInt(trimmedArgs);
+
+ //check if the input is in the range (0-100)
+ if (!Efficiency.isValidEfficiency(trimmedArgs)) {
+ throw new ParseException(Efficiency.MESSAGE_CONSTRAINTS);
+ }
+ return new FilterEfficiencyCommand(new PersonLessThanEfficiencyPredicate(threshold));
+
+ } catch (NumberFormatException e) {
+ throw new ParseException("The input efficiency should be an integer.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/FindTaskCommandParser.java
new file mode 100644
index 00000000000..188624b7298
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindTaskCommandParser.java
@@ -0,0 +1,33 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.address.logic.commands.FindTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.TaskContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindTaskCommand object
+ */
+public class FindTaskCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindCommand
+ * and returns a FindCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindTaskCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindTaskCommand.MESSAGE_USAGE));
+ }
+
+ String[] taskNameKeywords = trimmedArgs.split("\\s+");
+
+ return new FindTaskCommand(new TaskContainsKeywordsPredicate(Arrays.asList(taskNameKeywords)));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/MarkTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/MarkTaskCommandParser.java
new file mode 100644
index 00000000000..8bb75be714e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/MarkTaskCommandParser.java
@@ -0,0 +1,36 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_OWNER;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.MarkTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new MarkTaskCommand object
+ */
+public class MarkTaskCommandParser implements Parser {
+
+ @Override
+ public MarkTaskCommand parse(String userInput) throws ParseException {
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_TASK, PREFIX_TASK_OWNER);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_TASK, PREFIX_TASK_OWNER)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkTaskCommand.MESSAGE_USAGE));
+ }
+
+ String taskName = ParserTaskUtil.parseTaskName(argMultimap.getValue(PREFIX_TASK).get());
+ Index personIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_TASK_OWNER).get());
+
+ return new MarkTaskCommand(taskName, personIndex);
+ }
+
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserTaskUtil.java b/src/main/java/seedu/address/logic/parser/ParserTaskUtil.java
new file mode 100644
index 00000000000..1c051168889
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ParserTaskUtil.java
@@ -0,0 +1,47 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.task.Deadline;
+
+/**
+ * Contains utility methods used for parsing strings in the various *Parser classes.
+ */
+
+public class ParserTaskUtil {
+
+ public static final String MESSAGE_INVALID_DEADLINE = "Invalid date/time format. Please use dd-MM-yyyy HHmm";
+
+ /**
+ * Parses a {@code String taskName} into a {@code String}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static String parseTaskName(String taskName) {
+ requireNonNull(taskName);
+ String trimmedTaskName = taskName.trim();
+ return trimmedTaskName;
+ }
+
+ /**
+ * Parses a {@code String deadline} into a {@code Deadline}.
+ * Leading and trailing whitespaces will be trimmed before parsing.
+ *
+ * @throws ParseException if the given {@code deadline} is invalid.
+ */
+ public static Deadline parseDeadline(String deadline) throws ParseException {
+ requireNonNull(deadline);
+ String trimmedDeadline = deadline.trim();
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HHmm");
+ try {
+ LocalDateTime parsedDeadline = LocalDateTime.parse(trimmedDeadline, formatter);
+ return new Deadline(parsedDeadline);
+ } catch (DateTimeParseException e) {
+ throw new ParseException(MESSAGE_INVALID_DEADLINE);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..a766d5c190d 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -10,6 +10,8 @@
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Department;
+import seedu.address.model.person.Efficiency;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
@@ -80,6 +82,21 @@ public static Address parseAddress(String address) throws ParseException {
return new Address(trimmedAddress);
}
+ /**
+ * Parses a {@code String department} into a {@code Department}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code department} is invalid.
+ */
+ public static Department parseDepartment(String department) throws ParseException {
+ requireNonNull(department);
+ String trimmedDepartment = department.trim();
+ if (!Department.isValidDepartment(trimmedDepartment)) {
+ throw new ParseException(Department.MESSAGE_CONSTRAINTS);
+ }
+ return new Department(trimmedDepartment);
+ }
+
/**
* Parses a {@code String email} into an {@code Email}.
* Leading and trailing whitespaces will be trimmed.
@@ -121,4 +138,19 @@ public static Set parseTags(Collection tags) throws ParseException
}
return tagSet;
}
+
+ /**
+ * Parses a {@code String efficiency} into a {@code Efficiency}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code efficiency} is invalid.
+ */
+ public static Efficiency parseEfficiency(String efficiency) throws ParseException {
+ requireNonNull(efficiency);
+ String trimmedEfficiency = efficiency.trim();
+ if (!Efficiency.isValidEfficiency(trimmedEfficiency)) {
+ throw new ParseException(Efficiency.MESSAGE_CONSTRAINTS);
+ }
+ return new Efficiency(trimmedEfficiency);
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/ReassignTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/ReassignTaskCommandParser.java
new file mode 100644
index 00000000000..0206f5fdf87
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ReassignTaskCommandParser.java
@@ -0,0 +1,37 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_FROM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TO;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.ReassignTaskCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parse input arguments and create a new ReassignTaskCommand object.
+ */
+public class ReassignTaskCommandParser implements Parser {
+
+ @Override
+ public ReassignTaskCommand parse(String userInput) throws ParseException {
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_FROM, PREFIX_TO);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_FROM, PREFIX_TO)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ReassignTaskCommand.MESSAGE_USAGE));
+ }
+ Index fromIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_FROM).get());
+ Index toIndex = ParserUtil.parseIndex(argMultimap.getValue(PREFIX_TO).get());
+
+ return new ReassignTaskCommand(fromIndex, toIndex);
+
+ }
+
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
index 73397161e84..fc75fc80c52 100644
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ b/src/main/java/seedu/address/model/AddressBook.java
@@ -4,10 +4,15 @@
import java.util.List;
+import javafx.beans.InvalidationListener;
import javafx.collections.ObservableList;
+import seedu.address.commons.util.InvalidationListenerManager;
import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.UniquePersonList;
+import seedu.address.model.task.Task;
+import seedu.address.model.task.UniqueTaskList;
/**
* Wraps all data at the address-book level
@@ -16,6 +21,9 @@
public class AddressBook implements ReadOnlyAddressBook {
private final UniquePersonList persons;
+ private final UniqueTaskList tasks;
+ private final InvalidationListenerManager invalidationListenerManager = new InvalidationListenerManager();
+
/*
* The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
@@ -24,12 +32,19 @@ public class AddressBook implements ReadOnlyAddressBook {
* Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
* among constructors.
*/
- {
+ // {
+ // persons = new UniquePersonList();
+ // tasks = new UniqueTaskList();
+ // }
+
+ /**
+ * Constructs the {@code AddressBook}
+ */
+ public AddressBook() {
persons = new UniquePersonList();
+ tasks = new UniqueTaskList();
}
- public AddressBook() {}
-
/**
* Creates an AddressBook using the Persons in the {@code toBeCopied}
*/
@@ -46,8 +61,17 @@ public AddressBook(ReadOnlyAddressBook toBeCopied) {
*/
public void setPersons(List persons) {
this.persons.setPersons(persons);
+ indicateModified();
}
+ /**
+ * Replaces the contents of the task list with {@code tasks}.
+ * {@code tasks} must not contain duplicate tasks.
+ */
+ public void setTasks(List tasks) {
+ this.tasks.setTasks(tasks);
+ indicateModified();
+ }
/**
* Resets the existing data of this {@code AddressBook} with {@code newData}.
*/
@@ -55,6 +79,7 @@ public void resetData(ReadOnlyAddressBook newData) {
requireNonNull(newData);
setPersons(newData.getPersonList());
+ setTasks(newData.getTaskList());
}
//// person-level operations
@@ -73,6 +98,7 @@ public boolean hasPerson(Person person) {
*/
public void addPerson(Person p) {
persons.add(p);
+ indicateModified();
}
/**
@@ -84,6 +110,7 @@ public void setPerson(Person target, Person editedPerson) {
requireNonNull(editedPerson);
persons.setPerson(target, editedPerson);
+ indicateModified();
}
/**
@@ -92,6 +119,117 @@ public void setPerson(Person target, Person editedPerson) {
*/
public void removePerson(Person key) {
persons.remove(key);
+ Task task = key.getTask();
+ if (task != null) {
+ tasks.remove(key.getTask());
+ }
+ indicateModified();
+ }
+
+ /**
+ * Gets {@code Person} from {@code AddressBook} using {@code Name}
+ * {@code name} of the person
+ */
+ public Person getPerson(Name name) {
+ requireNonNull(name);
+
+ return persons.getPerson(name);
+ }
+
+ //// task-level operations
+
+ /**
+ * Returns true if a task with the same identity as {@code task} exists in the address book.
+ */
+ public boolean hasTask(Task task) {
+ requireNonNull(task);
+ return tasks.contains(task);
+ }
+
+ /**
+ * Adds a task to the address book.
+ * The task must not already exist in the address book.
+ */
+ public void addTask(Task t) {
+ tasks.add(t);
+ indicateModified();
+ }
+
+ /**
+ * Replaces the given task {@code target} in the list with {@code editedTask}.
+ * {@code target} must exist in the address book.
+ * The task identity of {@code editedTask} must not be the same as another existing task in the address book.
+ */
+ public void setTask(Task target, Task editedTask) {
+ requireNonNull(editedTask);
+
+ tasks.setTask(target, editedTask);
+ indicateModified();
+ }
+
+ /**
+ * Assign a task to a person by adding task to the address book,
+ * setting the person's task field and adding the task's personInCharge.
+ */
+ public void assignTask(Task task, Person pic) {
+ Person editedPerson = new Person(pic.getName(), pic.getPhone(), pic.getEmail(),
+ pic.getAddress(), pic.getDepartment(), pic.getTags(), pic.getEfficiency(), pic.getComment());
+
+ addTask(task);
+ task.setPersonInCharge(editedPerson);
+ editedPerson.setTask(task);
+
+ setPerson(pic, editedPerson);
+ indicateModified();
+ }
+
+ /**
+ * Reassigns a task from one person to another person.
+ */
+ public void reassignTask(Task task, Person oldPic, Person pic) {
+ Person addTaskTo = new Person(pic.getName(), pic.getPhone(), pic.getEmail(),
+ pic.getAddress(), pic.getDepartment(), pic.getTags(),
+ pic.getEfficiency(), pic.getComment());
+ Person removeTaskFrom = new Person(oldPic.getName(), oldPic.getPhone(), oldPic.getEmail(),
+ oldPic.getAddress(), oldPic.getDepartment(), oldPic.getTags(),
+ oldPic.getEfficiency(), oldPic.getComment());
+ setPerson(oldPic, removeTaskFrom);
+ Task editedTask = task.changePersonInCharge(pic);
+ setTask(task, editedTask);
+ addTaskTo.setTask(editedTask);
+ setPerson(pic, addTaskTo);
+ indicateModified();
+ }
+
+ /**
+ * Marks an assigned task as done.
+ */
+ public void markTask(Task task) {
+ Person target = task.getPersonInCharge();
+ Task editedTask = task.markDone();
+ Person editedPerson = new Person(target.getName(), target.getPhone(), target.getEmail(),
+ target.getAddress(), target.getDepartment(), target.getTags(),
+ target.updateEfficiency(), target.getComment());
+ setPerson(target, editedPerson);
+ setTask(task, editedTask);
+ indicateModified();
+ }
+
+ @Override
+ public void addListener(InvalidationListener listener) {
+ invalidationListenerManager.addListener(listener);
+ }
+
+ @Override
+ public void removeListener(InvalidationListener listener) {
+ invalidationListenerManager.removeListener(listener);
+ }
+
+ /**
+ * Notifies listeners that the address book has been modified.
+ */
+ protected void indicateModified() {
+ invalidationListenerManager.callListeners(this);
}
//// util methods
@@ -100,6 +238,7 @@ public void removePerson(Person key) {
public String toString() {
return new ToStringBuilder(this)
.add("persons", persons)
+ .add("tasks", tasks)
.toString();
}
@@ -108,6 +247,11 @@ public ObservableList getPersonList() {
return persons.asUnmodifiableObservableList();
}
+ @Override
+ public ObservableList getTaskList() {
+ return tasks.asUnmodifiableObservableList();
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -120,11 +264,12 @@ public boolean equals(Object other) {
}
AddressBook otherAddressBook = (AddressBook) other;
- return persons.equals(otherAddressBook.persons);
+ return persons.equals(otherAddressBook.persons) && tasks.equals(otherAddressBook.tasks);
}
@Override
public int hashCode() {
return persons.hashCode();
}
+
}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..05553bedca9 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -6,6 +6,7 @@
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
/**
* The API of the Model component.
@@ -14,6 +15,9 @@ public interface Model {
/** {@code Predicate} that always evaluate to true */
Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
+ /** {@code Predicate} that always evaluate to true */
+ Predicate PREDICATE_SHOW_ALL_TASKS = unused -> true;
+
/**
* Replaces user prefs data with the data in {@code userPrefs}.
*/
@@ -79,9 +83,75 @@ public interface Model {
/** Returns an unmodifiable view of the filtered person list */
ObservableList getFilteredPersonList();
+ ObservableList getFilteredTaskList();
+
/**
* Updates the filter of the filtered person list to filter by the given {@code predicate}.
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPersonList(Predicate predicate);
+
+ /**
+ * Returns true if a task with the same identity as {@code task} exists in the address book.
+ */
+ boolean hasTask(Task task);
+
+ /**
+ * Adds the given task.
+ * {@code task} must not already exist in the address book.
+ */
+ void addTask(Task task);
+
+ /**
+ * Replaces the given person {@code target} with {@code editedPerson}.
+ * {@code target} must exist in the address book.
+ * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
+ */
+ void setTask(Task target, Task editedTask);
+
+ /**
+ * Assigns specific task to a person
+ */
+ void assignTask(Task task, Person person);
+
+ /**
+ * Reassigns task from one person to another.
+ */
+ void reassignTask(Task task, Person assignedFrom, Person assignedTo);
+
+ /**
+ * Marks an assigned task as done.
+ */
+ void markTask(Task task);
+
+ /**
+ * Updates the filter of the filtered task list to filter by the given {@code predicate}.
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredTaskList(Predicate predicate);
+
+ /**
+ * Returns true if the model has previous address book states to restore.
+ */
+ boolean canUndoAddressBook();
+
+ /**
+ * Returns true if the model has undone address book states to restore.
+ */
+ boolean canRedoAddressBook();
+
+ /**
+ * Restores the model's address book to its previous state.
+ */
+ void undoAddressBook();
+
+ /**
+ * Restores the model's address book to its previously undone state.
+ */
+ void redoAddressBook();
+
+ /**
+ * Saves the current address book state for undo/redo.
+ */
+ void commitAddressBook();
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 57bc563fde6..fd06b0d60e1 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -12,6 +12,7 @@
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
/**
* Represents the in-memory model of the address book data.
@@ -19,21 +20,24 @@
public class ModelManager implements Model {
private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
- private final AddressBook addressBook;
+ private final VersionedAddressBook versionedAddressBook;
private final UserPrefs userPrefs;
private final FilteredList filteredPersons;
+ private final FilteredList filteredTasks;
/**
* Initializes a ModelManager with the given addressBook and userPrefs.
*/
public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
+ super();
requireAllNonNull(addressBook, userPrefs);
logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
- this.addressBook = new AddressBook(addressBook);
+ this.versionedAddressBook = new VersionedAddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ filteredPersons = new FilteredList<>(this.versionedAddressBook.getPersonList());
+ filteredTasks = new FilteredList<>(this.versionedAddressBook.getTaskList());
}
public ModelManager() {
@@ -79,28 +83,28 @@ public void setAddressBookFilePath(Path addressBookFilePath) {
@Override
public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
+ this.versionedAddressBook.resetData(addressBook);
}
@Override
public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
+ return versionedAddressBook;
}
@Override
public boolean hasPerson(Person person) {
requireNonNull(person);
- return addressBook.hasPerson(person);
+ return versionedAddressBook.hasPerson(person);
}
@Override
public void deletePerson(Person target) {
- addressBook.removePerson(target);
+ versionedAddressBook.removePerson(target);
}
@Override
public void addPerson(Person person) {
- addressBook.addPerson(person);
+ versionedAddressBook.addPerson(person);
updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
}
@@ -108,7 +112,49 @@ public void addPerson(Person person) {
public void setPerson(Person target, Person editedPerson) {
requireAllNonNull(target, editedPerson);
- addressBook.setPerson(target, editedPerson);
+ versionedAddressBook.setPerson(target, editedPerson);
+ }
+
+ @Override
+ public boolean hasTask(Task task) {
+ requireNonNull(task);
+ return versionedAddressBook.hasTask(task);
+ }
+
+ @Override
+ public void addTask(Task task) {
+ versionedAddressBook.addTask(task);
+ }
+
+ @Override
+ public void setTask(Task target, Task editedTask) {
+ requireAllNonNull(target, editedTask);
+
+ versionedAddressBook.setTask(target, editedTask);
+ }
+
+ @Override
+ public void assignTask(Task task, Person assignedTo) {
+ requireAllNonNull(task, assignedTo);
+ versionedAddressBook.assignTask(task, assignedTo);
+ }
+
+ @Override
+ public void reassignTask(Task task, Person assignedFrom, Person assignedTo) {
+ requireAllNonNull(task, assignedFrom, assignedTo);
+ versionedAddressBook.reassignTask(task, assignedFrom, assignedTo);
+ }
+
+ @Override
+ public void markTask(Task task) {
+ requireNonNull(task);
+ versionedAddressBook.markTask(task);
+ }
+
+ @Override
+ public void updateFilteredTaskList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredTasks.setPredicate(predicate);
}
//=========== Filtered Person List Accessors =============================================================
@@ -122,12 +168,45 @@ public ObservableList getFilteredPersonList() {
return filteredPersons;
}
+ @Override
+ public ObservableList getFilteredTaskList() {
+ return filteredTasks;
+ }
+
@Override
public void updateFilteredPersonList(Predicate predicate) {
requireNonNull(predicate);
filteredPersons.setPredicate(predicate);
}
+ //=========== Undo/Redo =================================================================================
+
+ @Override
+ public boolean canUndoAddressBook() {
+ return versionedAddressBook.canUndo();
+ }
+
+ @Override
+ public boolean canRedoAddressBook() {
+ return versionedAddressBook.canRedo();
+ }
+
+ @Override
+ public void undoAddressBook() {
+ versionedAddressBook.undo();
+ }
+
+ @Override
+ public void redoAddressBook() {
+ versionedAddressBook.redo();
+ }
+
+ @Override
+ public void commitAddressBook() {
+ versionedAddressBook.commit();
+ }
+
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -140,7 +219,7 @@ public boolean equals(Object other) {
}
ModelManager otherModelManager = (ModelManager) other;
- return addressBook.equals(otherModelManager.addressBook)
+ return versionedAddressBook.equals(otherModelManager.versionedAddressBook)
&& userPrefs.equals(otherModelManager.userPrefs)
&& filteredPersons.equals(otherModelManager.filteredPersons);
}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
index 6ddc2cd9a29..6a5fb4b7866 100644
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
@@ -1,12 +1,14 @@
package seedu.address.model;
+import javafx.beans.Observable;
import javafx.collections.ObservableList;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
/**
* Unmodifiable view of an address book
*/
-public interface ReadOnlyAddressBook {
+public interface ReadOnlyAddressBook extends Observable {
/**
* Returns an unmodifiable view of the persons list.
@@ -14,4 +16,10 @@ public interface ReadOnlyAddressBook {
*/
ObservableList getPersonList();
+ /**
+ * Returns an unmodifiable view of the tasks list.
+ * This list will not contain any duplicate tasks.
+ */
+ ObservableList getTaskList();
+
}
diff --git a/src/main/java/seedu/address/model/VersionedAddressBook.java b/src/main/java/seedu/address/model/VersionedAddressBook.java
new file mode 100644
index 00000000000..44853df2205
--- /dev/null
+++ b/src/main/java/seedu/address/model/VersionedAddressBook.java
@@ -0,0 +1,115 @@
+package seedu.address.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @@author yiwern5-reused
+ * Reused from AB4 https://github.com/se-edu/addressbook-level4/
+ * {@code AddressBook} that keeps track of its own history.
+ */
+public class VersionedAddressBook extends AddressBook {
+
+ private final List addressBookStateList;
+ private int currentStatePointer;
+
+ /**
+ * Constructs the {@code VersionedAddressBook}
+ */
+ public VersionedAddressBook(ReadOnlyAddressBook initialState) {
+ super(initialState);
+
+ addressBookStateList = new ArrayList<>();
+ addressBookStateList.add(new AddressBook(initialState));
+ currentStatePointer = 0;
+ }
+
+ /**
+ * Saves a copy of the current {@code AddressBook} state at the end of the state list.
+ * Undone states are removed from the state list.
+ */
+ public void commit() {
+ removeStatesAfterCurrentPointer();
+ addressBookStateList.add(new AddressBook(this));
+ currentStatePointer++;
+ indicateModified();
+ }
+
+ private void removeStatesAfterCurrentPointer() {
+ addressBookStateList.subList(currentStatePointer + 1, addressBookStateList.size()).clear();
+ }
+
+ /**
+ * Restores the address book to its previous state.
+ */
+ public void undo() {
+ if (!canUndo()) {
+ throw new NoUndoableStateException();
+ }
+ currentStatePointer--;
+ resetData(addressBookStateList.get(currentStatePointer));
+ }
+
+ /**
+ * Restores the address book to its previously undone state.
+ */
+ public void redo() {
+ if (!canRedo()) {
+ throw new NoRedoableStateException();
+ }
+ currentStatePointer++;
+ resetData(addressBookStateList.get(currentStatePointer));
+ }
+
+ /**
+ * Returns true if {@code undo()} has address book states to undo.
+ */
+ public boolean canUndo() {
+ return currentStatePointer > 0;
+ }
+
+ /**
+ * Returns true if {@code redo()} has address book states to redo.
+ */
+ public boolean canRedo() {
+ return currentStatePointer < addressBookStateList.size() - 1;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof VersionedAddressBook)) {
+ return false;
+ }
+
+ VersionedAddressBook otherVersionedAddressBook = (VersionedAddressBook) other;
+
+ // state check
+ return super.equals(otherVersionedAddressBook)
+ && addressBookStateList.equals(otherVersionedAddressBook.addressBookStateList)
+ && currentStatePointer == otherVersionedAddressBook.currentStatePointer;
+ }
+
+ /**
+ * Thrown when trying to {@code undo()} but can't.
+ */
+ public static class NoUndoableStateException extends RuntimeException {
+ private NoUndoableStateException() {
+ super("Current state pointer at start of addressBookState list, unable to undo.");
+ }
+ }
+
+ /**
+ * Thrown when trying to {@code redo()} but can't.
+ */
+ public static class NoRedoableStateException extends RuntimeException {
+ private NoRedoableStateException() {
+ super("Current state pointer at end of addressBookState list, unable to redo.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Comment.java b/src/main/java/seedu/address/model/person/Comment.java
new file mode 100644
index 00000000000..3b191b8b49d
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Comment.java
@@ -0,0 +1,56 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.person.Name.VALIDATION_REGEX;
+
+/**
+ * Represents a Person's comment in the address book.
+ */
+public class Comment {
+
+
+ public final String comment;
+
+ /**
+ * Constructs an {@code comment}.
+ *
+ * @param comment A valid comment.
+ */
+ public Comment(String comment) {
+ requireNonNull(comment);
+ this.comment = comment;
+ }
+
+ /**
+ * Returns true if a given string is a valid comment.
+ */
+ public static boolean isValidComment(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return this.comment;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Comment)) {
+ return false;
+ }
+
+ Comment otherComment = (Comment) other;
+ return comment.equals(otherComment.comment);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.comment.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/Department.java b/src/main/java/seedu/address/model/person/Department.java
new file mode 100644
index 00000000000..573b25cdf35
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Department.java
@@ -0,0 +1,63 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Department in the address book.
+ * Guarantees: immutable; name is valid as declared in {@link #isValidDepartment(String)}
+ */
+public class Department {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Department should only contain alphanumeric characters and spaces, and it should not be blank";
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+
+ public final String department;
+
+ /**
+ * Constructs a {@code Department}.
+ *
+ * @param department A valid department name.
+ */
+ public Department(String department) {
+ requireNonNull(department);
+ checkArgument(isValidDepartment(department), MESSAGE_CONSTRAINTS);
+ this.department = department.toUpperCase();
+ }
+
+ /**
+ * Returns true if a given string is a valid department name.
+ */
+ public static boolean isValidDepartment(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Department)) {
+ return false;
+ }
+
+ Department otherDepartment = (Department) other;
+ return department.equals(otherDepartment.department);
+ }
+
+ @Override
+ public int hashCode() {
+ return department.hashCode();
+ }
+
+ /**
+ * Format state as text for viewing.
+ */
+ public String toString() {
+ return department;
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/Efficiency.java b/src/main/java/seedu/address/model/person/Efficiency.java
new file mode 100644
index 00000000000..17a3d8436cb
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Efficiency.java
@@ -0,0 +1,82 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Person's efficiency in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidEfficiency(String)}
+ */
+public class Efficiency {
+ public static final String MESSAGE_CONSTRAINTS =
+ "Efficiency should be an integer in the range 0 to 100";
+ public static final String VALIDATION_REGEX = "\\b(\\d{1,2}|100)\\b";
+ public final String value;
+
+ /**
+ * Constructs a {@code Efficiency}.
+ *
+ * @param efficiency A valid efficiency
+ */
+ public Efficiency(String efficiency) {
+ requireNonNull(efficiency);
+ checkArgument(isValidEfficiency(efficiency), MESSAGE_CONSTRAINTS);
+ value = efficiency;
+ }
+
+ /**
+ * Returns true if a given string is a valid efficiency.
+ */
+ public static boolean isValidEfficiency(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Increases the efficiency by the specified amount.
+ *
+ * @param amount The amount to increase the efficiency by.
+ */
+ public Efficiency increase(int amount) {
+ int currentValue = Integer.parseInt(this.value);
+ int newValue = currentValue + amount;
+ newValue = Math.min(newValue, 100);
+ return new Efficiency(String.valueOf(newValue));
+ }
+
+ /**
+ * Decreases the efficiency by the double specified amount.
+ *
+ * @param amount The amount to decrease the efficiency by.
+ */
+ public Efficiency decrease(int amount) {
+ int currentValue = Integer.parseInt(this.value);
+ int newValue = currentValue - (2 * amount);
+ newValue = Math.max(newValue, 0);
+ return new Efficiency(String.valueOf(newValue));
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Efficiency)) {
+ return false;
+ }
+
+ Efficiency otherEfficiency = (Efficiency) other;
+ return value.equals(otherEfficiency.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
index 62d19be2977..f39ed0763fc 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
@@ -3,7 +3,7 @@
import java.util.List;
import java.util.function.Predicate;
-import seedu.address.commons.util.StringUtil;
+//import seedu.address.commons.util.StringUtil;
import seedu.address.commons.util.ToStringBuilder;
/**
@@ -19,7 +19,8 @@ public NameContainsKeywordsPredicate(List keywords) {
@Override
public boolean test(Person person) {
return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ .anyMatch(keyword -> person.getName().fullName.toLowerCase().replaceAll("\\s", "")
+ .contains(keyword.toLowerCase()));
}
@Override
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index abe8c46b535..59d5f7e1c52 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -2,6 +2,8 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
@@ -9,6 +11,7 @@
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.tag.Tag;
+import seedu.address.model.task.Task;
/**
* Represents a Person in the address book.
@@ -23,18 +26,27 @@ public class Person {
// Data fields
private final Address address;
+ private final Department department;
private final Set tags = new HashSet<>();
+ private transient Task task = null;
+ private Efficiency efficiency;
+ private final Comment comment;
/**
* Every field must be present and not null.
*/
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
+ public Person(Name name, Phone phone, Email email, Address address, Department department, Set tags,
+ Efficiency efficiency, Comment comment) {
+
+ requireAllNonNull(name, phone, email, address, department, tags, comment);
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
+ this.department = department;
this.tags.addAll(tags);
+ this.efficiency = efficiency;
+ this.comment = comment;
}
public Name getName() {
@@ -53,6 +65,61 @@ public Address getAddress() {
return address;
}
+ public Department getDepartment() {
+ return department;
+ }
+ public Efficiency getEfficiency() {
+ return efficiency;
+ }
+
+ public Comment getComment() {
+ return comment;
+ }
+
+ public Task getTask() {
+ return task;
+ }
+
+ /**
+ * Sets a {@code Task} to person
+ * @param task Task to be assigned to this person.
+ */
+ public void setTask(Task task) {
+ this.task = task;
+ }
+
+ /**
+ * Remove person's {@code Task}
+ */
+ public void removeTask() {
+ this.task = null;
+ }
+
+ /**
+ * Check if the person is busy
+ * @return boolean
+ */
+ public boolean isBusy() {
+ if (this.task == null) {
+ return false;
+ } else {
+ return !this.task.isDone();
+ }
+ }
+
+ /**
+ * Check if person has specified task assigned
+ * @param taskName
+ * @return boolean
+ */
+ public boolean hasTask(String taskName) {
+ if (this.task == null) {
+ return false;
+ } else {
+ return this.task.getTaskTitle().equals(taskName);
+ }
+ }
+
/**
* Returns an immutable tag set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
@@ -61,6 +128,27 @@ public Set getTags() {
return Collections.unmodifiableSet(tags);
}
+ /**
+ * Updates the efficiency value based on when the task was completed,
+ * +1 on the deadline day itself, +N for N days early and -2N for N days late.
+ */
+ public Efficiency updateEfficiency() {
+ if (this.task == null) {
+ return this.efficiency;
+ }
+
+ LocalDateTime deadlineDateTime = this.task.getDeadline().getDateTime();
+ int daysBetween = (int) ChronoUnit.DAYS.between(LocalDateTime.now(), deadlineDateTime);
+
+ if (daysBetween == 0) {
+ return this.efficiency.increase(1);
+ } else if (daysBetween > 0) {
+ return this.efficiency.increase(daysBetween);
+ } else {
+ return this.efficiency.decrease(-daysBetween);
+ }
+ }
+
/**
* Returns true if both persons have the same name.
* This defines a weaker notion of equality between two persons.
@@ -100,7 +188,7 @@ public boolean equals(Object other) {
@Override
public int hashCode() {
// use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
+ return Objects.hash(name, phone, email, address, department, tags, comment);
}
@Override
@@ -110,7 +198,9 @@ public String toString() {
.add("phone", phone)
.add("email", email)
.add("address", address)
+ .add("department", department)
.add("tags", tags)
+ .add("comment", comment)
.toString();
}
diff --git a/src/main/java/seedu/address/model/person/PersonContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/PersonContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..0fe95296e60
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonContainsKeywordsPredicate.java
@@ -0,0 +1,45 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
+ */
+public class PersonContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public PersonContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return keywords.stream()
+ .anyMatch(keyword -> person.getDepartment().toString().toLowerCase().replaceAll("\\s", "")
+ .contains(keyword.toLowerCase())
+ || person.getTags().toString().toLowerCase().contains(keyword.toLowerCase()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PersonContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ PersonContainsKeywordsPredicate otherPersonContainsKeywordsPredicate = (PersonContainsKeywordsPredicate) other;
+ return keywords.equals(otherPersonContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PersonHasNoTaskPredicate.java b/src/main/java/seedu/address/model/person/PersonHasNoTaskPredicate.java
new file mode 100644
index 00000000000..cd5073b359c
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonHasNoTaskPredicate.java
@@ -0,0 +1,34 @@
+package seedu.address.model.person;
+
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Name} has no active task.
+ */
+public class PersonHasNoTaskPredicate implements Predicate {
+ public PersonHasNoTaskPredicate() {
+ }
+
+ @Override
+ public boolean test(Person person) {
+ return !person.isBusy();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // Check for identity
+ if (other == this) {
+ return true;
+ }
+
+ // Check for correct type
+ return other instanceof PersonHasNoTaskPredicate;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("a", "a").toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/PersonLessThanEfficiencyPredicate.java b/src/main/java/seedu/address/model/person/PersonLessThanEfficiencyPredicate.java
new file mode 100644
index 00000000000..5025061b9d8
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PersonLessThanEfficiencyPredicate.java
@@ -0,0 +1,41 @@
+package seedu.address.model.person;
+
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+/**
+ * Tests that a {@code Person}'s {@code Efficiency} less than efficiency threshold given.
+ */
+public class PersonLessThanEfficiencyPredicate implements Predicate {
+ private final Integer threshold;
+
+ public PersonLessThanEfficiencyPredicate(int threshold) {
+ this.threshold = threshold;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ int effi = Integer.parseInt(person.getEfficiency().toString());
+ return effi <= this.threshold;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PersonLessThanEfficiencyPredicate)) {
+ return false;
+ }
+
+ PersonLessThanEfficiencyPredicate otherPersonLessThanEfficiency = (PersonLessThanEfficiencyPredicate) other;
+ return threshold.equals(otherPersonLessThanEfficiency.threshold);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("threshold", threshold).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
index d733f63d739..d7a768b572e 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/seedu/address/model/person/Phone.java
@@ -11,8 +11,9 @@ public class Phone {
public static final String MESSAGE_CONSTRAINTS =
- "Phone numbers should only contain numbers, and it should be at least 3 digits long";
- public static final String VALIDATION_REGEX = "\\d{3,}";
+ "Phone numbers should only contain numbers, and it should be at least 3 digits long, "
+ + "and no more than 15 digits long";
+ public static final String VALIDATION_REGEX = "\\d{3,15}";
public final String value;
/**
diff --git a/src/main/java/seedu/address/model/person/TaskContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/TaskContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..3a2513d17e9
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/TaskContainsKeywordsPredicate.java
@@ -0,0 +1,49 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
+ */
+public class TaskContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public TaskContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ if (person.getTask() == null) {
+ return false;
+ }
+
+ return keywords.stream()
+ .allMatch(keyword -> person
+ .getTask().getTaskTitle().toLowerCase().replaceAll("\\s", "")
+ .contains(keyword.toLowerCase()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof TaskContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ TaskContainsKeywordsPredicate otherTaskContainsKeywordsPredicate = (TaskContainsKeywordsPredicate) other;
+ return keywords.equals(otherTaskContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
index cc0a68d79f9..ce6ef7ec76b 100644
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ b/src/main/java/seedu/address/model/person/UniquePersonList.java
@@ -93,10 +93,21 @@ public void setPersons(List persons) {
if (!personsAreUnique(persons)) {
throw new DuplicatePersonException();
}
-
internalList.setAll(persons);
}
+ /**
+ * Gets a person by using the person's name.
+ */
+ public Person getPerson(Name name) {
+ for (Person person : internalList) {
+ if (person.getName().equals(name)) {
+ return person;
+ }
+ }
+ return null;
+ }
+
/**
* Returns the backing list as an unmodifiable {@code ObservableList}.
*/
diff --git a/src/main/java/seedu/address/model/task/Deadline.java b/src/main/java/seedu/address/model/task/Deadline.java
new file mode 100644
index 00000000000..c16c69751a5
--- /dev/null
+++ b/src/main/java/seedu/address/model/task/Deadline.java
@@ -0,0 +1,73 @@
+package seedu.address.model.task;
+
+import static java.util.Objects.requireNonNull;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Represents a Task's deadline in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDeadline(String)}
+ */
+public class Deadline {
+
+ public static final String MESSAGE_CONSTRAINTS = "Deadline should be in the format: dd-MM-yyyy HHmm";
+ public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy HHmm");
+ private LocalDateTime dateTime;
+
+ /**
+ * Constructs a {@code Deadline} using Local Date Time
+ * @param dateTime A valid deadline.
+ */
+ public Deadline(LocalDateTime dateTime) {
+ requireNonNull(dateTime);
+ this.dateTime = dateTime;
+ }
+
+ /**
+ * Constructs a {@code Deadline} using Local Date Time
+ * @param deadline A valid deadline.
+ */
+ public Deadline(String deadline) {
+ DateTimeFormatter f = DateTimeFormatter.ofPattern("dd-MM-yyyy HHmm");
+ this.dateTime = LocalDateTime.parse(deadline, f);
+ }
+
+
+
+ /**
+ * Returns true if the deadline is in the correct format.
+ */
+ public static boolean isValidDeadline(String deadline) {
+ try {
+ LocalDateTime.parse(deadline, FORMATTER);
+ return true;
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ }
+
+ public LocalDateTime getDateTime() {
+ return this.dateTime;
+ }
+ @Override
+ public String toString() {
+ return dateTime.format(FORMATTER);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Deadline)) {
+ return false;
+ }
+
+ Deadline otherName = (Deadline) other;
+ return dateTime.equals(otherName.dateTime);
+ }
+}
diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java
new file mode 100644
index 00000000000..dc33e555e45
--- /dev/null
+++ b/src/main/java/seedu/address/model/task/Task.java
@@ -0,0 +1,148 @@
+package seedu.address.model.task;
+
+import java.util.Objects;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.model.person.Person;
+
+/**
+ * Represents a Task in the address book.
+ */
+
+public class Task {
+ private final String taskTitle;
+
+ private Deadline deadline;
+
+ private Person personInCharge;
+ private boolean isDone;
+
+
+ /**
+ * Constructs a {@code Task}
+ * @param taskTitle A task name.
+ * @param deadline Deadline for the specific task.
+ */
+ public Task(String taskTitle, Deadline deadline) {
+ this.taskTitle = taskTitle;
+ this.deadline = deadline;
+ }
+
+
+ /**
+ * Constructs a {@code Task} with a specified status.
+ * @param taskTitle A task name.
+ * @param deadline Deadline for the specific task.
+ * @param isDone The status of the task (true if done, false otherwise).
+ */
+ public Task(String taskTitle, Deadline deadline, Boolean isDone) {
+ this.taskTitle = taskTitle;
+ this.deadline = deadline;
+ this.isDone = isDone;
+ }
+
+ /**
+ * Edit the deadline of the task.
+ * @param deadline new deadline of the task.
+ * @return an immutable Task instance.
+ */
+ public Task editDeadline(Deadline deadline) {
+ Task editedTask = new Task(this.taskTitle, deadline, this.isDone());
+ editedTask.setPersonInCharge(this.personInCharge);
+ return editedTask;
+ }
+
+ public String getTaskTitle() {
+ return this.taskTitle;
+ }
+
+ public Deadline getDeadline() {
+ return this.deadline;
+ }
+
+ public Person getPersonInCharge() {
+ return this.personInCharge;
+ }
+
+ /**
+ * Add person in charge to a task.
+ * @param pic
+ */
+ public void setPersonInCharge(Person pic) {
+ this.personInCharge = pic;
+ }
+
+ public boolean isDone() {
+ return this.isDone;
+ }
+
+ /**
+ * Marks an immutable task as done.
+ * @return Task an immutable Task instance
+ */
+ public Task markDone() {
+ Task doneTask = new Task(this.taskTitle, this.deadline, true);
+ doneTask.setPersonInCharge(this.personInCharge);
+ return doneTask;
+ }
+
+ /**
+ * Change the person in charge to another person of an immutable task
+ * @return Task an immutable Task instance
+ */
+ public Task changePersonInCharge(Person pic) {
+ Task updatedTask = new Task(this.taskTitle, this.deadline, false);
+ updatedTask.setPersonInCharge(pic);
+ return updatedTask;
+ }
+
+ /**
+ * Returns true if both tasks have the same name.
+ * This defines a weaker notion of equality between two tasks.
+ */
+ public boolean isSameTask(Task otherTask) {
+ if (otherTask == this) {
+ return true;
+ }
+
+ return otherTask != null
+ && otherTask.getTaskTitle().equals(getTaskTitle());
+ }
+
+ /**
+ * Returns true if both tasks have the same identity and data fields.
+ * This defines a stronger notion of equality between two tasks.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Task)) {
+ return false;
+ }
+
+ Task otherTask = (Task) other;
+ return taskTitle.equals(otherTask.taskTitle);
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(taskTitle, deadline);
+ }
+
+ /**
+ * Format state as text for viewing.
+ */
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("title", taskTitle)
+ .add("deadline", deadline)
+ .add("personInCharge", personInCharge.getName())
+ .toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/task/UniqueTaskList.java b/src/main/java/seedu/address/model/task/UniqueTaskList.java
new file mode 100644
index 00000000000..d77abcf6a4d
--- /dev/null
+++ b/src/main/java/seedu/address/model/task/UniqueTaskList.java
@@ -0,0 +1,149 @@
+package seedu.address.model.task;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.task.exceptions.DuplicateTaskException;
+import seedu.address.model.task.exceptions.TaskNotFoundException;
+
+/**
+ * A list of tasks that enforces uniqueness between its elements and does not allow nulls.
+ * A task is considered unique by comparing using {@code Task#isSameTask(Task)}. As such, adding and updating of
+ * tasks uses Task#isSameTask(Task) for equality so as to ensure that the task being added or updated is
+ * unique in terms of identity in the UniqueTaskList. However, the removal of a person uses Task#equals(Object) so
+ * as to ensure that the task with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Task#isSameTask(Task)
+ */
+public class UniqueTaskList implements Iterable {
+ private final ObservableList internalList = FXCollections.observableArrayList();
+
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent task as the given argument.
+ */
+ public boolean contains(Task toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameTask);
+ }
+
+ /**
+ * Adds a new task to the list.
+ * The task must not already exist in the list.
+ */
+ public void add(Task toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateTaskException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the task {@code target} in the list with {@code editedTask}.
+ * {@code target} must exist in the list.
+ * The task identity of {@code editedTask} must not be the same as another existing task in the list.
+ */
+ public void setTask(Task target, Task editedTask) {
+ requireAllNonNull(target, editedTask);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new TaskNotFoundException();
+ }
+
+ if (!target.isSameTask(editedTask) && contains(editedTask)) {
+ throw new DuplicateTaskException();
+ }
+
+ internalList.set(index, editedTask);
+ }
+
+ /**
+ * Removes the equivalent task from the list.
+ * The task must exist in the list.
+ */
+ public void remove(Task toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new TaskNotFoundException();
+ }
+ }
+
+ public void setPersons(UniqueTaskList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code tasks}.
+ * {@code tasks} must not contain duplicate tasks.
+ */
+ public void setTasks(List tasks) {
+ requireAllNonNull(tasks);
+ if (!tasksAreUnique(tasks)) {
+ throw new DuplicateTaskException();
+ }
+
+ internalList.setAll(tasks);
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UniqueTaskList)) {
+ return false;
+ }
+
+ UniqueTaskList otherUniqueTaskList = (UniqueTaskList) other;
+ return internalList.equals(otherUniqueTaskList.internalList);
+ }
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return internalList.toString();
+ }
+
+ /**
+ * Returns true if {@code persons} contains only unique persons.
+ */
+ private boolean tasksAreUnique(List tasks) {
+ for (int i = 0; i < tasks.size() - 1; i++) {
+ for (int j = i + 1; j < tasks.size(); j++) {
+ if (tasks.get(i).isSameTask(tasks.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/address/model/task/exceptions/DuplicateTaskException.java b/src/main/java/seedu/address/model/task/exceptions/DuplicateTaskException.java
new file mode 100644
index 00000000000..922c2a9cdd1
--- /dev/null
+++ b/src/main/java/seedu/address/model/task/exceptions/DuplicateTaskException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.task.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Tasks (Tasks are considered duplicates if they have the same
+ * identity).
+ */
+public class DuplicateTaskException extends RuntimeException {
+ public DuplicateTaskException() {
+ super("Operation would result in duplicate tasks");
+ }
+}
diff --git a/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java b/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java
new file mode 100644
index 00000000000..5122ecfaf0f
--- /dev/null
+++ b/src/main/java/seedu/address/model/task/exceptions/TaskNotFoundException.java
@@ -0,0 +1,7 @@
+package seedu.address.model.task.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified task.
+ */
+public class TaskNotFoundException extends RuntimeException{
+}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..15da30942b4 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -7,6 +7,9 @@
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Comment;
+import seedu.address.model.person.Department;
+import seedu.address.model.person.Efficiency;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
@@ -17,26 +20,27 @@
* Contains utility methods for populating {@code AddressBook} with sample data.
*/
public class SampleDataUtil {
+ public static final Comment EMPTY_COMMENT = new Comment("");
public static Person[] getSamplePersons() {
return new Person[] {
new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
- new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
+ new Address("Blk 30 Geylang Street 29, #06-40"), new Department("Business Development"),
+ getTagSet("friends"), new Efficiency("80"), EMPTY_COMMENT),
new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
- new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
+ new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), new Department("IT"),
+ getTagSet("colleagues", "friends"), new Efficiency("60"), EMPTY_COMMENT),
new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
- new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
+ new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), new Department("Marketing"),
+ getTagSet("neighbours"), new Efficiency("90"), EMPTY_COMMENT),
new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
- new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
+ new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), new Department("Marketing"),
+ getTagSet("family"), new Efficiency("50"), EMPTY_COMMENT),
new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
- new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
+ new Address("Blk 47 Tampines Street 20, #17-35"), new Department("Finance"),
+ getTagSet("classmates"), new Efficiency("20"), EMPTY_COMMENT),
new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
+ new Address("Blk 45 Aljunied Street 85, #11-31"), new Department("Production"),
+ getTagSet("colleagues"), new Efficiency("0"), EMPTY_COMMENT)
};
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
index bd1ca0f56c8..d93017d156f 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
@@ -11,6 +11,9 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Comment;
+import seedu.address.model.person.Department;
+import seedu.address.model.person.Efficiency;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
@@ -28,19 +31,29 @@ class JsonAdaptedPerson {
private final String phone;
private final String email;
private final String address;
+ private final String department;
private final List tags = new ArrayList<>();
+ private final String efficiency;
+ private final String comment;
+
/**
* Constructs a {@code JsonAdaptedPerson} with the given person details.
*/
@JsonCreator
public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tags") List tags) {
+ @JsonProperty("email") String email, @JsonProperty("address") String address,
+ @JsonProperty("department") String department,
+ @JsonProperty("tags") List tags,
+ @JsonProperty("efficiency") String efficiency,
+ @JsonProperty("comment") String comment) {
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
+ this.department = department;
+ this.efficiency = efficiency;
+ this.comment = comment;
if (tags != null) {
this.tags.addAll(tags);
}
@@ -54,11 +67,15 @@ public JsonAdaptedPerson(Person source) {
phone = source.getPhone().value;
email = source.getEmail().value;
address = source.getAddress().value;
+ department = source.getDepartment().department;
+ efficiency = source.getEfficiency().value;
+ comment = source.getComment().comment;
tags.addAll(source.getTags().stream()
.map(JsonAdaptedTag::new)
.collect(Collectors.toList()));
}
+
/**
* Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
*
@@ -102,8 +119,38 @@ public Person toModelType() throws IllegalValueException {
}
final Address modelAddress = new Address(address);
+ if (department == null) {
+ throw new IllegalValueException(String.format(
+ MISSING_FIELD_MESSAGE_FORMAT, Department.class.getSimpleName()));
+ }
+ if (!Department.isValidDepartment(department)) {
+ throw new IllegalValueException(Department.MESSAGE_CONSTRAINTS);
+ }
+ final Department modelDepartment = new Department(department);
+
+ if (efficiency == null) {
+ throw new IllegalValueException(String.format(
+ MISSING_FIELD_MESSAGE_FORMAT, Efficiency.class.getSimpleName()));
+ }
+
+ if (!Efficiency.isValidEfficiency(efficiency)) {
+ throw new IllegalValueException(Efficiency.MESSAGE_CONSTRAINTS);
+ }
+ final Efficiency modelEfficiency = new Efficiency(efficiency);
+
final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
+
+ final Comment modelComment;
+
+ if (comment == null) {
+ modelComment = new Comment("");
+ } else {
+ modelComment = new Comment(comment);
+ }
+
+
+ return new Person(modelName, modelPhone, modelEmail, modelAddress, modelDepartment, modelTags,
+ modelEfficiency, modelComment);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTask.java b/src/main/java/seedu/address/storage/JsonAdaptedTask.java
new file mode 100644
index 00000000000..d2b37fbaf6a
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedTask.java
@@ -0,0 +1,92 @@
+package seedu.address.storage;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.AddressBook;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Person;
+import seedu.address.model.task.Deadline;
+import seedu.address.model.task.Task;
+
+/**
+ * Jackson-friendly version of {@link Task}.
+ */
+public class JsonAdaptedTask {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Task's %s field is missing!";
+ //private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-ddTHH:mm");
+ private final String title;
+ private final LocalDateTime deadline;
+ private final String personInCharge;
+ private final Boolean isDone;
+
+ /**
+ * Constructs a {@code JsonAdaptedTask} with the given task details.
+ */
+ @JsonCreator
+ public JsonAdaptedTask(@JsonProperty("title") String title, @JsonProperty("deadline") String deadline,
+ @JsonProperty("personInCharge") String personInCharge,
+ @JsonProperty("isDone") Boolean isDone) {
+ this.title = title;
+ this.deadline = LocalDateTime.parse(deadline, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"));
+ this.personInCharge = personInCharge;
+ this.isDone = isDone;
+ }
+
+ /**
+ * Converts a given {@code Task} into this class for Jackson use.
+ */
+ public JsonAdaptedTask(Task source) {
+ title = source.getTaskTitle();
+ deadline = source.getDeadline().getDateTime();
+ personInCharge = source.getPersonInCharge().getName().toString();
+ isDone = source.isDone();
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted task object into the model's {@code Task} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted task.
+ */
+ public Task toModelType(AddressBook ab) throws IllegalValueException {
+ if (title == null || title == "") {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "task title"));
+ }
+ final String modelTaskTitle = title;
+
+ if (deadline == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "deadline"));
+ }
+ final Deadline modelDeadline = new Deadline(deadline);
+
+ if (personInCharge == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "personInCharge"));
+ }
+
+ if (isDone == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "isDone"));
+ }
+
+ if (!Name.isValidName(personInCharge)) {
+ throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
+ }
+ final Name name = new Name(personInCharge);
+
+ // Find the Person object from the personList using the personName
+ Person modelPic = ab.getPerson(name);
+
+ if (modelPic == null) {
+ return null;
+ }
+
+ Task task = new Task(modelTaskTitle, modelDeadline, isDone);
+ ab.assignTask(task, modelPic);
+
+ return task;
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
index 5efd834091d..bd20e0d08c8 100644
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
@@ -12,6 +12,7 @@
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
/**
* An Immutable AddressBook that is serializable to JSON format.
@@ -21,14 +22,21 @@ class JsonSerializableAddressBook {
public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
+ public static final String MESSAGE_DUPLICATE_TASK = "Task list contains duplicate task(s).";
+
+
private final List persons = new ArrayList<>();
+ private final List tasks = new ArrayList<>();
+
/**
* Constructs a {@code JsonSerializableAddressBook} with the given persons.
*/
@JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
+ public JsonSerializableAddressBook(@JsonProperty("persons") List persons,
+ @JsonProperty("tasks") List tasks) {
this.persons.addAll(persons);
+ this.tasks.addAll(tasks);
}
/**
@@ -38,6 +46,7 @@ public JsonSerializableAddressBook(@JsonProperty("persons") List {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
+ public static final String USERGUIDE_URL = "https://ay2324s2-cs2103t-t14-1.github.io/tp/UserGuide.html";
public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 79e74ef37c0..35a1f305eed 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -4,6 +4,7 @@
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
+import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextInputControl;
import javafx.scene.input.KeyCombination;
@@ -33,6 +34,7 @@ public class MainWindow extends UiPart {
// Independent Ui parts residing in this Ui container
private PersonListPanel personListPanel;
private ResultDisplay resultDisplay;
+ private TasksDisplay tasksDisplay;
private HelpWindow helpWindow;
@FXML
@@ -50,6 +52,12 @@ public class MainWindow extends UiPart {
@FXML
private StackPane statusbarPlaceholder;
+ @FXML
+ private StackPane tasksList;
+
+ @FXML
+ private Label listTitle;
+
/**
* Creates a {@code MainWindow} with the given {@code Stage} and {@code Logic}.
*/
@@ -121,6 +129,10 @@ void fillInnerParts() {
CommandBox commandBox = new CommandBox(this::executeCommand);
commandBoxPlaceholder.getChildren().add(commandBox.getRoot());
+
+ tasksDisplay = new TasksDisplay(logic.getTaskList());
+ tasksList.getChildren().add(tasksDisplay.getRoot());
+
}
/**
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
index 094c42cda82..baa9e75344d 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/address/ui/PersonCard.java
@@ -8,6 +8,7 @@
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import seedu.address.model.person.Person;
+import seedu.address.model.task.Task;
/**
* An UI component that displays information of a {@code Person}.
@@ -38,6 +39,14 @@ public class PersonCard extends UiPart {
private Label address;
@FXML
private Label email;
+ @FXML
+ private Label task;
+ @FXML
+ private Label efficiency;
+
+ @FXML
+ private Label comment;
+
@FXML
private FlowPane tags;
@@ -52,8 +61,33 @@ public PersonCard(Person person, int displayedIndex) {
phone.setText(person.getPhone().value);
address.setText(person.getAddress().value);
email.setText(person.getEmail().value);
+ efficiency.setText(person.getEfficiency().value + "%");
+ comment.setText(person.getComment().comment);
+ double efficiencyValue = Double.parseDouble(person.getEfficiency().value);
+ if (efficiencyValue < 80 && efficiencyValue > 20) {
+ efficiency.setStyle("-fx-text-fill: yellow;");
+ } else if (efficiencyValue <= 20) {
+ efficiency.setStyle("-fx-text-fill: red;");
+ }
+ Label departmentLabel = new Label(person.getDepartment().department);
+ departmentLabel.setStyle("-fx-background-color: #3e7b91;");
+ tags.getChildren().add(departmentLabel);
person.getTags().stream()
.sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+ .forEach(tag -> {
+ Label tagLabel = new Label(tag.tagName);
+ tags.getChildren().add(tagLabel);
+ });
+ if (person.getTask() != null && !person.getTask().isDone()) {
+ task.setText(displayCurrentTask(person.getTask()));
+ } else {
+ task.setText("No current task");
+ }
+ }
+
+ private String displayCurrentTask(Task t) {
+ String taskTitle = t.getTaskTitle();
+ String deadline = t.getDeadline().toString();
+ return ("Current task: " + taskTitle + " (by " + deadline + ")");
}
}
diff --git a/src/main/java/seedu/address/ui/TaskCard.java b/src/main/java/seedu/address/ui/TaskCard.java
new file mode 100644
index 00000000000..7349b200087
--- /dev/null
+++ b/src/main/java/seedu/address/ui/TaskCard.java
@@ -0,0 +1,81 @@
+package seedu.address.ui;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Region;
+import seedu.address.model.task.Task;
+
+/**
+ * An UI component that displays information of a {@code Task}.
+ */
+public class TaskCard extends UiPart {
+
+ private static final String FXML = "TaskListCard.fxml";
+
+ private static final String DONE_STRING = "Done";
+
+ private static final String NOT_DONE_STRING = "Not Done";
+
+ public final Task task;
+
+ @FXML
+ private Label id;
+
+ @FXML
+ private Label deadline;
+
+ @FXML
+ private Label taskName;
+
+ @FXML
+ private Label status;
+
+ @FXML
+ private Label inCharge;
+
+ /**
+ * Creates a {@code TaskCard} with the given {@code Task}, index and
+ * other relevant information to display.
+ */
+ public TaskCard(Task task, int displayedIndex) {
+ super(FXML);
+ this.task = task;
+ id.setText(displayedIndex + ". ");
+ taskName.setText(task.getTaskTitle());
+ deadline.setText(getDeadline(task));
+ status.setText(getStatus(task));
+ inCharge.setText(getPersonInCharge(task));
+
+ }
+
+ /**
+ * Get name of person in charge.
+ */
+ private String getPersonInCharge(Task task) {
+ return "In Charge: " + task.getPersonInCharge().getName().fullName;
+ }
+
+ /**
+ * Get deadline of Task.
+ */
+ private String getDeadline(Task task) {
+ return "Deadline: " + task.getDeadline().toString();
+ }
+
+ /**
+ * Get the current status of Task.
+ */
+ private String getStatus(Task task) {
+ String output = "";
+ if (task.isDone()) {
+ output += DONE_STRING;
+ status.setStyle("-fx-text-fill: green;");
+ } else {
+ output += NOT_DONE_STRING;
+ status.setStyle("-fx-text-fill: red;");
+ }
+
+ return output;
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/TasksDisplay.java b/src/main/java/seedu/address/ui/TasksDisplay.java
new file mode 100644
index 00000000000..8e4d6296a90
--- /dev/null
+++ b/src/main/java/seedu/address/ui/TasksDisplay.java
@@ -0,0 +1,46 @@
+package seedu.address.ui;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.model.task.Task;
+
+/**
+ * List containing all tasks.
+ */
+public class TasksDisplay extends UiPart {
+
+ private static final String FXML = "TasksDisplay.fxml";
+
+ @FXML
+ private ListView taskListView;
+
+
+ /**
+ * Creates a {@code TasksDisplay} with the given {@code ObservableList}.
+ */
+ public TasksDisplay(ObservableList taskList) {
+ super(FXML);
+ taskListView.setItems(taskList);
+ taskListView.setCellFactory(listview -> new TaskListViewCell());
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Task} using a {@code TaskCard}.
+ */
+ class TaskListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Task task, boolean isEmpty) {
+ super.updateItem(task, isEmpty);
+
+ if (isEmpty || task == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new TaskCard(task, getIndex() + 1).getRoot());
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/address/ui/UiManager.java
index fdf024138bc..5ba75c83bb6 100644
--- a/src/main/java/seedu/address/ui/UiManager.java
+++ b/src/main/java/seedu/address/ui/UiManager.java
@@ -20,7 +20,7 @@ public class UiManager implements Ui {
public static final String ALERT_DIALOG_PANE_FIELD_ID = "alertDialogPane";
private static final Logger logger = LogsCenter.getLogger(UiManager.class);
- private static final String ICON_APPLICATION = "/images/address_book_32.png";
+ private static final String ICON_APPLICATION = "/images/ET_logo.png";
private Logic logic;
private MainWindow mainWindow;
diff --git a/src/main/resources/images/ET_logo.png b/src/main/resources/images/ET_logo.png
new file mode 100644
index 00000000000..ae6b9779af7
Binary files /dev/null and b/src/main/resources/images/ET_logo.png differ
diff --git a/src/main/resources/view/CommandBox.fxml b/src/main/resources/view/CommandBox.fxml
index 124283a392e..033a5d66a29 100644
--- a/src/main/resources/view/CommandBox.fxml
+++ b/src/main/resources/view/CommandBox.fxml
@@ -4,6 +4,6 @@
-
+
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..2d95a33b056 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -1,8 +1,12 @@
.background {
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: derive(#FBF9F1, 20%);
background-color: #383838; /* Used in the default.html file */
}
+.command-pane {
+ -fx-background-color: #F2E6CE;
+}
+
.label {
-fx-font-size: 11pt;
-fx-font-family: "Segoe UI Semibold";
@@ -13,14 +17,14 @@
.label-bright {
-fx-font-size: 11pt;
-fx-font-family: "Segoe UI Semibold";
- -fx-text-fill: white;
+ -fx-text-fill: black;
-fx-opacity: 1;
}
.label-header {
-fx-font-size: 32pt;
-fx-font-family: "Segoe UI Light";
- -fx-text-fill: white;
+ -fx-text-fill: black;
-fx-opacity: 1;
}
@@ -30,7 +34,7 @@
}
.tab-pane {
- -fx-padding: 0 0 0 1;
+ -fx-padding: 0 0 0 0;
}
.tab-pane .tab-header-area {
@@ -40,9 +44,9 @@
}
.table-view {
- -fx-base: #1d1d1d;
- -fx-control-inner-background: #1d1d1d;
- -fx-background-color: #1d1d1d;
+ -fx-base: #FBF9F1;
+ -fx-control-inner-background: #FBF9F1;
+ -fx-background-color: #FBF9F1;
-fx-table-cell-border-color: transparent;
-fx-table-header-border-color: transparent;
-fx-padding: 5;
@@ -67,7 +71,7 @@
.table-view .column-header .label {
-fx-font-size: 20pt;
-fx-font-family: "Segoe UI Light";
- -fx-text-fill: white;
+ -fx-text-fill: black;
-fx-alignment: center-left;
-fx-opacity: 1;
}
@@ -77,47 +81,52 @@
}
.split-pane:horizontal .split-pane-divider {
- -fx-background-color: derive(#1d1d1d, 20%);
- -fx-border-color: transparent transparent transparent #4d4d4d;
+ -fx-background-color: #FBF9F1;
}
.split-pane {
-fx-border-radius: 1;
-fx-border-width: 1;
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: derive(#FBF9F1, 20%);
}
.list-view {
-fx-background-insets: 0;
-fx-padding: 0;
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: derive(#FBF9F1, 20%);
}
.list-cell {
+ -fx-background-radius: 5px;
-fx-label-padding: 0 0 0 0;
- -fx-graphic-text-gap : 0;
- -fx-padding: 0 0 0 0;
+ -fx-graphic-text-gap: 0;
+ -fx-padding: 0 0 5 0;
+ -fx-spacing: 10 10 10 10;
}
.list-cell:filled:even {
- -fx-background-color: #3c3e3f;
+ -fx-background-color: #BBAB8C;
+ -fx-background-insets: 0 0 5 0;
}
.list-cell:filled:odd {
- -fx-background-color: #515658;
+ -fx-background-color: #BB9E83;
+ -fx-background-insets: 0 0 5 0;
}
.list-cell:filled:selected {
- -fx-background-color: #424d5f;
+ -fx-background-color: #A9B388;
}
.list-cell:filled:selected #cardPane {
- -fx-border-color: #3e7b91;
+ -fx-background-radius: 5px;
+ -fx-border-color: #6E8B74;
-fx-border-width: 1;
+ -fx-border-radius: 5px;
}
.list-cell .label {
- -fx-text-fill: white;
+ -fx-text-fill: black;
}
.cell_big_label {
@@ -132,25 +141,35 @@
-fx-text-fill: #010504;
}
+.efficiency_small_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 14px;
+ -fx-text-fill: #010504;
+}
+
+.status_small_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 14px;
+ -fx-text-fill: #010504;
+}
+
.stack-pane {
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: derive(#FBF9F1, 20%);
}
.pane-with-border {
- -fx-background-color: derive(#1d1d1d, 20%);
- -fx-border-color: derive(#1d1d1d, 10%);
- -fx-border-top-width: 1px;
+ -fx-background-color: derive(#FBF9F1, 20%);
}
.status-bar {
- -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-background-color: derive(#FBF9F1, 30%);
}
.result-display {
-fx-background-color: transparent;
-fx-font-family: "Segoe UI Light";
- -fx-font-size: 13pt;
- -fx-text-fill: white;
+ -fx-font-size: 12pt;
+ -fx-text-fill: black;
}
.result-display .label {
@@ -159,52 +178,83 @@
.status-bar .label {
-fx-font-family: "Segoe UI Light";
- -fx-text-fill: white;
+ -fx-text-fill: black;
-fx-padding: 4px;
-fx-pref-height: 30px;
}
.status-bar-with-border {
- -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-background-color: derive(#FBF9F1, 30%);
-fx-border-color: derive(#1d1d1d, 25%);
-fx-border-width: 1px;
}
.status-bar-with-border .label {
- -fx-text-fill: white;
+ -fx-text-fill: black;
}
.grid-pane {
- -fx-background-color: derive(#1d1d1d, 30%);
- -fx-border-color: derive(#1d1d1d, 30%);
+ -fx-background-color: derive(#FBF9F1, 30%);
-fx-border-width: 1px;
}
.grid-pane .stack-pane {
- -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-background-color: derive(#FBF9F1, 30%);
}
.context-menu {
- -fx-background-color: derive(#1d1d1d, 50%);
+ -fx-background-color: derive(#FBF9F1, 50%);
}
.context-menu .label {
- -fx-text-fill: white;
+ -fx-text-fill: black;
}
.menu-bar {
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: #FBF9F1;
}
.menu-bar .label {
- -fx-font-size: 14pt;
+ -fx-font-size: 12pt;
-fx-font-family: "Segoe UI Light";
- -fx-text-fill: white;
+ -fx-text-fill: #B99470;
-fx-opacity: 0.9;
}
+.menu {
+ -fx-background-color: #FBF9F1;
+}
+
.menu .left-container {
- -fx-background-color: black;
+ -fx-background-color: #FBF9F1;
+}
+
+.menu:hover {
+ -fx-background-color: #BB9E83;
+}
+
+.menu:hover .label {
+ -fx-text-fill: black;
+}
+
+.menu:selected {
+ -fx-background-color: #BB9E83;
+}
+
+.menu:focused {
+ -fx-background-color: #BB9E83;
+}
+
+.menu-item {
+ -fx-background-color: derived(#FBF9F1, 30%);
+}
+
+.menu-item:hover {
+ -fx-background-color: #BB9E83;
+}
+
+.menu-item:hover .label {
+ -fx-text-fill: black;
}
/*
@@ -214,10 +264,10 @@
*/
.button {
-fx-padding: 5 22 5 22;
- -fx-border-color: #e2e2e2;
+ -fx-border-color: #BB9E83;
-fx-border-width: 2;
-fx-background-radius: 0;
- -fx-background-color: #1d1d1d;
+ -fx-background-color: #BB9E83;
-fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
-fx-font-size: 11pt;
-fx-text-fill: #d8d8d8;
@@ -225,7 +275,7 @@
}
.button:hover {
- -fx-background-color: #3a3a3a;
+ -fx-background-color: #BB9E83;
}
.button:pressed, .button:default:hover:pressed {
@@ -243,50 +293,50 @@
.button:disabled, .button:default:disabled {
-fx-opacity: 0.4;
- -fx-background-color: #1d1d1d;
+ -fx-background-color: #BB9E83;
-fx-text-fill: white;
}
.button:default {
- -fx-background-color: -fx-focus-color;
- -fx-text-fill: #ffffff;
+ -fx-background-color:#BBAB8C;
+ -fx-text-fill: black;
}
.button:default:hover {
- -fx-background-color: derive(-fx-focus-color, 30%);
+ -fx-background-color: #BB9E83;
}
.dialog-pane {
- -fx-background-color: #1d1d1d;
+ -fx-background-color: #FBF9F1;
}
.dialog-pane > *.button-bar > *.container {
- -fx-background-color: #1d1d1d;
+ -fx-background-color: #FBF9F1;
}
.dialog-pane > *.label.content {
-fx-font-size: 14px;
-fx-font-weight: bold;
- -fx-text-fill: white;
+ -fx-text-fill: black;
}
.dialog-pane:header *.header-panel {
- -fx-background-color: derive(#1d1d1d, 25%);
+ -fx-background-color: derive(#FBF9F1, 25%);
}
.dialog-pane:header *.header-panel *.label {
-fx-font-size: 18px;
-fx-font-style: italic;
- -fx-fill: white;
- -fx-text-fill: white;
+ -fx-fill: black;
+ -fx-text-fill: black;
}
.scroll-bar {
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: derive(#FBF9F1, 20%);
}
.scroll-bar .thumb {
- -fx-background-color: derive(#1d1d1d, 50%);
+ -fx-background-color: #F2E6CE;
-fx-background-insets: 3;
}
@@ -309,6 +359,7 @@
#cardPane {
-fx-background-color: transparent;
+ -fx-background-radius: 5px;
-fx-border-width: 0;
}
@@ -318,22 +369,26 @@
}
#commandTextField {
- -fx-background-color: transparent #383838 transparent #383838;
- -fx-background-insets: 0;
- -fx-border-color: #383838 #383838 #ffffff #383838;
- -fx-border-insets: 0;
- -fx-border-width: 1;
+ -fx-border-width: 0;
+ -fx-border-radius: 10;
-fx-font-family: "Segoe UI Light";
- -fx-font-size: 13pt;
- -fx-text-fill: white;
+ -fx-font-size: 12pt;
+ -fx-text-fill: black;
}
#filterField, #personListPanel, #personWebpage {
-fx-effect: innershadow(gaussian, black, 10, 0, 0, 0);
}
+#listTitle {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 16px;
+ -fx-text-fill: #B99470;
+ -fx-alignment: center-left;
+}
+
#resultDisplay .content {
- -fx-background-color: transparent, #383838, transparent, #383838;
+ -fx-background-color: transparent, #F2E6CE, transparent, #F2E6CE;
-fx-background-radius: 0;
}
@@ -344,7 +399,7 @@
#tags .label {
-fx-text-fill: white;
- -fx-background-color: #3e7b91;
+ -fx-background-color: #6E8B74;
-fx-padding: 1 3 1 3;
-fx-border-radius: 2;
-fx-background-radius: 2;
diff --git a/src/main/resources/view/Extensions.css b/src/main/resources/view/Extensions.css
index bfe82a85964..6ac12a149d5 100644
--- a/src/main/resources/view/Extensions.css
+++ b/src/main/resources/view/Extensions.css
@@ -5,7 +5,7 @@
.list-cell:empty {
/* Empty cells will not have alternating colours */
- -fx-background: #383838;
+ -fx-background: transparent;
}
.tag-selector {
diff --git a/src/main/resources/view/HelpWindow.css b/src/main/resources/view/HelpWindow.css
index 17e8a8722cd..02c99d117b1 100644
--- a/src/main/resources/view/HelpWindow.css
+++ b/src/main/resources/view/HelpWindow.css
@@ -1,13 +1,13 @@
#copyButton, #helpMessage {
- -fx-text-fill: white;
+ -fx-text-fill: black;
}
#copyButton {
- -fx-background-color: dimgray;
+ -fx-background-color: #BBAB8C;
}
#copyButton:hover {
- -fx-background-color: gray;
+ -fx-background-color: #BB9E83;
}
#copyButton:armed {
@@ -15,5 +15,5 @@
}
#helpMessageContainer {
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: derive(#FBF9F1, 20%);
}
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 7778f666a0a..15982810b7f 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -1,20 +1,16 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
@@ -33,25 +29,41 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index f5e812e25e6..3a41973687f 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -1,36 +1,52 @@
-
-
-
-
-
-
-
-
+
+
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/PersonListPanel.fxml
index a1bb6bbace8..e675e861ead 100644
--- a/src/main/resources/view/PersonListPanel.fxml
+++ b/src/main/resources/view/PersonListPanel.fxml
@@ -1,8 +1,8 @@
-
-
+
+
-
+
diff --git a/src/main/resources/view/TaskListCard.fxml b/src/main/resources/view/TaskListCard.fxml
new file mode 100644
index 00000000000..8cab6c31e0d
--- /dev/null
+++ b/src/main/resources/view/TaskListCard.fxml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/TasksDisplay.fxml b/src/main/resources/view/TasksDisplay.fxml
new file mode 100644
index 00000000000..3a80cd51d88
--- /dev/null
+++ b/src/main/resources/view/TasksDisplay.fxml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
index ccd21f7d1a9..ab2f5489f95 100644
--- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
@@ -4,5 +4,6 @@
"phone": "9482424",
"email": "hans@example.com",
"address": "4th street"
- } ]
+ } ],
+ "tasks": []
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
index a7427fe7aa2..ce4a5c24ffa 100644
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
@@ -4,11 +4,17 @@
"phone": "94351253",
"email": "alice@example.com",
"address": "123, Jurong West Ave 6, #08-111",
- "tags": [ "friends" ]
+ "department" : "IT",
+ "tags": [ "friends" ],
+ "efficiency": "80"
}, {
"name": "Alice Pauline",
"phone": "94351253",
"email": "pauline@example.com",
- "address": "4th street"
- } ]
+ "department" : "IT",
+ "address": "4th street",
+ "efficiency": "80"
+ } ],
+
+ "tasks": []
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
index ad3f135ae42..1cf2e38d80c 100644
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
@@ -3,6 +3,8 @@
"name": "Hans Muster",
"phone": "9482424",
"email": "invalid@email!3e",
- "address": "4th street"
- } ]
+ "address": "4th street",
+ "department": " "
+ } ],
+ "tasks": []
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalAddressBook.json
new file mode 100644
index 00000000000..0ff8f30d53e
--- /dev/null
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalAddressBook.json
@@ -0,0 +1,81 @@
+{
+ "_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
+ "persons" : [ {
+ "name" : "Alice Pauline",
+ "phone" : "94351253",
+ "email" : "alice@example.com",
+ "address" : "123, Jurong West Ave 6, #08-111",
+ "department" : "Finance",
+ "tags" : [ "friends" ],
+ "efficiency": "80"
+ }, {
+ "name" : "Benson Meier",
+ "phone" : "98765432",
+ "email" : "johnd@example.com",
+ "address" : "311, Clementi Ave 2, #02-25",
+ "department" : "IT",
+ "tags" : [ "owesMoney", "friends" ],
+ "efficiency": "50"
+ }, {
+ "name" : "Carl Kurz",
+ "phone" : "95352563",
+ "email" : "heinz@example.com",
+ "address" : "wall street",
+ "department" : "Marketing",
+ "tags" : [ ],
+ "efficiency": "90"
+ }, {
+ "name" : "Daniel Meier",
+ "phone" : "87652533",
+ "email" : "cornelia@example.com",
+ "address" : "10th street",
+ "department" : "Production",
+ "tags" : [ "friends" ],
+ "efficiency": "40"
+ }, {
+ "name" : "Elle Meyer",
+ "phone" : "9482224",
+ "email" : "werner@example.com",
+ "address" : "michegan ave",
+ "department" : "IT",
+ "tags" : [ ],
+ "efficiency": "30"
+ }, {
+ "name" : "Fiona Kunz",
+ "phone" : "9482427",
+ "email" : "lydia@example.com",
+ "address" : "little tokyo",
+ "department" : "Business Development",
+ "tags" : [ ],
+ "efficiency": "20"
+ }, {
+ "name" : "George Best",
+ "phone" : "9482442",
+ "email" : "anna@example.com",
+ "address" : "4th street",
+ "department" : "Administration",
+ "tags" : [ ],
+ "efficiency": "0"
+ } ],
+ "tasks": [ {
+ "title" : "Complete Project Proposal",
+ "deadline" : "2024-03-25T23:59:00",
+ "personInCharge": "Alice Pauline",
+ "isDone": "False"
+ }, {
+ "title" : "Prepare Presentation Slides",
+ "deadline" : "2024-05-05T09:00:00",
+ "personInCharge": "Benson Meier",
+ "isDone": "False"
+ }, {
+ "title" : "Submit Year End Report",
+ "deadline" : "2024-11-30T17:00:00",
+ "personInCharge": "Carl Kurz",
+ "isDone": "False"
+ }, {
+ "title" : "Organize Team Meeting",
+ "deadline" : "2024-08-04T14:00:00",
+ "personInCharge": "Daniel Meier",
+ "isDone": "False"
+ }]
+}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
deleted file mode 100644
index 72262099d35..00000000000
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
- "persons" : [ {
- "name" : "Alice Pauline",
- "phone" : "94351253",
- "email" : "alice@example.com",
- "address" : "123, Jurong West Ave 6, #08-111",
- "tags" : [ "friends" ]
- }, {
- "name" : "Benson Meier",
- "phone" : "98765432",
- "email" : "johnd@example.com",
- "address" : "311, Clementi Ave 2, #02-25",
- "tags" : [ "owesMoney", "friends" ]
- }, {
- "name" : "Carl Kurz",
- "phone" : "95352563",
- "email" : "heinz@example.com",
- "address" : "wall street",
- "tags" : [ ]
- }, {
- "name" : "Daniel Meier",
- "phone" : "87652533",
- "email" : "cornelia@example.com",
- "address" : "10th street",
- "tags" : [ "friends" ]
- }, {
- "name" : "Elle Meyer",
- "phone" : "9482224",
- "email" : "werner@example.com",
- "address" : "michegan ave",
- "tags" : [ ]
- }, {
- "name" : "Fiona Kunz",
- "phone" : "9482427",
- "email" : "lydia@example.com",
- "address" : "little tokyo",
- "tags" : [ ]
- }, {
- "name" : "George Best",
- "phone" : "9482442",
- "email" : "anna@example.com",
- "address" : "4th street",
- "tags" : [ ]
- } ]
-}
diff --git a/src/test/java/seedu/address/commons/util/InvalidationListenerManagerTest.java b/src/test/java/seedu/address/commons/util/InvalidationListenerManagerTest.java
new file mode 100644
index 00000000000..dcdc065b910
--- /dev/null
+++ b/src/test/java/seedu/address/commons/util/InvalidationListenerManagerTest.java
@@ -0,0 +1,72 @@
+package seedu.address.commons.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+import javafx.beans.InvalidationListener;
+import javafx.beans.property.SimpleObjectProperty;
+
+public class InvalidationListenerManagerTest {
+ private final SimpleObjectProperty