diff --git a/.gitignore b/.gitignore index 71c9194e8bd..48d00bec63d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ src/main/resources/docs/ /config.json /preferences.json /*.log.* +/export/ +/import/ # Test sandbox files src/test/data/sandbox/ diff --git a/README.md b/README.md index 13f5c77403f..0967d52919e 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,17 @@ -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) +# QuickCache +[![Java CI](https://github.com/AY2021S1-CS2103T-T13-2/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2021S1-CS2103T-T13-2/tp/actions) ![Ui](docs/images/Ui.png) -* 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. +This is a desktop application called **QuickCache**.
+**QuickCache** is a flashcard knowledge bank where students can add their content by questions and test themselves afterwards. +Students can monitor their performance and progress over time using **QuickCache** as well.
+**QuickCache** contains a Graphical User Interface (GUI) but has been optimized to enable user interaction mostly via the Command Line Interface (CLI). + +## Site Map +* [User Guide](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/docs/UserGuide.md) +* [Developer Guide](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/docs/DeveloperGuide.md) +* [About Us](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/docs/AboutUs.md) + +## Acknowledgements +* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org). diff --git a/build.gradle b/build.gradle index be2d2905dde..a6cc28fda7c 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id 'jacoco' } -mainClassName = 'seedu.address.Main' +mainClassName = 'quickcache.Main' sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -20,6 +20,10 @@ checkstyle { toolVersion = '8.29' } +run { + enableAssertions = true +} + test { useJUnitPlatform() finalizedBy jacocoTestReport @@ -42,7 +46,7 @@ task coverage(type: JacocoReport) { dependencies { String jUnitVersion = '5.4.0' - String javaFxVersion = '11' + String javaFxVersion = '11.0.1' implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' @@ -66,7 +70,7 @@ dependencies { } shadowJar { - archiveName = 'addressbook.jar' + archiveName = 'quickcache.jar' } defaultTasks 'clean', 'test' diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 1c9514e966a..ce4fb48bcc1 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -3,57 +3,69 @@ layout: page title: About Us --- +QuickCache was developed by the CS2103T-T13-2 Team (AY2021 Sem 1). We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg). -You can reach us at the email `seer[at]comp.nus.edu.sg` - ## Project team -### John Doe +### Josiah + + + +[[github](https://github.com/josiahkhoo)] +[[portfolio](team/josiahkhoo.md)] - +#### Developer and Team Lead +* Responsible for overall project coordination. +* In charge of defining, assigning, and tracking project tasks. +* Ensure project deliverables are done on time and in the right format. -[[homepage](http://www.comp.nus.edu.sg/~damithch)] -[[github](https://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +### Francis Hodianto -* Role: Project Advisor + -### Jane Doe +[[github](https://github.com/FH-30)] +[[portfolio](team/fh-30.md)] - +#### Developer and Test Lead +* Ensures the testing of the project is done properly and on time. +* Ensures that code coverage is not compromised even when new features are being added. +* Holds everyone to a high standard of test code. -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +### Joshua Tan -* Role: Team Lead -* Responsibilities: UI + -### Johnny Doe +[[github](http://github.com/joshtyf)] +[[portfolio](team/joshtyf.md)] - +#### Developer and Documentation Lead +* Responsible for the quality of various project documents (eg. README.md, UG, DG). +* Set goals for documenting new features and for improving the quality of existing documentation. +* Review documents for accuracy and style and ensure all publication standards are met. -[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)] +### Gilbert Tan -* Role: Developer -* Responsibilities: Data + -### Jean Doe +[[github](https://github.com/GilbertTan19)] +[[portfolio](team/gilberttan19.md)] - +#### Developer and Code Quality Lead +* Looks after code quality of the entire codebase. +* Ensures adherence to coding standards, javadocs, etc. +* Set up code review process and ensures adherence to good code review practices. -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +### Xingjian Chen -* Role: Developer -* Responsibilities: Dev Ops + Threading + -### James Doe +[[github](https://github.com/ChenXJ98)] +[[portfolio](team/chenxj98.md)] - +#### Developer and Integration Lead +* In charge of versioning of the code, maintaining the code repository, integrating various parts of the software to create a whole. +* Facilitates the merging of code into the production branch. +* Ensures that integration tests are performed properly and on time. -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] -* Role: Developer -* Responsibilities: UI diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 4829fe43011..65170645f07 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -21,13 +21,7 @@ Refer to the guide [_Setting up and getting started_](SettingUp.md). The ***Architecture Diagram*** given above explains the high-level design of the App. Given below is a quick overview of each component. -
- -:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/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. - -
- -**`Main`** has two classes called [`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). It is responsible for, +**`Main`** has two classes called [`Main`](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/java/quickcache/Main.java) and [`MainApp`](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/java/quickcache/MainApp.java). It is responsible for, * At app launch: Initializes the components in the correct sequence, and connects them up with each other. * At shut down: Shuts down the components and invokes cleanup methods where necessary. @@ -43,7 +37,7 @@ The rest of the App consists of four components. Each of the four components, * defines its *API* in an `interface` with the same name as the Component. -* exposes its functionality using a concrete `{Component Name}Manager` class (which implements the corresponding API `interface` mentioned in the previous point. +* exposes its functionality using a concrete `{Component Name} Manager` class (which implements the corresponding API `interface` mentioned in the previous point.) For example, the `Logic` component (see the class diagram given below) defines its API in the `Logic.java` interface and exposes its functionality using the `LogicManager.java` class which implements the `Logic` interface. @@ -62,11 +56,11 @@ The sections below give more details of each component. ![Structure of the UI Component](images/UiClassDiagram.png) **API** : -[`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java) +[`Ui.java`](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/java/quickcache/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. +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `FlashcardListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class. -The `UI` component uses 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 [JavaFx](https://openjfx.io) 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/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/java/quickcache/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/resources/view/MainWindow.fxml) The `UI` component, @@ -78,11 +72,11 @@ The `UI` component, ![Structure of the Logic Component](images/LogicClassDiagram.png) **API** : -[`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java) +[`Logic.java`](https://github.com/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/java/quickcache/logic/Logic.java) -1. `Logic` uses the `AddressBookParser` class to parse the user command. +1. `Logic` uses the `QuickCacheParser` class to parse the user command. 1. This results in a `Command` object which is executed by the `LogicManager`. -1. The command execution can affect the `Model` (e.g. adding a person). +1. The command execution can affect the `Model` (e.g. adding a new flashcard). 1. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. 1. In addition, the `CommandResult` object can also instruct the `Ui` to perform certain actions, such as displaying help to the user. @@ -93,39 +87,34 @@ Given below is the Sequence Diagram for interactions within the `Logic` componen
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
### Model component ![Structure of the Model Component](images/ModelClassDiagram.png) -**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/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/java/quickcache/model/Model.java) The `Model`, * stores a `UserPref` object that represents the user’s preferences. -* stores the address book data. -* exposes an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. +* stores the quick cache flashcard data. +* exposes an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. * does not depend on any of the other three 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` object.
-![BetterModelClassDiagram](images/BetterModelClassDiagram.png) - -
- - +
### Storage component ![Structure of the Storage Component](images/StorageClassDiagram.png) -**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/AY2021S1-CS2103T-T13-2/tp/blob/master/src/main/java/quickcache/storage/Storage.java) The `Storage` component, * can save `UserPref` objects in json format and read it back. -* can save the address book data in json format and read it back. +* can save the QuickCache data in json format and read it back. ### Common classes -Classes used by multiple components are in the `seedu.addressbook.commons` package. +Classes used by multiple components are in the `quickcache.commons` package. -------------------------------------------------------------------------------------------------------------------- @@ -133,224 +122,1605 @@ 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 +The features mentioned are: -#### Proposed Implementation +- [Adding flashcards with open ended questions](#add-flashcard-with-open-ended-question) +- [Adding flashcards with multiple choice questions](#add-flashcard-with-multiple-choice-question) +- [Opening of flashcards](#open-flashcard) +- [Tagging system](#tags) +- [Editing a flashcard](#edit-flashcard) +- [Deleting a flashcard by index](#delete-by-index) +- [Deleting by Tags](#delete-by-tag) +- [Finding flashcards](#find-flashcards) +- [Setting difficulty for flashcards](#difficulty) +- [Displaying statistics of a flashcard](#display-statistics-of-a-flashcard) +- [Displaying statistics of flashcards by tag](#display-statistics-of-flahcards-by-tag) +- [Clearing all flashcards](#clear-all-flashcards) +- [Clearing statistics of a flashcard](#clear-statistics-of-a-flashcard) +- [Testing a flashcard](#test-a-flashcard) +- [Exporting flashcards](#export-flashcards) +- [Importing flashcards](#import-flashcards) -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: +### Add flashcard with open-ended question -* `VersionedAddressBook#commit()` — Saves the current address book state in its history. -* `VersionedAddressBook#undo()` — Restores the previous address book state from its history. -* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history. +#### Implementation +The Add Open Ended Question mechanism is facilitated by `QuickCache`. +The flashcard created is stored internally inside a `UniqueFlashcardList` within the `QuickCache` object. -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. +##### Usage -Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. +The following activity diagram summarizes what happens when a user executes add open ended question command on a specified flashcard: -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. +![AddOpenEndedActivityDiagram](images/AddOpenEndedActivityDiagram.png) -![UndoRedoState0](images/UndoRedoState0.png) +Given below is an example usage scenario and how the mechanism behaves at each step. -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 1. The user launches the application for the first time. `QuickCache` will be initialized with the initial state. -![UndoRedoState1](images/UndoRedoState1.png) +Step 2. The user executes `add q/question...` command to add a flashcard. +The following sequence diagram shows how the input command gets parsed: -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`. +![AddOpenEndedSequenceDiagram](images/AddOpenEndedParserSequenceDiagram.png) -![UndoRedoState2](images/UndoRedoState2.png) +Step 3. This will result in the creation of a flashcard with an open-ended question inside `QuickCache`. -
: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`. +The following sequence diagram shows how the flashcard is added: +![AddOpenEndedSequenceDiagram](images/AddOpenEndedSequenceDiagram.png) + +
:information_source: **Note:** If a command fails its execution, QuickCache will not create the flashcard.
-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. +#### Design considerations + +* **Current implementation:** Flashcard is saved upon creation inside the QuickCache. + * Pros: Easy to implement and CLI-optimized. + * Cons: May be complicated in the future as there will be too many prefixes along with the `add` command. + +### Add flashcard with multiple choice question + +#### Implementation + +The Add Multiple Choice Question mechanism is facilitated by `QuickCache`. +The flashcard created is stored internally inside a `UniqueFlashcardList` within the `QuickCache` object. + +##### Usage -![UndoRedoState3](images/UndoRedoState3.png) +The following activity diagram summarizes what happens when a user executes add multiple choice question command on a specified flashcard: -
: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 -than attempting to perform the undo. +![AddMcqActivityDiagram](images/AddMcqActivityDiagram.png) +Given below is an example usage scenario and how the Add Multiple Choice Question mechanism behaves at each step. + +Step 1. The user launches the application for the first time. `QuickCache` will be initialized with the initial state. + +Step 2. The user executes `addmcq q/question ans/1 c/first c/second` command to add a flashcard. +The following sequence diagram shows how the input is parsed: + +![AddMcqSequenceDiagram](images/AddMcqParserSequenceDiagram.png) + +Step 3. This will result in the creation of a flashcard with an multiple choice question inside `QuickCache`. + +The following sequence diagram shows how flashcard is added: + +![AddMcqSequenceDiagram](images/AddMcqSequenceDiagram.png) + +
:information_source: **Note:** If a command fails its execution, QuickCache will not create the flashcard.
-The following sequence diagram shows how the undo operation works: +#### Design considerations: + +* **Current implementation:** Flashcard is saved upon creation inside the QuickCache. + * Pros: Easy to implement and CLI-optimized. + * Cons: May be complicated in the future as there will be too many prefixes along with the `addmcq` command. + +### Open flashcard + +#### Implementation + +The Open flashcard mechanism will allow the user to open a flashcard specified by the given index and display it in the GUI. +The `OpenCommandParser#parse` takes in a single `String` argument called `index`. It then parses the argument and creates an `Index` object to be passed on to +the `OpenCommand` class instance. If no argument is given, then a `CommandException` will be thrown. + +During execution, the `OpenCommand` class will pass the `Question` to the GUI for it to display the`Question` of the `Flashcard` to the user. +This is be done by passing the `Question` into a `Feedback` object which is an attribute of the `CommandResult` given to the GUI. + +The GUI will change the content of some of its placeholders to display the question and if available, its choices to the user. +The GUI will change the contents of its placeholders accordingly if other commands aside from another `OpenCommand` is called afterwards. + +##### Usage + +The following activity diagram summarizes what happens when a user executes open command on a specified flashcard: + +![OpenFlashcardActivityDiagram](images/OpenFlashcardActivityDiagram.png) + +Given below is an example usage scenario and how the Open mechanism behaves at each step. + +Step 1. The user launches the application for the first time. `QuickCache` will be initialized with the initial state. + +Step 2. The user executes `open 1` command to display the first flashcard in the list on the GUI. + +Step 3. This will call `OpenCommandParser#parse` which will then parse the arguments provided. Within the method, `ParserUtil#parseIndex` will be called to convert the user input to index of the first `Flashcard`. + +Step 4. The `Index` is then passed to the `OpenCommand` during its construction. +The following sequence diagram briefly shows how the parser operation works: + +![OpenParserSequenceDiagram](images/OpenParserSequenceDiagram.png) + +Step 5. `OpenCommand#execute` will get the `Flashcard` at the specified `Index` and get its `Question` to be passed to the GUI as part of the `Feedback` attribute within the `CommandResult`. + +Step 6. The GUI will then proceed to get the `Question` from `Feedback` and display its choices and question to the user. + +The following sequence diagram shows how the Open mechanism works: + +![OpenSequenceDiagram](images/OpenSequenceDiagram.png) + +#### Design considerations: + +* **Current implementation:** Flashcard is taken from the last displayed list + * Pros: Easy to implement and CLI-optimized. + * Cons: *nil* + +### Tags + +#### Implementation + +A `Tag` is stored internally in a `Set` within a `Flashcard` object. +It is is created and added to the flashcard during the parsing stage of an `add` or `addmcq` command. +Multiple tags can be created for each `Flashcard` as well. + +##### Usage + +Given below is an example usage scenario and how the Tag mechanism behaves at each step. + +Step 1. The user launches the application for the first time. `QuickCache` will be initialized with the initial state. + +Step 2. The user executes `add q/question... t/tag` command to add a flashcard with a tag inside QuickCache. + +Step 3. During the execution of `AddOpenEndedQuestionCommandParser#parse` method, `ParserUtil#parseTags` will be called +to parse and create `Tag` objects for each unique tag. This will then be stored in a `Set` called `tagList` + +Step 4. The `Flashcard` will then be constructed containing the `tagList`. + +#### Design considerations: + +* **Current implementation:** Tag is saved within a `Set` within `Flashcard` + * Pros: Easy to implement and doesn't allow for duplicates. + * Cons: Might take very long to search for flashcards with a specified tag especially if there are many flashcards. + +* **Alternative:** Utilise an additional data structure for each individual tag to store flashcards. + * Pros: Easy and fast to find flashcards with a specified tag. + * Cons: Many duplicate copies of flashcards will be created. + +### Edit flashcard + +#### Implementation + +The following activity diagram summarizes what happens when a user executes an edit flashcard command on a specified flashcard: + +![EditActivityDiagram](images/EditActivityDiagram.png) + +The Edit flashcard mechanism operates by editing the flashcard at a specified index of the last displayed list. +The new information is encapsulated inside a `EditFlashcardDescriptor` and is passed together with the `Index` object +to the `EditCommand`. + +During `EditComamnd#execute`, a new `Flashcard` object will be created. For each of its individual content (i.e `Answer`), +if the `EditFlashcardDescriptor` does not have the new information, the old content will be from the original `Flashcard`. + +##### Usage + +Given below is an example usage scenario and how the Edit mechanism behaves at each step. -![UndoSequenceDiagram](images/UndoSequenceDiagram.png) +Step 1. The user executes `edit 1 ans/answer` command to edit the answer field of the first flashcard. -
: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. +Step 2. `EditCommandParser#parse` will then parse the arguments provided. In this example, a new `Answer` object will be +created after parsing. +Step 3. The `Answer` object will then be passed to the `EditFlashcardDescriptor` object. The `EditFlashcardDescriptor` +object together with the original `Flashcard` will be passed to the `EditCommand` object. The following sequence diagram +briefly shows how the parser operation works (`Answer` and `EditFlashcardDescriptor` objects not included): + +![EditSequenceDiagram](images/EditParserSequenceDiagram.png) + +Step 4. The `EditCommand` will then create a new `Flashcard` using information from `EditFlashcardDescriptor`. +In the example, only a new answer is present. All other information will be taken from the original `Flashcard`. + +Step 5. `EditCommand#execute` will then replace the old `Flashcard` in the `model` with the new `Flashcard`. + +The following sequence diagram shows how the Edit mechanism works: + +![EditSequenceDiagram](images/EditSequenceDiagram.png) + +
:information_source: **Note:** If a command fails its execution, it will not be saved in the QuickCache, so the flashcard inside the QuickCache will not be updated.
-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. +#### Design considerations: + +* **Current choice:** Create a new flashcard with all the new information to replace the old flashcard. + * Pros: Maintains immutability. + * Cons: Difficult to implement as a seperate `EditFlashcardDescriptor` class must be implemented as well. + +* **Alternative:** Edit the old flashcard directly. + * Pros: Much easier to implement. + * Cons: If the execution is stopped halfway, then the newly updated flashcard will contain wrong information. It will + be difficult to debug as well. + +### Delete by Index + +#### Implementation + +The Delete By Index mechanism deletes the flashcard at the specified index of the last displayed list. + +##### Usage + +The following activity diagram briefly summarizes what happens when a user executes the delete command to delete +flashcards by tags: + +![DeleteByIndexActivityDiagram](images/DeleteByIndexActivityDiagram.png) + +Given below is an example usage scenario and how the Delete By Index mechanism behaves at each step. + +Step 1. The user launches the application. -
: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. +Step 2. The user executes `delete 1` command to delete the first flashcard. This command will be parsed by `DeleteCommandParser`. +Step 3. `DeleteCommandParser#parse` will then create a `DeleteCommand` which has its `isDeleteByTag` field set to `false`. +`DeleteCommandParser#parse` will also create an `Index` object to be passed to the `DeleteCommand` object. + +Step 4. `DeleteCommand#execute` will then get a copy of the to-be `Flashcard` from the `model` using the `Index` provided. + +Step 5. The `model#deleteFlashcard` will then delete the `Flashcard` by finding for it based on its copy. + +
:information_source: **Note:** If a command fails its execution, it will not be saved in the QuickCache, so the flashcard inside the QuickCache will not be updated.
-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. +The following sequence diagram shows how the Delete By Index mechanism works: + +![DeleteSequenceDiagram](images/DeleteSequenceDiagram.png) + +#### Design considerations: + +* **Current choice:** Delete command works for both index and tags + * Pros: Convenient for the user as there is only one command. + * Cons: Extra checks have to be implemented to make sure that the correct deletion mechanism is executed. + +* **Alternative:** Create a seperate delete command for deleting by tags + * Pros: Less overlapping and easier to debug. + * Cons: Extra work needed to implement the delete command. + +### Delete by Tag + +#### Implementation + +The Delete By Tag mechanism will delete flashcards specified by a given set of tags. Any flashcard containing +all of the specified tags will be deleted. + +It works by filtering for the flashcards in the `model` and deleting them one by one. + +##### Usage + +The following activity diagram briefly summarizes what happens when a user executes the delete command to delete +flashcards by tags: + +![DeleteByTagActivityDiagram](images/DeleteByTagActivityDiagram.png) + +Given below is an example usage scenario and how the Delete By Tag mechanism behaves at each step. + + Step 1. The user launches the application. + + Step 2. The user executes `delete t/MCQ` command to delete all flashcards with the tag `MCQ`. + + Step 3. This will call `DeleteCommandParser#parse` which will then parse the arguments provided. + Within `DeleteCommandParser#parse`, `ParserUtil#parseTags` will be called to create a `FlashcardPredicate` using the tags. + + Step 4. A new `DeleteCommand` object will be created with its `isDeleteByTag` field set to `true`. The `FlashcardPredicate` + will also be passed to the `DeleteCommand` object. + The following sequence diagram briefly shows how the parser operation works (`FlashcardPredicate` not shown): + + ![DeleteByTagParserSequenceDiagram](images/DeleteByTagParserSequenceDiagram.png) + + Step 5. `DeleteCommand#execute` will filter the `QuickCache` model with the provided predicate and get back the filtered list + + Step 6. It will then iterate through the list and call `QuickCache#deleteFlashcard` on each `Flashcard` in the list. + +The following sequence diagram shows how the Delete By Tag mechanism works: + +![DeleteByTagSequenceDiagram](images/DeleteByTagSequenceDiagram.png) + +#### Design considerations: + +* **Current choice:** Delete command works for both index and tags + * Pros: Convenient for the user as there is only one command. + * Cons: Extra checks have to be implemented to make sure that the correct deletion mechanism is executed. + +* **Alternative:** Create a seperate delete command for deleting by tags + * Pros: Less overlapping and easier to debug. + * Cons: Extra work needed to implement the delete command. + +### Find flashcards + +#### Implementation + +The following activity diagram summarizes what happens when a user executes a find flashcard command with both a keyword and tag query: + +![FindActivityDiagram](images/FindActivityDiagram.png) + +The Find mechanism searches for flashcards based on the specified tag or question keyword or both. +Each filter will result in the creation of a `Predicate`. +A class called `FlashcardPredicate` will be introduced that collects all `Predicate` into one class. + +##### Usage + +Given below is an example usage scenario and how the Find mechanism behaves at each step. + +Step 1. The user launches the application. + +Step 2. The user executes `find t/Assembly q/What` command to find a `Flashcard` with the tag `Assembly` and the keyword `What` in its `Question`. + +Step 3. This will call `FindCommandParser#parse` which will then parse the arguments provided. +Within the method, `ParserUtil#parseTags`and `Parserutil#parseKeywords` will be called to create tags and keywords for the arguments. + +Step 4. A new `FlashcardPredicate` will then be created from the `QuestionContainsKeywordsPredicate` and `FlashcardContainsTagPredicate` generated from the given tags and keywords. +It will be used to filter for all the flashcards that have the specified tags. This `FlashcardPredicate` is then passed to the `FindCommand` +The following sequence diagram shows how the parser operation works: + +![FindParserSequenceDiagram](images/FindParserSequenceDiagram.png) + + Step 5. `FindCommand#execute` will set the `QuickCache` model's filter with the provided predicate. + + Step 6. The GUI will then proceed to get the filtered list based on the newly set predicate to display to the user. + + Step 7. After execution, `CommandResult` will contain a message indicating that it has listed all `Flashcards` based on the specified restrictions. + + The following sequence diagram shows how the Find mechanism works: + +![FindSequenceDiagram](images/FindSequenceDiagram.png) + +#### Design considerations + +* **Current choice:** Use a `FlashcardPredicate` to filter for the `Flashcard`s. + * Pros: `FlashcardPredicate` can be extended to be used for other operations. + * Cons: Multiple predicates will have be created if more search fields are used. + +### Difficulty + +#### Implementation -![UndoRedoState4](images/UndoRedoState4.png) +The Difficulty mechanism is facilitated by storing a `Difficulty` object inside a `Flashcard` object. -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 `Difficulty` class takes difficulty levels from `Difficulties` enums which contains four difficulty levels `LOW`, `MEDIUM`, `HIGH` and `UNSPECIFIED`. -![UndoRedoState5](images/UndoRedoState5.png) +##### Usage -The following activity diagram summarizes what happens when a user executes a new command: +Given below is an example usage scenario and how the Difficulty mechanism behaves at each step. -![CommitActivityDiagram](images/CommitActivityDiagram.png) +Step 1. The user launches the application. -#### Design consideration: +Step 2. The user executes `add q/question... d/difficultyLevel` command to add a flashcard with difficulty. +If the user executes `add q/question...` command without `d/` prefix. +The `add` command will cause the addition of a flashcard with a difficulty set to `UNSPECIFIED` inside the QuickCache. -##### Aspect: How undo & redo executes +Step 3. The user executes `edit 1 d/difficultyLevel` to edit the difficulty in the first flashcard of the list. +The edit command will change the internal structure of flashcard such that the `Difficulty` is updated. -* **Alternative 1 (current choice):** Saves the entire address book. +#### Design considerations: + +* **Current choice:** Difficulty is saved upon creation. * Pros: Easy to implement. - * Cons: May have performance issues in terms of memory usage. + * Cons: May be complicated as there will be too many fields in the `add` command. -* **Alternative 2:** Individual command knows how to undo/redo by +* **Alternative:** Individual command knows how to add difficulty by itself. - * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). - * Cons: We must ensure that the implementation of each individual command are correct. + * Pros: Will be less complicated. + * Cons: There may be too many commands which can be combined to one. -_{more aspects and alternatives to be added}_ -### \[Proposed\] Data archiving +### Test a flashcard -_{Explain here how the data archiving feature will be implemented}_ +#### Implementation +The Test mechanism is facilitated by `Flashcard`. Specifically, `Statistics` stored within the flashcard. `Flashcard` implements the following methods. +* `Flashcard#getFlashcardAfterTestSuccess()` — Returns a new `Flashcard` object with `Statistics:timesTested` and `Statistics:timesTestedCorrect` incremented by one. +* `Flashcard#getFlashcardAfterTestFailure()` — Returns a new `Flashcard` object with `Statistics:timesTested` incremented by one. --------------------------------------------------------------------------------------------------------------------- +##### Usage -## **Documentation, logging, testing, configuration, dev-ops** +Given below is an example usage scenario and how the Test mechanism behaves at each step. -* [Documentation guide](Documentation.md) -* [Testing guide](Testing.md) -* [Logging guide](Logging.md) -* [Configuration guide](Configuration.md) -* [DevOps guide](DevOps.md) +Step 1. The user launches the application. The `Flashcard` to be tested will be initialized with the initial flashcard state. --------------------------------------------------------------------------------------------------------------------- +![TestState0](images/TestState0.png) -## **Appendix: Requirements** +Step 2. The user tests the flashcard with a specified `answer` or `option`. -### Product scope +Step 2a. The user executes `test 1 ans/correct answer` command to test the `Flashcard`. The `test` command calls `Flashcard#getFlashcardAfterTestSuccess()`, and replaces the previously tested flashcard with the newly updated flashcard, changing its state. -**Target user profile**: +![TestState1](images/TestState1.png) -* 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 +Step 2b. The user executes `test 1 ans/wrong answer` command to test the `Flashcard`. The `test` command calls `Flashcard#getFlashcardAfterTestFailure()`, and replaces the previously tested flashcard with the newly updated flashcard, changing its state. -**Value proposition**: manage contacts faster than a typical mouse/GUI driven app +![TestState2](images/TestState2.png) +The following sequence diagram shows how the Test mechanism works: -### User stories +![TestSequenceDiagram](images/TestSequenceDiagram.png) -Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` +The following sequence diagram shows how the input get parsed: -| 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 | +![TestParserSequenceDiagram](images/TestParserSequenceDiagram.png) -*{More to be added}* +The following activity diagram summarizes what happens when a user executes a test command on a specified flashcard: -### Use cases +![TestActivityDiagram](images/TestActivityDiagram.png) -(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise) +#### Design considerations: -**Use case: Delete a person** +* **Current choice:** Increments a counter of `timesTestedCorrect` and `timesTested` in `Statistics`. + * Pros: Easy to implement. + * Cons: Unable to keep track of useful information such as performance over time. -**MSS** +* **Alternative:** `Statistics` is made up of an `Array` of `test`, including information such as `timestamp` + * Pros: Retrieval of useful statistics will be possible. + * Cons: Save file will expand very quickly because each `test` record needs to be logged. -1. User requests to list persons -2. AddressBook shows a list of persons -3. User requests to delete a specific person in the list -4. AddressBook deletes the person +### Display statistics of a flashcard - Use case ends. +#### Implementation -**Extensions** +The Display mechanism will allow the user to view a Pie Chart of the statistics of the Flashcard specified by the given index and display it in the GUI. -* 2a. The list is empty. +The implementation requires the creation of a `StatsCommandParser` and a `StatsCommand`. The `StatsCommandParser#parse` will take in a single argument for `Index`. After parsing the argument, it will then proceed to create a `StatsCommand` class instance. If no `Index` is given then a `CommandException` will be thrown. - Use case ends. +The `StatsCommand` class will have to pass the `Statistics` to the GUI for it to display the `Statistics` of the `Flashcard` to the user. This will be done by passing the `Statistics` into a `Feedback` object which is an attribute of the `CommandResult` given to the GUI. -* 3a. The given index is invalid. +The GUI will change the content of some of its placeholders to display the `Statistics` as a Pie Chart. The GUI will change the contents of its placeholders accordingly if other commands aside from another `StatsCommand` is called afterwards. - * 3a1. AddressBook shows an error message. +##### Usage - Use case resumes at step 2. +The following activity diagram summarizes what happens when a user executes stats command on a specified flashcard: -*{More to be added}* +![StatsActivityDiagram](images/StatsActivityDiagram.png) -### Non-Functional Requirements +Given below is an example usage scenario and how the Displaystats mechanism behaves at each step. -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. +Step 1. The user launches the application after a few times of using the `TestCommand` feature. The `QuickCache` will be initialized with the existing QuickCache state. -*{More to be added}* +Step 2. The user executes `stats 1` command to display the `Statistics` of the first flashcard in the list on the GUI. -### Glossary +Step 3. This will call `StatsCommandParser#parse` which will then parse the arguments provided. Within the method, `ParserUtil#parseIndex` will be called to convert the user input into the `Index` of the first `Flashcard`. -* **Mainstream OS**: Windows, Linux, Unix, OS-X -* **Private contact detail**: A contact detail that is not meant to be shared with others +Step 4. The `index` is then passed to the `StatsCommand`. +The following sequence diagram shows how the parser operation works: --------------------------------------------------------------------------------------------------------------------- +![StatsParserSequenceDiagram](images/StatsParserSequenceDiagram.png) -## **Appendix: Instructions for manual testing** +Step 5. `StatsCommand#execute` will get the `Flashcard` at the specified `Index` and get its `Statistics` to be passed to the GUI as part of the `Feedback` attribute within the `CommandResult`. -Given below are instructions to test the app manually. +Step 6. The GUI will then proceed to get the `Statistics` from `Feedback` and display its data in the form of a Pie Chart to the user. -
:information_source: **Note:** These instructions only provide a starting point for testers to work on; -testers are expected to do more *exploratory* testing. +The following sequence diagram shows how the Displaystats mechanism works: -
+![StatsSequenceDiagram](images/StatsSequenceDiagram.png) -### Launch and shutdown +#### Design Considerations: -1. Initial launch +* **Current choice:** Passes the `Statistics` object to the GUI in `Feedback` which is an attribute of `CommandResult`. + * Pros: Provides more abstraction as all of the data the GUI needs to display are in the `Feedback` object. + * Cons: There is a violation of Demeter's law as GUI interacts with an attribute of `CommandResult`. - 1. Download the jar file and copy into an empty folder +* **Alternative:** Do not use the `Feedback` object. Place all the data in the `CommandResult` object directly. + * Pros: Demeter's law is no longer violated. + * Cons: There is less abstraction. + +### Display statistics of flashcards by tag + +#### Implementation + +The Display stats by tag mechanism will allow the user to view a Pie Chart of the aggregated statistics of flashcards specified by a given set of tags. Any flashcard that contains all the specified tags will have their statistics aggregated. + +It works by filtering for the flashcards in the `model` and aggregating their statistics using `StatsCommand:getAggregatedStatistics`. + +##### Usage + +The following activity diagram summarizes what happens when a user executes stats command with a set of specified tags: + +![StatsByTagActivityDiagram](images/StatsByTagActivityDiagram.png) + +Given below is an example usage scenario and how the Displaystats mechanism behaves at each step. + +Step 1. The user launches the application after a few times of using the `TestCommand` feature. The `QuickCache` will be initialized with the existing QuickCache state. + +Step 2. The user executes `stats t/MCQ` command to display the aggregated `Statistics` of all flashcards with the tag `MCQ`. + +Step 3. This will call `StatsCommandParser#parse` which will then parse the arguments provided. Within `StatsCommandParser#parse`, `ParserUtil#parseTags` will be called to create a `FlashcardPredicate` using the tags. + +Step 4. The `FlashcardPredicate` is then passed to the `StatsCommand`. +The following sequence diagram shows how the parser operation works: + +![StatsByTagParserSequenceDiagram](images/StatsByTagParserSequenceDiagram.png) + +Step 5. `StatsCommand#execute` will filter the `QuickCache` model with the provided predicate and get back the filtered list. + +Step 6. The filtered list will have their statistics aggregated through the `StatsCommand:getAggregatedStatistics`. + +Step 7. The aggregated `Statistics` will be passed to the GUI as part of the `Feedback` attribute within the `CommandResult`. + +Step 8. The GUI will then proceed to get the `Statistics` from `Feedback` and display its data in the form of a Pie Chart to the user. + +The following sequence diagram shows how the Display stats by tag mechanism works: + +![StatsByTagSequenceDiagram](images/StatsByTagSequenceDiagram.png) + +#### Design Considerations: + +* **Current choice:** Passes the `Statistics` object to the GUI in `Feedback` which is an attribute of `CommandResult`. + * Pros: Provides more abstraction as all of the data the GUI needs to display are in the `Feedback` object. + * Cons: There is a violation of Demeter's law as GUI interacts with an attribute of `CommandResult`. + +* **Alternative:** Do not use the `Feedback` object. Place all the data in the `CommandResult` object directly. + * Pros: Demeter's law is no longer violated. + * Cons: There is less abstraction. + +### Clear all flashcards + +#### Implementation + +The following activity diagram summarizes what happens when a user executes the clear command in QuickCache. + +![ClearActivityDiagram](images/ClearActivityDiagram.png) + +The Clear mechanism will allow the user to delete all flashcards in his local QuickCache. + +The implementation makes use of the `Model#setQuickCache` and `QuickCache`. A new instance of `QuickCache` without any existing flashcards will replace the users current `QuickCache` in `Model`. + +##### Usage + +Given below is an example usage scenario and how the Clear mechanism behaves at each step. + +Step 1. The user executes `clear` command to clear all flashcards in his local QuickCache. - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. +Step 2. `ClearCommand#execute` will replace the current instance of `QuickCache` with a new empty instance of `QuickCache` through the `Model#setQuickCache` method. -1. Saving window preferences +Step 3. After execution, `CommandResult` will contain a message indicating that it has cleared QuickCache. - 1. Resize the window to an optimum size. Move the window to a different location. Close the window. +The following sequence diagram shows how the Clear mechanism works: - 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. +![ClearSequenceDiagram](images/ClearSequenceDiagram.png) -1. _{ more test cases …​ }_ +#### Design Considerations: -### Deleting a person +* **Current choice:** Replaces the existing `QuickCache` in model with a new `QuickCache` that is empty. + * Pros: Easy to implement - minimizes the occurence of bugs. + * Cons: Waste of resources as a new `QuickCache` instance needs to be created when a user wants to clear QuickCache. -1. Deleting a person while all persons are being shown +### Clear statistics of a flashcard - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. +#### Implementation - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. +The Clearstats mechanism will allow the user to reset the statistics of the flashcard specified by the given index. - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. +The implementation requires the creation of a `ClearStatsCommandParser` and a `ClearStatsCommand`. The `ClearStatsCommandParser#parse` will take in a single argument for `Index`. After parsing the argument, it will then proceed to create a `ClearStatsCommand` class instance. If no `Index` is given then a `CommandException` will be thrown. - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. +The `ClearStatsCommand` class will replace the `Flashcard` at the specified `Index` with a copy of the original `Flashcard` that has its `Statistics` reset to zero for all fields. -1. _{ more test cases …​ }_ +##### Usage + +The following activity diagram summarizes what happens when a user executes clearstats command on a specified flashcard: + +![ClearStatsActivityDiagram](images/ClearStatsActivityDiagram.png) + +Given below is an example usage scenario and how the Clearstats mechanism behaves at each step. + +Step 1. The user launches the application after a few times of using the `TestCommand` feature. The `QuickCache` will be initialized with the existing QuickCache state. + +Step 2. The user executes `stats 1` command to display the `Statistics` of the first flashcard in the list on the GUI. The user sees that the `Statistics` has values that are not zero. + +Step 3. The user executes `clearstats 1` command to clear the `Statistics` of the first flashcard in the list on the GUI. + +Step 4. This will call `ClearStatsCommandParser#parse` which will then parse the arguments provided. Within the method, `ParserUtil#parseIndex` will be called to convert the user input into the `Index` of the first `Flashcard`. + +Step 5. The `index` is then passed to the `ClearStatsCommand`. +The following sequence diagram shows how the parser operation works: + +![ClearStatsSequenceDiagram](images/ClearStatsParserSequenceDiagram.png) + +Step 6. `ClearStatsCommand#execute` will get the `Flashcard` at the specified `Index` and call `ClearStatsCommand#getFlashcardAfterClearStatistics` which will give a copy of the original `Flashcard` with its `Statistics` reset to zero for all fields. The original `Flashcard` will then be replaced by the new `Flashcard` copy. + +Step 7. After execution, `CommandResult` will contain a message indicating that it has cleared the `Statistics` of the `Flashcard` on the specified index. + +Step 7. The user executes `stats 1` command to display the `Statistics` of the first flashcard in the list on the GUI. The user sees that the `Statistics` is reset. + +The following sequence diagram shows how the Clearstats mechanism works: + +![ClearStatsSequenceDiagram](images/ClearStatsSequenceDiagram.png) + +#### Design Considerations: + +* **Current choice:** Replaces the existing `Flashcard` with a new `Flashcard` that has a new `Statistics` with all attributes set at zero. + * Pros: `Flashcard` and `Statistics` are easier to debug. + * Cons: Waste of resources as new `Flashcard` and `Statistics` objects need to be created when a user wants to clear its statistics. + +* **Alternative:** Edit the `Statistics` of the `Flashcard` directly + * Pros: No "unnecessary" creation of a new `Flashcard` and `Statistics` object when a user requests to clear its statistics. + * Cons: `Flashcard` and `Statistics` become difficult to debug. + +### Export flashcards + +#### Implementation + +The Export mechanism is facilitated by `Storage` and `QuickCache`. `Storage` is used to interact with the users local data, and a new `QuickCache` containing the data to be exported is passed to `Storage` to save to local data. + +##### Usage + +Given below is an example usage scenario and how the Export mechanism behaves at each step. + +Step 1. The user inputs the `find t/cs2100` command to find all `Flashcard` containing the tag `cs2100`. The `Model` updates its current filtered flashcard list. + +Step 2. The user inputs the `export out.json` command. The following sequence diagram shows how the input command gets parsed: + +![ExportParserSequenceDiagram](images/ExportParserSequenceDiagram.png) + +Step 3. The parsed `Export` command is executed. The current filtered flashcard list is exported to `out.json`, located in the `/export/` directory. + +The following sequence diagram shows how the Export mechanism works as a whole: + +![ExportSequenceDiagram](images/ExportSequenceDiagram.png) + +The following activity diagram summarizes what happens when a user executes an `Export` command: + +![ExportActivityDiagram](images/ExportActivityDiagram.png) + +#### Design considerations: + +* **Current choice:** Predefined directory of `/export/` + * Pros: Easy to implement. + * Cons: The user will have to navigate to his `/export/` folder to retrieve output file. + +* **Alternative:** User specifies which directory to save the export file to. + * Pros: More control over where the export file will end up at. + * Cons: Difficult to implement. + * Cons: Command becomes more complicated as the entire path needs to be typed out. + +### Import flashcards + +#### Implementation + +The Import mechanism is similarly facilitated by `Storage` and `QuickCache`. `Storage` is used to interact with the users local data, and a new `QuickCache` containing the data to be imported is read by `Storage` from local data. + +##### Usage + +Given below is an example usage scenario and how the Import mechanism behaves at each step. + +Step 1. The user places the file `in.json` that he wants to import in his `/import/`folder. + +Step 2. The user inputs the `import in.json` command. The following sequence diagram shows how the input command gets parsed: + +![ImportParserSequenceDiagram](images/ImportParserSequenceDiagram.png) + +Step 3. The parsed `Import` command is executed. The flashcards from the file `in.json` is imported into his local `QuickCache`. If a flashcard has been imported before, it will not be imported again. The check for repitive flashcards is carried out using `Model#hasFlashcard` and `Flashcard#equals`. + +The following sequence diagram shows how the Import mechanism works as a whole: + +![ImportSequenceDiagram](images/ImportSequenceDiagram.png) + +The following activity diagram summarizes what happens when a user executes an `Import` command: + +![ImportActivityDiagram](images/ImportActivityDiagram.png) + +#### Design considerations: + +* **Current choice:** Predefined directory of `/import/` + * Pros: Easy to implement. + * Cons: The user will have to navigate to his `/import/` folder to a place the input file in it. + +* **Alternative:** User specifies which directory to save the export file to. + * Pros: More control over where the import file can be from e.g. user's download folder. + * Cons: Difficult to implement. + * Cons: Command becomes more complicated as the entire path needs to be typed out. + + +-------------------------------------------------------------------------------------------------------------------- + +## **Documentation, logging, testing, configuration, dev-ops** + +* [Documentation guide](Documentation.md) +* [Testing guide](Testing.md) +* [Logging guide](Logging.md) +* [Configuration guide](Configuration.md) +* [DevOps guide](DevOps.md) + +-------------------------------------------------------------------------------------------------------------------- + +## **Appendix: Requirements** + +### Product scope + +**Target user profile**: + +* Students with many modules who want to memorize points +* Prefer desktop apps over other types +* Prefers typing to mouse interactions +* Is reasonably comfortable using CLI apps +* Wants to monitor his/her progress + +**Value proposition**: manage flashcards faster than a typical mouse/GUI driven app with +a test feature and track the progress later. + + +### 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 | +| `* * *` | new user | have a get started | see the features available in the app | +| `* * *` | new user | have a sample data | explore more about the app | +| `* * *` | new user | purge all current data | delete the sample data for exploring the app | +| `* * *` | user | add a new flashcard | | +| `* * *` | user | delete a flashcard | remove flashcards that I no longer need | +| `* *` | user | find a flashcard by name | locate details of flashcards without having to go through the entire list | +| `* *` | user | edit a flashcard | | +| `* *` | user | quiz myself | memorize things better | +| `* *` | user | organize my flashcard | | +| `* *` | user | categorize my flashcards | easily find the flashcard associated with the category | +| `* *` | user | import a set of flashcard | easily add new category of flashcard | +| `* *` | user | export a set of flashcard | easily transfer a category of flashcard | +| `*` | user who has created many flashcards | delete a category of flashcard | easily transfer a category of flashcard | +| `*` | user with many flashcards in the list | specify the importance | | +| `*` | user | randomize the question | test myself better | +| `*` | user | get the statistic of quiz | get a visualisation form of my performance | +| `*` | user | track the progress | know what I have done when using the app | + +### Use cases + +For all use cases below, the **System** is the `QuickCache` and the **Actor** is the `user`, unless specified otherwise. + +**Use case: UC01 - Explore QuickCache** + +**MSS** + +1. User double clicks on QuickCache.jar +2. QuickCache opens and shows a list of flashcards +3. User plays around with QuickCache features to familiarize with them +4. User purges all "get started" data + + Use case ends. + +**Extensions** + +* 1a. Error message indicating that QuickCache.jar cannot be opened pops up. + + * 1a1. User opens up CLI in the directory containing QuickCache and runs `java -jar QuickCache.jar`. + + Use case resumes at step 2. + +* 3a. User wants to know all the available commands present in QuickCache. + + * 3a1. User requests for all the instructions available in QuickCache. + + * 3a2. QuickCache displays all available commands. + + Use case resumes at step 3. + + +**Use case: UC02 - View statistics of a flashcard** + +**Preconditions: User has QuickCache open.** + +**MSS** + +1. User requests for statistics of a flashcard +2. QuickCache displays statistics of the flashcard +3. User tests himself with the same flashcard (UC05) +4. User requests for statistics of the flashcard +5. QuickCache displays updated statistics of the flashcard + + Use case ends. + +**Extensions** + +* 1a. The given index is invalid. + + * 1a1. QuickCache shows an error message. + + Use case resumes at step 1. + + +**Use case: UC03 - Delete a flashcard** + +**Preconditions: User has QuickCache open.** + +**MSS** + +1. User requests to list flashcards +2. QuickCache shows a list of flashcards +3. User requests to delete a specific flashcard in the list +4. QuickCache deletes the flashcard +5. QuickCache updates flashcard save file (UC09) + + Use case ends. + +**Extensions** + +* 2a. The list is empty. + + Use case ends. + +* 3a. The given index is invalid. + + * 3a1. QuickCache shows an error message. + + Use case resumes at step 2. + +**Use case: UC04 - Delete multiple flashcards** + +**Preconditions: User has QuickCache open.** + +**MSS** + +1. User requests to list flashcards +2. QuickCache shows a list of flashcards +3. User requests to delete all flashcards with a specified tag +4. QuickCache deletes all flashcards that contains the specified tag +5. QuickCache updates flashcard save file (UC07) +6. QuickCache displays a message indicating that all flashcards with the specified tag has been deleted +7. QuickCache updates flashcard save file (UC09) + + Use case ends. + +**Use case: UC05 - Create a flashcard with open ended question** + +**Preconditions: User has QuickCache open.** + +**MSS** + +1. User requests to add a flashcard +2. QuickCache adds it to the list +3. QuickCache updates flashcard save file (UC09) +4. User requests to list flashcards +5. QuickCache shows the list of flashcards including the recently added flashcard + + Use case ends. + +**Extensions** + +* 1a. The question is empty. + + * 1a1. QuickCache shows an error message. + + Use case ends. + +* 1b. The answer is empty. + + * 1b1. QuickCache shows an error message. + + Use case ends. +* 1c. User provided more than one question or answer + + * 1c1. QuickCache shows an error message. + + Use case ends. + + +**Use case: UC06 - Create a flashcard with Multiple choice question** + +**Preconditions: User has QuickCache open.** + +**MSS** + +1. User requests to add a flashcard +2. QuickCache adds it to the list +3. QuickCache updates flashcard save file (UC09) +4. User requests to list flashcards +5. QuickCache shows the list of flashcards including the recently added flashcard + + Use case ends. + +**Extensions** + +* 1a. The question is empty. + + * 1a1. QuickCache shows an error message. + + Use case ends. + +* 1b. The answer is empty. + + * 1b1. QuickCache shows an error message. + + Use case ends. + +* 1c. The choices are empty. + + * 1c1. QuickCache shows an error message. + + Use case ends. + +* 1d. User provided more than one question or answer + + * 1d1. QuickCache shows an error message. + + Use case ends. + + +**Use case: UC07 - Test a single flashcard** + +**MSS:** + +1. User requests to list flashcards +2. QuickCache shows a list of flashcards +3. User requests to test a specific flashcard in the list with a specific answer +4. QuickCache displays whether the answer is correct +5. QuickCache updates the statistics for that flashcard + + Use case ends. + +**Extensions:** + +* 2a. The list is empty. + + Use case ends. + +* 3a. The given index is invalid. + + * 3a1. QuickCache shows an error message. + + Use case resumes at step 2. + + +**System: QuickCache** + +**Use case: UC08 - Test a set of flashcards by category** + +MSS: + +1. User requests to list categories +2. QuickCache shows a list of categories +3. User requests to test a specific category in the list +4. User
    tests each flashcard on the list (UC07) +5. QuickCache shows the number of successful questions at the end + + Use case ends. + +**Extensions:** + +* 2a. The list is empty. + + Use case ends. + +* 3a. The given index is invalid. + + * 3a1. QuickCache shows an error message. + + Use case resumes from step 2. + +* 3b. The user specifies a time limit. + + * 3b1. QuickCache starts a timer. + + Use case resumes from step 4. + +* 3c. The user specifies to randomly sort the questions. + + * 3c1. QuickCache randomizes the flashcards from the category. + + Use case resumes from step 4. + +* 4a. The user answers the question. + + * 4a1. QuickCache shows the next question to answer. + + * Step 4a. is repeated until all questions in the category is answered. + + Use case resumes from step 5. + +* 4b. The user cancels the test midway. + + Use case resumes from step 5. + +* 4c. The user runs out of time midway. + + Use case resumes from step 5. + +* 4d. The user closes QuickCache + + Use case ends. + + + +**Use case: UC09 - Update flashcard save file** + +**Actor: QuickCache** + +MSS: + +1. QuickCache accepts update request +2. QuickCache updates save file + + Use case ends. + +**Extensions:** + +* 2a. No save file. + + * 3a1. QuickCache creates new save file. + + Use case resumes from step 2. + +* 2b. Save file corrupted. + + * 2b1. QuickCache shows an error message. + + * 2b2. QuickCache creates new save file. + + Use case resumes from step 2. + + +**Use case: UC10 - Import flashcard data file** + +MSS: + +1. User specifies the file name containing the set of flashcards to import from +2. QuickCache imports each flashcard from the file + + Use case ends. + +**Extensions:** + +* 1a. File not found. + + * 1a1. QuickCache shows an error message. + + Use case ends. + +* 1b. Data file corrupted. + + * 1b1. QuickCache shows an error message. + + Use case ends. + +* 2a. Duplicate flashcard found. + + * 2a1. QuickCache ignores the duplicate flashcard. + + Use case resumes from step 3. + + +**Use case: UC11 - Add tags during creation of a flashcard** + +MSS: + +1. User creates a flashcard and specifies the tags associated with it +2. QuickCache creates the flashcards and adds the tags to it + + Use case ends. + +**Extensions** + +* 1a. The tags are invalid. + + * 1a1. QuickCache shows an error message. + + Use case ends. + +**Use case: UC12 - Edit an existing flashcard** + +MSS: + +1. User wants to edit an existing flashcard +2. User enters new information pertaining to the flashcard fields he wants to update +4. QuickCache edits the flashcard with the new information +5. QuickCache updates flashcard save file (UC09) + + Use case ends. + +**Extensions** + +* 1a. The list is empty. + + Use case ends. + +* 2a. The given index in invalid. + + * 2a1. QuickCache shows an error message. + + Use case resumes at step 2. + +* 2b. User provides no field to edit. + + * 2b1. QuickCache shows an error message. + + Use case resumes at step 2. + +* 3b. There is no change in the flashcard or the newly edited flashcard is the same as another flashcard. + + * 3b1. QuickCache shows an error message. + + Use case resumes at step 2. + +**Use case: UC13 - Search for flashcards based on tags and/or question** + +**MSS** + +1. User enters the tags and/or keywords in the question associated with the flashcard he wants to search for +2. QuickCache filters all existing flashcards based on the tag and/or keywords. +3. Quickcache displays all the requested flashcards to the user. + + Use case ends. + + +**Use case: UC14 - Open a single flashcard** + +**MSS** + +1. QuickCache opens and shows a list of flashcards +2. User forgets the choices of a flashcard's question +3. User requests to open a specific flashcard in the list +4. QuickCache opens the flashcard and displays the choices + + Use case ends. + +**Extensions** + +* 4a. The given index is invalid. + + * 4a1. QuickCache shows an error message. + + Use case resumes at step 3. + +**Use case: UC15 - Clear statistics of a flashcard** + +**MSS** + +1. User requests for statistics of a flashcard +2. QuickCache displays statistics of the flashcard +3. User clears the statistics of the flashcard +4. User requests for statistics of the flashcard +5. QuickCache displays statistics, that has been reset, of the flashcard + + Use case ends. + +**Extensions** + +* 1a. The given index is invalid. + + * 1a1. QuickCache shows an error message. + + Use case resumes at step 1. + +**Use case: UC16 - Export flashcard data file** + +MSS: + +1. User requests to list flashcards +2. QuickCache shows a list of flashcards +3. User specifies the file name to export the displayed list of flashcards +4. QuickCache exports displayed the list of flashcards into the specified file + + Use case ends. + +**Extensions:** + +* 3a. Invalid file name. + + * 3a1. QuickCache shows an error message. + + Use case ends. + +**Use case: UC17 - Add difficulty during creation of a flashcard** + +MSS: + +1. User creates a flashcard and specifies the difficulty level associated with it +2. QuickCache creates the flashcards and adds the difficulty level to it + + Use case ends. + +**Extensions** + +* 1a. The difficulty level is invalid. + + * 1a1. QuickCache shows an error message. + + Use case ends. + +**** +### 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 flashcards 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. + +### Glossary + +* **Mainstream OS**: Windows, Linux, Unix, OS-X +* **Private contact detail**: A contact detail that is not meant to be shared with others + +-------------------------------------------------------------------------------------------------------------------- + +## **Appendix: Instructions for manual testing** + +Given below are instructions to test the app manually. + +
    + +:information_source: **Note:** These instructions only provide a starting point for testers to work on; +testers are expected to do more *exploratory* testing. + +
    + +### 1. Launch and shutdown + +1. Initial launch + + 1. Download the jar file and copy into an empty folder + + 1. Double-click the jar file
    + Expected: Shows the GUI with a set of sample flashcards. The window size may not be optimum but can be adjusted. + +1. Shutdown after adding flashcards into QuickCache + + 1. Type `exit` to exit the application + + 1. Re-launch the app by double-clicking the jar file
    + Expected: The data of all the flashcards is retained. + +### 2. Creating a flashcard + +User can create two types of flashcards - containing open end question or multiple choice question. + +1. Creating a flashcard with open ended question + + 1. Prerequisites: The flashcard you are creating should not already be in QuickCache. + + 1. Test Case 1: `add q/Test OEQ 1 ans/Test ans 1`
    + Expected: The flashcard with the specified parameters will be added to the list of flashcards. The details of the question will be shown in the display window on the side. + + 1. Test Case 2: `add q/Test OEQ 2 ans/Test ans 2 t/OEQ t/test d/LOW`
    + Expected: The flashcard with the specified parameters will be added to the list of flashcards together with its two tags `OEQ`, `test` and difficulty level `LOW` shown. The details of the question will be shown in the display window on the side. + + 1. Test Case 3: `add q/Test OEQ 1 ans/Test ans 1`
    + Expected: QuickCache responds with an error message indicating that the flashcard already exists (added in Test Case 1). Flashcard is not added. + + 1. Test Case 4: `add q/Test OEQ 1 ans/Test ans 1 t/Invalid Tag`
    + Expected: QuickCache responds with an error message indicating that tag field is invalid. Flashcard is not added.
    +
    + + :information_source: Note that flashcards containing similar questions and answers but different tags are treated as different flashcards. + +
    + + 1. Test Case 5: `add q/Test OEQ 1 ans/Test ans 1 d/Invalid Difficulty`
    + Expected: QuickCache responds with an error message indicating that difficulty field is invalid. Flashcard is not added.
    +
    + + :information_source: Note that flashcards containing similar questions and answers but different difficulty are treated as different flashcards. + +
    + 1. Some incorrect `add` commands with missing fields to try: `add`, `add q/ ans/Test ans 1`, `add q/Test OEQ 1 ans/`, `add q/Test OEQ 1 ans/Test ans 1 t/`
    + Expected: QuickCache responds with an error message and no flashcard is added.
    +
    + + :information_source: Empty field for difficulty `d/` is accepted and flashcard difficulty is set to unspecified. + +
    + 1. Some incorrect `add` commands with duplicate prefix to try: `add q/Test OEQ 1 q/Test OEQ 2 ans/Test ans 1`, `add q/Test OEQ 1 ans/Test ans 1 ans/Test ans 2`, `add q/Test OEQ 1 ans/Test ans 1 d/LOW d/HIGH`
    + Expected: QuickCache responds with an error message and no flashcard is added. + +1. Creating a flashcard with multiple choice question + + 1. Prerequisites: The flashcard you are creating should not already be in QuickCache. + + 1. Test Case 1: `addmcq q/Test MCQ 1 ans/1 c/Choice1 c/Choice2`
    + Expected: The flashcard with the specified parameters will be added to the list of flashcards. The details of the question will be shown in the display window on the side. + + 1. Test Case 2: `addmcq q/Test MCQ 2 ans/1 c/Choice1 c/Choice2 t/MCQ t/test d/LOW`
    + Expected: The flashcard with the specified parameters will be added to the list of flashcards together with its two tags `MCQ`, `test` and difficulty level `LOW` shown. The details of the question will be shown in the display window on the side. + + 1. Test Case 3: `addmcq q/Test MCQ 1 ans/1 c/Choice1 c/Choice2`
    + Expected: QuickCache responds with an error message indicating that the flashcard already exists (added in Test Case 1). Flashcard is not added. + + 1. Test Case 4: `addmcq q/Test MCQ 1 ans/1 c/Choice1 c/Choice2 t/Invalid Tag`
    + Expected: QuickCache responds with an error message indicating that tag field is invalid. Flashcard is not added.
    +
    + + :information_source: Note that flashcards containing similar questions and answers but different tags are treated as different flashcards. + +
    + + 1. Test Case 5: `addmcq q/Test MCQ 1 ans/1 c/Choice1 c/Choice2 d/Invalid Difficulty`
    + Expected: QuickCache responds with an error message indicating that difficulty field is invalid. Flashcard is not added.
    +
    + + :information_source: Note that flashcards containing similar questions and answers but different difficulty are treated as different flashcards. + +
    + 1. Test Case 6: `addmcq q/Test MCQ 1 ans/3 c/Choice1 c/Choice2`
    + Expected: QuickCache responds with an error message indicating that ans field is invalid. Flashcard is not added. + + 1. Some incorrect `addmcq` commands with missing fields to try: `addmcq`, `addmcq q/ ans/1 c/Choice1`, `addmcq q/Test MCQ 1 ans/ c/Choice1`, `addmcq q/Test MCQ 1 ans/1 c/`
    + Expected: QuickCache responds with an error message and no flashcard is added.
    +
    + + :information_source: Empty field for difficulty `d/` is accepted and flashcard difficulty is set to unspecified. + +
    + 1. Some incorrect `addmcq` commands with duplicate prefix to try: `addmcq q/Test MCQ 1 q/Test MCQ 2 ans/1 c/Choice1 c/Choice2`, `addmcq q/Test MCQ 1 ans/1 ans/2 c/Choice1 c/Choice2`
    + Expected: QuickCache responds with an error message and no flashcard is added. + +### 3. Opening a flashcard + +1. Prerequisites: + + 1. There is at least one flashcard stored in QuickCache. + + 1. List flashcards using the `list` command to see the index of the flashcard. + +1. Test Case 1: `open 1`
    + Expected: First flashcard is opened. Details of the question and options (for multiple choice questions) will be displayed. + +1. Test Case 2: `open 0`
    + Expected: No flashcard is opened. Error details shown in display. + +1. Other incorrect `open` commands to try: `open`, `open x` (where x is more than the last index in flashcard list), `open Invalid`
    + Expected: Error message will appear with instructions on how to use the `open` command. + +### 4. Editing a flashcard + +1. Prerequisites: + + 1. There is at least one flashcard stored in QuickCache. + + 1. List flashcards using the `list` command to see the index of the flashcard. + + 1. For some test cases listed bellow to work, user's first three flashcards should be the same as the sample starting flashcards that was provided. + +1. Test Case 1: `edit 1 q/Edited question ans/New answer`
    + Expected: The flashcard with index 1 is edited with the specified parameters. The details of the question will be shown in the display window on the side. + +1. Test Case 2: `edit 1 t/`
    + Expected: All tags are removed from the flashcard with index 1. The details of the question will be shown in the display window on the side. + +1. Test Case 3: `edit 1 t/General t/OEQ`
    + Expected: Specified tags are added to the flashcard with index 1. The details of the question will be shown in the display window on the side. + +1. Test Case 4: `edit 1 d/HIGH`
    + Expected: Difficulty level changed to `HIGH` for the flashcard with index 1. The details of the question will be shown in the display window on the side. + +1. Test Case 5: `edit 1 d/`
    + Expected: Difficulty tag is removed from the flashcard with index 1. The details of the question will be shown in the display window on the side.
    +
    + + :information_source: User can also use `edit 1 d/UNSPECIFIED` to achieve the same result. + +
    + +1. Test Case 6: `edit 1 c/Choice1`
    + Expected: Error message displayed. Choices should not be provided for open ended questions. + +1. Test Case 7: `edit 2 c/Choice1 c/Choice2 c/Choice3 c/Choice4`
    + Expected: The flashcard with index 1 is edited with the specified parameters. The details of the question will be shown in the display window on the side. + +1. Test Case 8: `edit 2 c/Choice1 c/Choice1`
    + Expected: Error message displayed. Choices should not be the same. + +1. Test Case 9: `edit 2 c/Choice1`
    + Expected: Error message displayed. Number of choices smaller than the answer. + +1. Test Case 10: `edit 2 ans/100`
    + Expected: Error message displayed. Number of choices smaller than the answer. + +1. Test Case 11: `edit 0`
    + Expected: No flashcard is opened. Error details shown in display. + +1. Other incorrect `edit` commands to try: `edit`, `edit x` (where x is more than the last index in flashcard list), `edit Invalid`
    + Expected: Error message will appear with instructions on how to use the `edit` command. + +### 5. Finding flashcards + +Users can fins flashcards both through keywords using the `q/` prefix and through tags using the `t/` prefix. + +1. Prerequisites: For some test cases listed bellow to work, user should have the sample starting flashcards that was provided stored in QuickCache. + +1. Test Case 1: `find q/Sample`
    + Expected: Finds all flashcards containing the keyword `Sample` (not case-sensitive) in its question. Found flashcards will be listed out. + +1. Test Case 2: `find q/Sample q/Singapore`
    + Expected: Finds all flashcards containing the keyword `Sample` and `Singapore` (not case-sensitive) in its question. Found flashcards will be listed out. + +1. Test Case 3: `find t/OEQ`
    + Expected: Finds all flashcards containing the tag `OEQ` (case-sensitive). Found flashcards will be listed out. + +1. Test Case 4: `find q/Sample t/OEQ t/General`
    + Expected: Finds all flashcards containing the tags `OEQ` and `General` (case-sensitive) and keyword `Sample` (not case-sensitive) in its question. Found flashcards will be listed out. + +1. Other incorrect `find` commands to try: `find`, `find Something`, `find q/`, `find t/`
    + Expected: Error message will appear with instructions on how to use the `find` command. + +### 6. Deleting flashcards + +There are 2 ways to delete flashcards – by index or by tags. + +1. Prerequisites: List all flashcards using the `list` command. There is at least one flashcard stored in QuickCache. + +1. Deleting a flashcard by index + + 1. Test Case 1: `delete 1`
    + Expected: First flashcard is deleted from the list. Details of the deleted flashcard shown in the status message. + + 1. Test Case 2: `delete 0`
    + Expected: No flashcard is deleted. Error details shown in the display. + +1. Deleting flashcards through tags + + 1. Test Case 1: `delete t/MCQ`
    + Expected: All flashcards with the tag `MCQ` is deleted + + 1. Other incorrect `delete` commands to try: `delete`, `delete x` (where x is larger than the list size), `delete 1 t/MCQ`
    + Expected: Error message will appear with instructions on how to use the delete command. + +1. Clearing all flashcards + + 1. Test Case 1: `clear` + Expected: All flashcards deleted from QuickCache. + +### 7. Testing a flashcard + +1. Prerequisites: List all flashcards using the `list` command. There is at least one flashcard stored in QuickCache. + +1. Testing flashcard containing open ended question + + 1. Test Case 1: `test 1 ans/Singapore`
    + Expected: Checks if answer provided matches with the answer stored in the open ended question within the first flashcard. Users starting off with the sample questions will expect test to be correct. Flashcard statistics will be updated.
    +
    + + :information_source: Answers are not case-sensitive. + +
    + 1. Test Case 2: `test 1 ans/`
    + Expected: Error message will appear as answer cannot be blank. Flashcard statistics will not be updated. + +1. Testing flashcard containing multiple choice question + + 1. Test Case 1: `test 2 o/2`
    + Expected: Checks if option provided matches with the option stored in the multiple choice question within the second flashcard. Users starting off with the sample questions will expect test to be correct. Flashcard statistics will be updated.
    +
    + + :information_source: Answers are not case sensitive. + +
    + 1. Test Case 2: `test 1 o/`
    + Expected: Error message will appear as option cannot be blank. Flashcard statistics will not be updated. + + 1. Other incorrect `test` commands to try: `test`, `test x ans/...` (where x is 0 or larger than the list size)
    + Expected: Error message will appear with instructions on how to use the test command. + +### 8. Displaying statistics + +There are 2 ways to display statistics of flashcards – by index or by tags. + +1. Prerequisites: For some test cases listed bellow to work, user should have the sample starting flashcards that was provided stored in QuickCache. + +1. Displaying statistics of a flashcard by index + + 1. Test Case 1: `stats 1`
    + Expected: Display statistics of the first flashcard. + + 1. Test Case 2: `stats 0`
    + Expected: No flashcard statistics. Error details shown in display. + + 1. Other incorrect `stats` commands to try: `stats`, `stats x` (where x is more than the last index in flashcard list), `stats Invalid`
    + Expected: Error message will appear with instructions on how to use the `stats` command. + +1. Displaying statistics of flashcards through tags + + 1. Test Case 1: `stats t/MCQ`
    + Expected: Display statistics of all flashcards containing tag `MCQ`. + + 1. Test Case 2: `stats t/MCQ t/CS2103`
    + Expected: Display statistics of all flashcards containing tags `MCQ` and `CS2103`. + + 1. Test Case 3: `stats t/`
    + Expected: Error message will appear on display. Tags cannot be empty. + +### 9. Clearing statistics in a flashcard + +1. Prerequisites: + + 1. There is at least one flashcard stored in QuickCache. + + 1. List flashcards using the `list` command to see the index of the flashcard. + +1. Test Case 1: `clearstats 1`
    + Expected: Statistics for the first flashcard is cleared. + +1. Test Case 2: `clearstats 0`
    + Expected: No flashcard statistics is cleared. Error details shown in display. + +1. Other incorrect `clearstats` commands to try: `clearstats`, `clearstats x` (where x is more than the last index in flashcard list), `clearstats Invalid`
    + Expected: Error message will appear with instructions on how to use the `clearstats` command. + +### 10. Sharing flashcards + +User can choose to import or export their data + +1. Export data + + 1. Prerequisites: Data file present within QuickCache. + + 1. Test case 1: `export my-flashcard.json`
    + Expected: File containing the flashcards will be exported into the export folder, located in the same directory as QuickCache.jar. + +1. Import data + + 1. Prerequisites: Create an import folder in the same directory as where QuickCache.jar is located. Place the file that you want to import in the import folder. For testing purposes, we will name this file as `my-flashcard.json`. + + 1. Test case 1: `import my-flashcard.json`
    + Expected: Flashcards within the file will be imported in your local QuickCache.
    +
    + + :information_source: Flashcards that has previously been imported and has not been modified will be ignored. Flashcards that already exists will not be imported as well. + +
    + +### 11. Saving data + +1. Dealing with missing data file + + 1. Users can simulate missing data file by deleting the json file in the data folder in the same directory as where QuickCache.jar.
    + Expected: Upon restart, QuickCache will create a new data file in the data folder containing the sample flashcards for the user. + +1. Dealing with corrupted data files + + 1. Users can simulate corrupted data file by deleting parts of the json file in the data folder in the same directory as where QuickCache.jar.
    + Expected: Upon restart, QuickCache will create a new empty data file in the data folder. + +## **Appendix: Effort** ## + +### Difficulty + +The difficulty level for developing QuickCache was high because we chose to morph AB3 into a flashcard manager instead of evolving it into a more powerful contact management app. We also wanted QuickCache to support both Open Ended Questions and Multiple Choice Questions. Other than managing questions, we felt that it was also important for the user to be able to test him/herself within QuickCache, view his/her performance, as well as share flashcards with his/her friends. + +Our team wrote a total of ~15k LoC, ~40 pages of User Guide and ~60 pages of Developer Guide. + +### Challenges + +We faced a number of challenges in developing QuickCache: +1. The biggest hurdle that we had to overcome was having to work together remotely for the entire project. This was also our first project module in SoC where we had to work together in a large group of five. +2. In addition, we also had to optimize experience of the application for viewing flashcards - some flashcards contained choices and to display statistics of flashcards. It was important that we had to reveal it to the user in a way that is intuitive to them. Since AB3's GUI was designed to only show one possible window (the list of people stored in it), we had to examine the GUI code, understand how it works and made sure the data given from the command result of `OpenCommand`, `TestCommand`, etc. can be displayed. +3. As QuickCache supports different types of questions, we also had to implement additional entity types and made us of the `Question` interface so that our flashcard can support different type of questions. +4. To be able to show statistics, it was important for us to maintain a state on each flashcard, even between sessions. To solve this, we created a `Statistics` class and used it to keep track of the number of times a question is tested and is tested correctly. + +### Effort + +In terms of effort compared to AB3, we felt that QuickCache took at least the same amount of effort, or twice that of AB3 to develop. You can refer to the table below to see the additions and extensions we made to the commands that AB3 came with: + +| Commands | AB3 | QuickCache | Extensions | +| --- | --- | --- | --- | +| add | Y | Y | Add supports both Multiple Choice and Open Ended questions | +| edit | Y | Y | Edit supports both Multiple Choice and Open Ended questions | +| delete | Y | Y | Delete supports both specific flashcard index or bulk deletion by tags | +| list | Y | Y | | +| exit | Y | Y | | +| open | | Y | | +| clear | | Y | | +| test | | Y | | +| stats | | Y | Stats supports both specific flashcard index and aggregation by tags | +| clear stats | | Y | | +| import | | Y | | +| export | | Y | | + +We also overhauled the entire `Person` model, and created our own `Flashcard` model, which makes use of the `Question` interface to support multiple entity types. + +The following class diagram shows the structure of `Person`: + +![BetterModelClassDiagram](images/BetterModelClassDiagram.png) -### Saving data +The following class diagram shows the structure of `Flashcard`: -1. Dealing with missing/corrupted data files +![FlashcardClassDiagram](images/FlashcardClassDiagram.png) - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ +### Achievements -1. _{ more test cases …​ }_ +Overall, we are proud of coming up with a complete product amidst the work from the other modules that we have and our individual commitments. We put in a lot of hard work into our documentation as well to make sure QuickCache is as easy to use for the end-user (the student) as possible. We have also improved the test coverage and achieved a codecov of 74%. diff --git a/docs/SettingUp.md b/docs/SettingUp.md index b89b691fed9..66c40b4d1d1 100644 --- a/docs/SettingUp.md +++ b/docs/SettingUp.md @@ -23,7 +23,7 @@ If you plan to use Intellij IDEA (highly recommended): 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. **Verify the setup**: - 1. Run the `seedu.address.Main` and try a few commands. + 1. Run the `Main` and try a few commands. 1. [Run the tests](Testing.md) to ensure they all pass. -------------------------------------------------------------------------------------------------------------------- diff --git a/docs/Testing.md b/docs/Testing.md index 8a99e82438a..b003b9342df 100644 --- a/docs/Testing.md +++ b/docs/Testing.md @@ -33,4 +33,4 @@ This project has three types of tests: 1. *Integration tests* that are checking the integration of multiple code units (those code units are assumed to be working).
    e.g. `seedu.address.storage.StorageManagerTest` 1. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
    - e.g. `seedu.address.logic.LogicManagerTest` + e.g. `LogicManagerTest` diff --git a/docs/UserGuide.css b/docs/UserGuide.css new file mode 100644 index 00000000000..9da848815c1 --- /dev/null +++ b/docs/UserGuide.css @@ -0,0 +1,30 @@ +/* This solution is adapted from +https://stackoverflow.com/questions/4098195/can-ordered-list- +produce-result-that-looks-like-1-1-1-2-1-3-instead-of-just-1*/ + +ol { + list-style-type: none; + counter-reset: item; + margin: 0; + padding: 0; +} + +ol > li { + display: table; + counter-increment: item; + margin-bottom: 0.6em; +} + +ol > li:before { + content: counters(item, ".") ". "; + display: table-cell; + padding-right: 0.6em; +} + +li ol > li { + margin: 0; +} + +li ol > li:before { + content: counters(item, ".") " "; +} diff --git a/docs/UserGuide.md b/docs/UserGuide.md index b91c3bab04d..408d373850f 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,36 +1,122 @@ --- -layout: page +:layout: page title: User Guide --- -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. +# Welcome to QuickCache User Guide -* Table of Contents -{:toc} +This User Guide is co-written by Josiah, Joshua, Gilbert, Francis and Xingjian. We are computer science students from National University of Singapore, and members of AY2021S1-CS2103T-T13-2. -------------------------------------------------------------------------------------------------------------------- +## Table of Contents + + + +1. [Introduction](#intro) +2. [Using this guide](#using-this-guide) +3. [Quick start](#quick-start) +4. [Features](#features) + 1. [Viewing help](#help) + 2. [Creating a new flashcard](#creating-a-new-flashcard) + 1. [Open ended question](#oeq) + 2. [Multiple choice question](#mcq) + 3. [Opening a flashcard](#opening-a-flashcard) + 4. [Editing a flashcard](#editing-a-flashcard) + 5. [Listing all flashcards](#listing-all-flashcards) + 6. [Finding flashcards](#finding-flashcards) + 1. [Finding by question](#finding-by-question) + 2. [Finding by tags](#finding-by-tags) + 3. [Finding by tags and question](#finding-by-tags-and-question) + 7. [Deleting flashcards](#deleting-flashcards) + 1. [Deleting by index](#deleting-by-index) + 2. [Deleting by tags](#deleting-by-tags) + 3. [Clearing all entries](#clear) + 8. [Testing a flashcard](#testing-flashcard) + 1. [Containing an open-ended question](#testing-oeq) + 2. [Containing a multiple choice question](#testing-mcq) + 9. [Displaying statistics](#displaying-statistics) + 1. [Statistics by index](#stats-by-index) + 2. [Statistics by tags](#stats-by-tags) + 10. [Clearing a flashcard's statistics](#clearing-a-flashcards-statistics) + 11. [Sharing flashcards](#sharing-flashcards) + 1. [Exporting a set of flashcards](#export) + 2. [Importing a set of flashcards](#import) + 12. [Exiting the program](#exit) + 13. [Saving the data](#save) +5. [FAQ](#faq) +6. [Command summary](#command-summary) + +-------------------------------------------------------------------------------------------------------------------- + + +## Introduction to QuickCache + +**QuickCache** is a desktop app for managing flashcards, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). + +If you are a student who can type fast and loves organizing your study materials, **QuickCache** can get your flashcard management tasks done faster than any traditional GUI appplication. + +The **QuickCache User Guide** helps you get started with using **QuickCache**. This user guide aims to walk you through the robust features that **QuickCache** has to offer and take you from zero to hero. Don't like reading? A summary is available at the end for your reference. + + +-------------------------------------------------------------------------------------------------------------------- + + +## Using this guide + +Before diving into **QuickCache** and getting to know its features, lets get familiar with the symbols used in this user guide. + +:information_source: This symbol represents important information + +:exclamation: This symbol represents warnings + +:bulb: This symbol represents additional information + + +-------------------------------------------------------------------------------------------------------------------- + + ## Quick start +Here is a quick start on how you can start using our app in your own computer. 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 `quickcache.jar` from [here](https://github.com/AY2021S1-CS2103T-T13-2/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 QuickCache. + +1. Double-click the file to start the app. A GUI similar to the one below should appear in a few seconds. Note how the app contains some sample data.
    -1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
    ![Ui](images/Ui.png) 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`**`q/Plants give out ___ when they photosynthesise? ans/Oxygen t/Biology` : Adds an open ended question `Plants give out ___ when they photosynthesise?` with answer `Oxygen` and tagged to `Biology`. + + * **`addmcq`**`q/Plants give out ___ when they photosynthesise? ans/1 c/Oxygen c/Carbon c/Carbon dioxide` : Adds a multiple choice question `Plants give out ___ when they photosynthesise?` with 3 options `Oxygen`, `Carbon`, `Carbon dioxide` and with answer `Oxygen`. + + * **`open`**`1` : Opens the 1st question shown in the current list. + + * **`edit`**`1 ans/Edited answer` : Edit the answer of the first flashcard on the list to become `Edited answer`. + + * **`list`** : Lists all flashcards. + + * **`find`** `find t/MCQ q/All mammals q/survive t/Biology` : Finds all Flashcards tagged to the tag `MCQ` and `Biology` and has keywords `All`, `mammals` and `survive` in question. - * **`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 flashcard shown in the current list. - * **`delete`**`3` : Deletes the 3rd contact shown in the current list. + * **`clear`** : Deletes all flashcards. - * **`clear`** : Deletes all contacts. + * **`test`**`1 ans/Example answer` : Tests the 1st question shown in the current list with `Example answer` as the answer. + + * **`stats`**`1` : Show stats of the 1st question shown in the current list. + + * **`clearstats`**`1` : Clears the statistics of the 1st flashcard shown in the current list. + + * **`export`**`science-questions.json` : Exports current list of flashcard to a file named `science-questions.json` in the `export` folder. + + * **`import`**`science-questions.json` : Import all flashcards from a file named `science-questions.json` in the `import` folder. * **`exit`** : Exits the app. @@ -38,6 +124,7 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo -------------------------------------------------------------------------------------------------------------------- + ## Features
    @@ -45,134 +132,777 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo **:information_source: 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`. + e.g. in `add ans/ANSWER`, `ANSWER` is a parameter which can be used as `add ans/Oxygen`. -* Items in square brackets are optional.
    - e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. +* Parameters can be in any order.
    + e.g. if the command specifies `q/QUESTION ans/ANSWER`, `q/ANSWER ans/QUESTION` is also acceptable. -* Items with `…`​ after them can be used multiple times including zero times.
    - e.g. `[t/TAG]…​` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. +* Items in square brackets are optional. + e.g. q/QUESTION [t/TAG] can be used as q/What is my name? t/personal or as q/What is my name? . -* Parameters can be in any order.
    - e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. +* Items with ... after them can be used multiple times. + e.g. [c/CHOICE]... can be used as c/Choice1, c/Choice1 c/Choice2 etc.
    + ### Viewing help : `help` -Shows a message explaning how to access the help page. - -![help message](images/helpMessage.png) +If you want to see a step-by-step guide for all QuickCache commands, you can get the URL to the QuickCache user guide by using the help command. Format: `help` +![HelpMessage](images/helpMessage.png) -### Adding a person: `add` + +### Creating a new flashcard +You can add a new flashcard to the list. -Adds a person to the address book. +
    +:exclamation: You cannot have multiple question and answer prefixes. +
    + + +#### Creating a flashcard with open ended question: `add q/QUESTION ans/ANSWER [t/TAG]... [d/DIFFICULTY]` +You can create a flashcard that contains an open ended question which will be added to the list. + +1. You can use the add command to add a flashcard with an open ended question which will be added to the list. +For example, you can enter`add q/Sample Question ans/Sample Answer` + + ![addOpenEnded](images/addOpenEnded.png) -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​` +2. You have successfully created a flashcard with an open ended question and it will be saved immediately in the list. -
    :bulb: **Tip:** -A person can have any number of tags (including 0) + ![addOpenEnded2](images/addOpenEnded2.png) + +
    +:exclamation: You cannot add a flashcard with empty question and empty answer. Additionally, DIFFICULTY +can only be set to LOW, MEDIUM, HIGH or UNSPECIFIED.
    -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` + +#### Creating a flashcard with multiple choice question: `addmcq q/QUESTION ans/ANSWER c/CHOICE... [t/TAG]... [d/DIFFICULTY]` +You can create a flashcard that contains a multiple choice question which will be added to the list. + +1. You can use the addmcq command to add a flashcard with a multiple choice question which will be added to the list. +For example, you can enter `addmcq q/Sample Question ans/1 c/Sample Choice c/Sample Choice 2` + + ![addMCQ](images/addMCQ.png) + +2. You have successfully created a flashcard with a multiple choice question and it will be saved immediately in the list. -### Listing all persons : `list` + ![addMCQ2](images/addMCQ2.png) -Shows a list of all persons in the address book. +
    -Format: `list` +:exclamation: +- You cannot add flashcard with missing question or missing answer or missing choice. +- DIFFICULTY can only be set to LOW, MEDIUM, HIGH or UNSPECIFIED. +
    + + +### Opening a flashcard: `open INDEX` -### Editing a person : `edit` +To view a flashcard you can open it by its index. + +
    -Edits an existing person in the address book. +:information_source: The INDEX refers to the index number shown on the last displayed flashcard list and it must be a positive integer. -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [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, …​ -* 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 - specifying any tags after it. +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. -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. + ![OpenIndexStep1](./images/OpenIndexStep1.png) -### Locating persons by name: `find` +2. Using the indices of the displayed list, enter the open command followed by the index of the flashcard you want to open. For example, if you want to open the 1st flashcard in the displayed list, you can enter `open 1`. -Finds persons whose names contain any of the given keywords. + ![OpenIndexStep2](./images/OpenIndexStep2.png) -Format: `find KEYWORD [MORE_KEYWORDS]` +3. Press enter and QuickCache will open the flashcard specified by the index. -* 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` -* Persons matching at least one keyword will be returned (i.e. `OR` search). - e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang` + ![OpenIndexStep3](./images/OpenIndexStep3.png) -Examples: -* `find John` returns `john` and `John Doe` -* `find alex david` returns `Alex Yeoh`, `David Li`
    - ![result for 'find alex david'](images/findAlexDavidResult.png) -### Deleting a person : `delete` +You have successfully opened a flashcard! -Deletes the specified person from the address book. + +### Editing a flashcard: `edit INDEX [q/QUESTION] [ans/ANSWER] [c/CHOICE]... [t/TAG]... [d/DIFFICULTY]` -Format: `delete INDEX` +You can edit a flashcard that you have created previously. -* Deletes 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, …​ +
    +:exclamation: At least one field of the flashcard must be changed! +
    -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. +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. -### Clearing all entries : `clear` + ![edit](images/Edit.png) -Clears all entries from the address book. +2. Using the indices of the displayed list, enter the edit command followed by the index of the flashcard you want to edit. +For example, if you want to edit the 3rd flashcard in the displayed list, you can enter `edit 3 q/Updated Question`. -Format: `clear` + ![edit2](images/Edit2.png) -### Exiting the program : `exit` +3. Press enter and QuickCache will edit the flashcard specified by the index. -Exits the program. + ![edit3](images/Edit3.png) -Format: `exit` +You have successfully edited a flashcard. -### Saving the data +
    + +:information_source:
    +- When editing tags, the existing tags of the flashcard will be removed i.e adding of tags is not cumulative. +- You can remove all the flashcard’s tags by typing t/ without specifying any tags after it. +- You can remove the flashcard’s difficulty by typing d/ without specifying any difficulty after it. Or you can manually set it to d/UNSPECIFIED. + +
    + + +### Listing all flashcards : `list` + +If you want to see all the flashcards you have created, use the `list` command. + + +### Finding flashcards + +To find flashcards, you can find them by specifying keywords within their questions and/or specifying their tags. + +
    + +:information_source: You must provide at least one search parameter. + +
    + +
    + +:exclamation: Take note that only flashcards which fulfill **all** the specified search parameters will be displayed. Flashcards that fulfill only some search parameters will not be diplayed. -AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. +
    + + +#### Finding by question: `find q/KEYWORD...` + +
    + +:information_source:
    +- Words in spaced keywords will be treated as individual keywords. Example, the keyword `what is` will be treated as two keywords: `what` and `is`.
    +- Keywords do not need to match exact word. Example, the keyword `Wha` will pick up questions containing `What` as a word. + +
    + +1. Use the `list` command to first list all the flashcards. + + ![FindQuestionStep1](./images/FindQuestionStep1.png) + +2. Enter the find command followed by `q/` and the keyword in the question of the flashcards you want to find. For example, if you want to find flashcards with the keyword `CS2103` in their question in the displayed list, you can enter `find q/CS2103`. + + ![FindQuestionStep2](./images/FindQuestionStep2.png) + +3. Press enter and QuickCache will display all the flashcards with the keyword `CS2103` in their question. + + ![FindQuestionStep3](./images/FindQuestionStep3.png) + + +#### Finding by tags: `find t/TAG1...` + +
    + +:information_source: Tags are case-sensitive. + +
    + +1. Use the `list` command to first list all the flashcards. + + ![FindTagsStep1](./images/FindTagsStep1.png) + +2. Enter the find command followed by `t/` and the tag of the flashcards you want to find. For example, if you want to find flashcards with the tag `Biology` in the displayed list, you can enter `find t/Biology`. + + ![FindTagsStep2](./images/FindTagsStep2.png) + +3. Press enter and QuickCache will display all the flashcards with the tag `Biology`. + + ![FindTagsStep3](./images/FindTagsStep3.png) + + +#### Finding by tags and question: `find t/TAG... q/KEYWORD...` + +
    + +:information_source:
    +- Words in spaced keywords will be treated as individual keywords. Example, the keyword `what is` will be treated as two keywords: `what` and `is`.
    +- Keywords do not need to match exact word. Example, the keyword `Wha` will pick up questions containing `What` as a word.
    +- Tags are case-sensitive. + +
    -### Archiving data files `[coming in v2.0]` +
    +:exclamation: Take note that finding flashcards based on both tags and question will only display flashcards that have both the specified tags **and** keywords. It will not display flashcards that only have either the specified tags or the specified keywords. + +
    + +1. Use the `list` command to first list all the flashcards. + + ![FindQuestionAndTagsStep1](./images/FindQuestionAndTagsStep1.png) + +2. Enter the find command followed by `t/` and the tag of the flashcards you want to find. Proceed to include `q/` and the keyword in the question of the flashcards you want to find. For example, if you want to find flashcards with the tag `General` and the keyword `University` in the question, you can enter `find t/General q/University`. + + ![FindQuestionAndTagsStep2](./images/FindQuestionAndTagsStep2.png) + +3. Press enter and QuickCache will display all the flashcards with the tag `General ` and the keyword `University` in their question. + + ![FindQuestionAndTagsStep3](./images/FindQuestionAndTagsStep3.png) + + +### Deleting flashcards + +To delete a flashcard, you can either delete it by its index or based off its tags. + +
    + +:exclamation: You can only delete based on index or based on tags but not both! + +
    + + +#### Deleting by index : `delete INDEX` + +You can delete a flashcard based on the index shown in the last displayed list. -_{explain the feature here}_ + +
    + +:information_source: The INDEX refers to the index number shown on the last displayed flashcard list and it must be a positive integer. + +
    + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![DeleteIndexStep1](./images/DeleteIndexStep1.png) + +2. Using the indices of the displayed list, enter the delete command followed by the index of the flashcard you want to delete. For example, if you want to delete the 3rd flashcard in the displayed list, you can enter `delete 3`. + + ![DeleteIndexStep2](./images/DeleteIndexStep2.png) + +3. Press enter and QuickCache will delete the flashcard specified by the index. + + ![DeleteIndexStep3](./images/DeleteIndexStep3.png) + +You have successfully deleted a flashcard! + + +#### Deleting by tags : `delete t/TAG...` + +You can delete a group of flashcards based on a specified tag. All flashcards that have this specified tag will be deleted. + +
    + +:bulb: You can specify more than one tag to be used when deleting flashcards. But only flashcards with **all** of these specified tags will be deleted. + +
    + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![DeleteIndexStep1](./images/DeleteTagStep1.png) + +2. In the user input box, enter in the delete command together with the tags that you want to use as the criteria. For example, if you want to delete all flashcards with the tag `MCQ`, type `delete t/MCQ`. + + ![DeleteTagStep2](./images/DeleteTagStep2.png) + +3. Press enter and QuickCache will delete the flashcards accordingly. + + ![DeleteTagStep3](./images/DeleteTagStep3.png) + +You have successfully deleted all the flashcards with the specified tag(s)! + + +#### Clearing all entries : `clear` + +Suppose you are in a situation where you want to get rid of all the flashcards in QuickCache. You might find it troublesome to delete each flashcard one-by-one. Instead, you can utilize the clear command to clear all flashcards on QuickCache directly. + + +### Testing a flashcard + + +#### Containing an open-ended question : `test INDEX ans/ANSWER` + +You can test yourself with a flashcard containing open-ended question by specifying an answer. + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![TestStep1](./images/TestStep1.png) + +2. Using the indices of the displayed list, enter the `test` command followed by the index of the flashcard you want to test and what you think the answer to the question is. For example, if you want to test the first flashcard in the displayed list with the answer `Singapore`, you can enter `test 1 ans/Singapore`. + +
    + :bulb: Answer is case insensitive. +
    +
    + :exclamation: The index must be a positive integer 1, 2, 3, ... +
    + + ![TestOpenStep2](./images/TestOpenStep2.png) + +3. Press enter and QuickCache will tell you whether you got the question right. + + ![TestOpenStep3](./images/TestOpenStep3.png) + +You have successfully tested yourself on an open-ended question! + + +#### Containing a multiple choice question : `test INDEX o/OPTION` + +You can also test yourself a flashcard containing a multiple choice question by specifying an option. + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![TestStep1](./images/TestStep1.png) + +2. Using the indices of the displayed list, enter the `open` command followed by the index of the flashcard you want to see the options of. For example, if you want to see the options from the second flashcard in the displayed list, you can enter `open 2`. + + ![TestMCQStep2](./images/TestMCQStep2.png) + +3. Using the indices of the previous displayed list, enter the `test` command followed by the index of the flashcard you want to test and what you think the answer to the question is. For example, if you want to test the second flashcard in the displayed list with the 1st option, you can enter `test 2 o/1`. + +
    + :exclamation: The index and option must both be a positive integer 1, 2, 3, ... +
    + + ![TestMCQStep3](./images/TestMCQStep3.png) + +4. Press enter and QuickCache will tell you whether you got the question right. + + ![TestMCQStep4](./images/TestMCQStep4.png) + +You have successfully tested yourself on a multiple choice question! + + +### Displaying statistics + +
    +:exclamation: You can only show statistics based on index or based on tags but not both! +
    + +Statistics include: + +* The number of times and the percentage the user answers all flashcards containing the specified tag(s) correctly. +* The number of times and the percentage the user answers all flashcards containing the specified tag(s) incorrectly. + + +#### Statistics by index: `stats INDEX` + +You can display the statistics of a specified flashcard in a Pie Chart based on the last displayed list. + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![StatsIndexStep1](./images/StatsIndexStep1.png) + +2. Using the indices of the displayed list, enter the stats command followed by the index of the flashcard you want to view the statistics of. For example, if you want to view the statistics of the first flashcard in the displayed list, you can enter `stats 1`. + +
    + :information_source: The INDEX refers to the the index number shown on the last displayed flashcard list and it must be a positive integer. +
    + + ![StatsIndexStep2](./images/StatsIndexStep2.png) + +3. Press enter and QuickCache will display the statistics of the flashcard specified by the index. + + ![StatsIndexStep3](./images/StatsIndexStep3.png) + +You have successfully displayed the statistics of a flashcard! + + +#### Statistics by tags: `stats t/TAG...` + +You can also display the statistics of multiple flashcards in a Pie Chart by specifying tags. + +1. In the user input box, enter the stats command together with the tags that you want to use as the criteria. For example, if you want to display statistics for all flashcards with the tag `MCQ`, type `stats t/MCQ`. + +
    + + :bulb: You can specify more than one tag to be used when displaying statistics of multiple flashcards. But only flashcards with **all** of these specified tags will be included in the aggregation. + +
    + + ![StatsTagsStep1](./images/StatsTagsStep1.png) + +2. Press enter and QuickCache will display the statistics of the flashcards containing the specified tags. + + ![StatsTagsStep2](./images/StatsTagsStep2.png) + +You have successfully displayed the statistics of all flashcards containing the specified tags! + + +### Clearing a flashcard's statistics : `clearstats INDEX` + +To clear the statistics of a flashcard you can use the clearstats command. + +
    + +:information_source: The INDEX refers to the the index number shown on the last displayed flashcard list and it must be a positive integer. + +
    + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![ClearstatsIndexStep1](./images/ClearstatsIndexStep1.png) + +
    + Optional Step: + You can first check the statistics of the flashcard you want to clear the statistics of. + + + +
    + +2. Using the indices of the displayed list, enter the clearstats command followed by the index of the flashcard you want to clear the statistics of. For example, if you want to clear the statistics of the first flashcard in the displayed list, you can enter `clearstats 1`. + + ![ClearstatsIndexStep2](./images/ClearstatsIndexStep2.png) + +3. Press enter and QuickCache will clear the statistics of the flashcard specified by the index. + + ![ClearstatsIndexStep3](./images/ClearstatsIndexStep3.png) + +
    + Optional Step: + You can check that the statistics of the flashcard has been cleared. + + + +
    + +You have successfully cleared the statistics of a flashcard! + + +### Sharing flashcards + + +#### Exporting a set of flashcards : `export FILE_NAME` + +You can export all flashcards from the last displayed list into a file named `FILE_NAME` for backup or sharing with your friends. + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![ExportStep1](./images/ExportStep1.png) + +2. In the user input box, enter the `export` command together with the `FILE_NAME` you would like to save the flashcards into. For example, if you would like the file to be named as `josiah-flashcard.json`, you can enter `export josiah-flashcard.json`. + +
    + :bulb: The filename specified includes the file format extension e.g. file.json +
    + + ![ExportStep2](./images/ExportStep2.png) + +3. Press enter and the file containing the flashcards will be exported into the `export` folder, located in the same directory as `QuickCache.jar` + + ![ExportStep3a](./images/ExportStep3a.png) + + Here is the file location on Mac OS. + + ![ExportStep3b](./images/ExportStep3b.png) + + ![ExportStep3c](./images/ExportStep3c.png) + + Here is the file location on Windows. + + ![ExportStep3bW](./images/ExportStep3bW.png) + + ![ExportStep3cW](./images/ExportStep3cW.png) + + +Voila! You have successfully exported your flashcards into a file. + + +#### Importing a set of flashcards : `import FILE_NAME` + +You can import external flashcards into your local QuickCache as well. + +1. Create an `import` folder in the same directory as where `QuickCache.jar` is located. The pictures shown are the equivalents +for both Mac OS and Windows. + + ![ImportStep1](./images/ImportStep1.png) + + ![ImportStep1W](./images/ImportStep1W.png) + +2. Place the file that you want to import in the `import` folder. + + ![ImportStep2](./images/ImportStep2.png) + + ![ImportStep2W](./images/ImportStep2W.png) + +3. In the user input box, enter the `import` command together with the name of the file you would like to import the flashcards from. For example, if the file to import from is named `joshua-flashcard.json`, you can enter `import joshua-flashcard.json`. + +
    + :bulb: The filename specified includes the file format extension e.g. file.json and duplicate flashcards will be ignored. +
    + + ![ImportStep3](./images/ImportStep3.png) + +4. Press enter and the flashcards within the file will be imported in your local QuickCache. + +
    + :information_source: Flashcards that has previously been imported and has not been modified will be ignored. Flashcards that already exists will not be imported as well. +
    + + ![ImportStep4](./images/ImportStep4.png) + +Good job! You have successfully imported flashcards from an external file. + + +### Exiting the program : `exit` + +You can exit QuickCache by using the exit command. + + +### Saving the data + +For your convenience, QuickCache data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. -------------------------------------------------------------------------------------------------------------------- + ## 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. +**Q**: Why can't I open QuickCache on my device?
    +**A**: There are a few potential reasons as to why QuickCache is not opening on your device: + +1. You first need to ensure that your device is a **desktop device** as QuickCache is not supported on mobile devices. +2. Next, you need to ensure that you have **Java 11 or above** installed on your device. You can refer to this [guide to check your java version](https://superuser.com/questions/1221096/how-do-i-check-what-version-of-java-i-have-installed). +3. Double clicking QuickCache doesn't work on every desktop device. If you are experiencing problems with this, you can try using terminal or the command prompt to navigate to the folder where `quickcache.jar` is located and then proceed to execute the following command **`java -jar quickcache.jar`**. Note that if you rename `quickcache.jar` you have to tweak the command accordingly. + +**Q**: How do I transfer my flashcards to my friend?
    +**A**: You can first [export](#export) the flashcards that are stored in QuickCache into your desired file format. After exporting, you can proceed to send the file to your friend over your favourite messaging application. Upon receving the file, your friend can then proceed to [import](#import) the flashcards into QuickCache. + +**Q**: How can I contribute to QuickCache?
    +**A**: There are a few ways you can contribute to QuickCache: + +* If you are an investor, you can reach out to us [here](mailto:damith@comp.nus.edu.sg). +* If you are a developer, we greatly welcome you to contribute to QuickCache by submitting a pull request [here](https://github.com/AY2021S1-CS2103T-T13-2/tp/pulls). You can view QuickCache's source code at this [link](https://github.com/AY2021S1-CS2103T-T13-2/tp). + +**Q**: How do I give suggestions or report for bugs on QuickCache?
    +**A**: If you have something to suggest to us or experienced any bugs while using QuickCache, we would appreciate it if you post an issue on it [here](https://github.com/AY2021S1-CS2103T-T13-2/tp/issues). -------------------------------------------------------------------------------------------------------------------- + ## 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` -**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` +If you need to quickly look up a command, we have added a table below to summarize all the commands offered by QuickCache. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ActionCommandFormatExample
    + Creating a flashcard + add + add q/QUESTION ans/ANSWER [t/TAG]... [d/DIFFICULTY] + + add q/Sample Question? ans/A +
    addmcq + addmcq q/QUESTION ans/ANSWER
    + c/CHOICE... [t/TAG]... [d/DIFFICULTY]
    +
    + addmcq q/Sample Question? ans/1 c/A c/B c/C +
    + Deleting flashcard(s)delete + delete INDEX + + delete 1 +
    + delete t/TAG... + + delete t/Assembly +
    clear + clear + + clear +
    + Editing a flashcardedit + edit INDEX [q/QUESTION] [ans/ANSWER] [c/CHOICE]... [t/TAG]... [d/DIFFICULTY] + + edit 1 q/Sample Question? ans/2 c/A c/C c/B +
    + Exit QuickCache + exit + exit + + exit +
    + Finding flashcardsfind + find q/KEYWORD... + + find q/CS2103T q/What q/is +
    + find t/TAG... + + find t/Assembly t/MCQ +
    + find [t/TAG]... [q/KEYWORD1]... + + find t/Assembly t/MCQ q/CS2100 q/What +
    + Flashcard Statistics + stats + Display statistics of a single flashcard:stats INDEX + + stats 1 +
    + Display statistics based on tags:stats t/TAG... + + stats t/MCQ +
    clearstats + Clear statistics:clearstats INDEX + + clearstats 1 +
    + Get user guide URL + help + help + + help +
    + Import and Export + import + import FILE_NAME + + import science-questions.json +
    export + export FILE_NAME + + export science-questions.json +
    + Listing flashcardslist + list + + list +
    + Opening a flashcardopen + open INDEX + + open 1 +
    + Testing a flashcard + test + Open Ended: test INDEX a/ANSWER + + test 2 ans/Sample Answer +
    + MCQ: test INDEX o/OPTION + + test 3 o/1 +
    diff --git a/docs/_config.yml b/docs/_config.yml index 6bd245d8f4e..5abe3f8cbb0 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,5 +1,5 @@ -title: "AB-3" -theme: minima +title: "QuickCache" +theme: jekyll-theme-minimal header_pages: - UserGuide.md @@ -8,7 +8,7 @@ header_pages: markdown: kramdown -repository: "se-edu/addressbook-level3" +repository: "AY2021S1-CS2103T-T13-2/tp" github_icon: "images/github-icon.png" plugins: diff --git a/docs/_includes/head.html b/docs/_includes/head.html index 83ac5326933..8ca74a5004b 100644 --- a/docs/_includes/head.html +++ b/docs/_includes/head.html @@ -4,6 +4,7 @@ + {%- include custom-head.html -%} diff --git a/docs/diagrams/AddMcqActivityDiagram.puml b/docs/diagrams/AddMcqActivityDiagram.puml new file mode 100644 index 00000000000..4b5335aab9f --- /dev/null +++ b/docs/diagrams/AddMcqActivityDiagram.puml @@ -0,0 +1,23 @@ +@startuml +start +:User executes add multiple choice question command; +:QuickCache parses the input from user; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. +if() then ([Successfully parsed]) + if () then ([flashcard already exists]) + :Throw CommandException; + :Pass the CommandException to the UI; + else ([else]) + : Model add flashcard to the list; + :Pass the result to the UI; + endif +else ([else]) + :Throw ParseException; + :Pass the ParseException to the UI; +endif + +:UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/AddMcqParserSequenceDiagram.puml b/docs/diagrams/AddMcqParserSequenceDiagram.puml new file mode 100644 index 00000000000..a67407e4345 --- /dev/null +++ b/docs/diagrams/AddMcqParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse AddMultipleChoiceQuestionCommand +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":AddMultipleChoiceQuestionCommandParser" as AddMultipleChoiceQuestionCommandParser LOGIC_COLOR +participant "t:AddMultipleChoiceQuestionCommand" as AddMultipleChoiceQuestionCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("add q/question ans/1 c/first c/second") +activate QuickCacheParser + +create AddMultipleChoiceQuestionCommandParser +QuickCacheParser -> AddMultipleChoiceQuestionCommandParser +activate AddMultipleChoiceQuestionCommandParser + +AddMultipleChoiceQuestionCommandParser -> QuickCacheParser +deactivate AddMultipleChoiceQuestionCommandParser + +QuickCacheParser -> AddMultipleChoiceQuestionCommandParser : parse("q/question ans/1 c/first c/second") +activate AddMultipleChoiceQuestionCommandParser + +create AddMultipleChoiceQuestionCommand +AddMultipleChoiceQuestionCommandParser -> AddMultipleChoiceQuestionCommand +activate AddMultipleChoiceQuestionCommand + +AddMultipleChoiceQuestionCommand --> AddMultipleChoiceQuestionCommandParser : t +deactivate AddMultipleChoiceQuestionCommand + +AddMultipleChoiceQuestionCommandParser -> QuickCacheParser : t +deactivate AddMultipleChoiceQuestionCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddMultipleChoiceQuestionCommandParser -[hidden]-> QuickCacheParser +destroy AddMultipleChoiceQuestionCommandParser + +QuickCacheParser --> LogicManager : t +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/AddMcqSequenceDiagram.puml b/docs/diagrams/AddMcqSequenceDiagram.puml new file mode 100644 index 00000000000..a42cf36525b --- /dev/null +++ b/docs/diagrams/AddMcqSequenceDiagram.puml @@ -0,0 +1,50 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "t:AddMultipleChoiceQuestionCommand" as AddMultipleChoiceQuestionCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant ":QuickCache" as QuickCache MODEL_COLOR +participant "flashcards:UniqueFlashcardList" as Flashcards MODEL_COLOR +participant "internalList:ObservableList" as ObservableList MODEL_COLOR +end box +[-> LogicManager : execute("add q/question ans/1 c/first c/second") +activate LogicManager + +ref over LogicManager, AddMultipleChoiceQuestionCommand : Parse AddMultipleChoiceQuestionCommand + +LogicManager -> AddMultipleChoiceQuestionCommand : execute() +activate AddMultipleChoiceQuestionCommand + +AddMultipleChoiceQuestionCommand -> Model : addFlashcard() +activate Model + +Model -> QuickCache :addFlashcard() +activate QuickCache + +QuickCache -> Flashcards :addFlashcard() +activate Flashcards + +Flashcards -> ObservableList : add() +activate ObservableList +return + +return + +return + +return + +return result + +AddMultipleChoiceQuestionCommand -[hidden]-> LogicManager +destroy AddMultipleChoiceQuestionCommand + + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/AddOpenEndedActivityDiagram.puml b/docs/diagrams/AddOpenEndedActivityDiagram.puml new file mode 100644 index 00000000000..c5b7e9ea857 --- /dev/null +++ b/docs/diagrams/AddOpenEndedActivityDiagram.puml @@ -0,0 +1,23 @@ +@startuml +start +:User executes add open ended question command; +:QuickCache parses the input from user; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. +if() then ([Successfully parsed]) + if () then ([flashcard already exists]) + :Throw CommandException; + :Pass the CommandException to the UI; + else ([else]) + : Model add flashcard to the list; + :Pass the result to the UI; + endif +else ([else]) + :Throw ParseException; + :Pass the ParseException to the UI; +endif + +:UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/AddOpenEndedParserSequenceDiagram.puml b/docs/diagrams/AddOpenEndedParserSequenceDiagram.puml new file mode 100644 index 00000000000..12b985c1943 --- /dev/null +++ b/docs/diagrams/AddOpenEndedParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse AddOpenEndedQuestionCommand +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":AddOpenEndedQuestionCommandParser" as AddOpenEndedQuestionCommandParser LOGIC_COLOR +participant "t:AddOpenEndedQuestionCommand" as AddOpenEndedQuestionCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("add q/question ans/answer") +activate QuickCacheParser + +create AddOpenEndedQuestionCommandParser +QuickCacheParser -> AddOpenEndedQuestionCommandParser +activate AddOpenEndedQuestionCommandParser + +AddOpenEndedQuestionCommandParser -> QuickCacheParser +deactivate AddOpenEndedQuestionCommandParser + +QuickCacheParser -> AddOpenEndedQuestionCommandParser : parse("q/question ans/answer") +activate AddOpenEndedQuestionCommandParser + +create AddOpenEndedQuestionCommand +AddOpenEndedQuestionCommandParser -> AddOpenEndedQuestionCommand +activate AddOpenEndedQuestionCommand + +AddOpenEndedQuestionCommand --> AddOpenEndedQuestionCommandParser : t +deactivate AddOpenEndedQuestionCommand + +AddOpenEndedQuestionCommandParser -> QuickCacheParser : t +deactivate AddOpenEndedQuestionCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddOpenEndedQuestionCommandParser -[hidden]-> QuickCacheParser +destroy AddOpenEndedQuestionCommandParser + +QuickCacheParser --> LogicManager : t +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/AddOpenEndedSequenceDiagram.puml b/docs/diagrams/AddOpenEndedSequenceDiagram.puml new file mode 100644 index 00000000000..c5600321d19 --- /dev/null +++ b/docs/diagrams/AddOpenEndedSequenceDiagram.puml @@ -0,0 +1,50 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "t:AddOpenEndedQuestionCommand" as AddOpenEndedQuestionCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant ":QuickCache" as QuickCache MODEL_COLOR +participant "flashcards:UniqueFlashcardList" as Flashcards MODEL_COLOR +participant "internalList:ObservableList" as ObservableList MODEL_COLOR +end box +[-> LogicManager : execute("add q/question ans/answer") +activate LogicManager + +ref over LogicManager, AddOpenEndedQuestionCommand : Parse AddOpenEndedQuestionCommand + + +LogicManager -> AddOpenEndedQuestionCommand : execute() +activate AddOpenEndedQuestionCommand + +AddOpenEndedQuestionCommand -> Model : addFlashcard() +activate Model + +Model -> QuickCache :addFlashcard() +activate QuickCache + +QuickCache -> Flashcards :addFlashcard() +activate Flashcards + +Flashcards -> ObservableList : add() +activate ObservableList +return + +return + +return + +return + +return result + +AddOpenEndedQuestionCommand -[hidden]-> LogicManager +destroy AddOpenEndedQuestionCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index ef81d18c337..718959ad056 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -13,13 +13,13 @@ activate ui UI_COLOR ui -[UI_COLOR]> logic : execute("delete 1") activate logic LOGIC_COLOR -logic -[LOGIC_COLOR]> model : deletePerson(p) +logic -[LOGIC_COLOR]> model : deleteFlashcard(flashcardTodelete) activate model MODEL_COLOR model -[MODEL_COLOR]-> logic deactivate model -logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook) +logic -[LOGIC_COLOR]> storage : saveAddressBook(quickCache) activate storage STORAGE_COLOR storage -[STORAGE_COLOR]> storage : Save to file diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml index 29076104af3..a43e85be25b 100644 --- a/docs/diagrams/BetterModelClassDiagram.puml +++ b/docs/diagrams/BetterModelClassDiagram.puml @@ -4,6 +4,15 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR +package Person <> { +class Person +class Phone +class Name +class Tag +class Email +class Address +} + AddressBook *-right-> "1" UniquePersonList AddressBook *-right-> "1" UniqueTagList UniqueTagList -[hidden]down- UniquePersonList diff --git a/docs/diagrams/ClearActivityDiagram.puml b/docs/diagrams/ClearActivityDiagram.puml new file mode 100644 index 00000000000..ca64edc18d2 --- /dev/null +++ b/docs/diagrams/ClearActivityDiagram.puml @@ -0,0 +1,9 @@ +@startuml +start +:User executes clear command; +:Empty instance of QuickCache is created; +:Existing QuickCache in model is replaced with the new empty instance of QuickCache; +:Command result is passed to UI; +:UI displays successful clear message to User; +stop +@enduml diff --git a/docs/diagrams/ClearSequenceDiagram.puml b/docs/diagrams/ClearSequenceDiagram.puml new file mode 100644 index 00000000000..2c371a4d64e --- /dev/null +++ b/docs/diagrams/ClearSequenceDiagram.puml @@ -0,0 +1,39 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "c:ClearCommand" as ClearCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "emptyQC:QuickCache" as QuickCache MODEL_COLOR +end box + +[-> LogicManager : execute("clear") +activate LogicManager + +LogicManager -> ClearCommand : execute() +activate ClearCommand + +create QuickCache +ClearCommand -> QuickCache +activate QuickCache + +QuickCache -> ClearCommand : emptyQC +deactivate QuickCache + +ClearCommand -> Model : setQuickCache(emptyQC) +activate Model + +Model -> ClearCommand +deactivate Model + +ClearCommand --> LogicManager : result +deactivate ClearCommand + +[<--LogicManager : result +deactivate LogicManager +destroy ClearCommand +@enduml diff --git a/docs/diagrams/ClearStatsActivityDiagram.puml b/docs/diagrams/ClearStatsActivityDiagram.puml new file mode 100644 index 00000000000..ec084102176 --- /dev/null +++ b/docs/diagrams/ClearStatsActivityDiagram.puml @@ -0,0 +1,22 @@ +@startuml +start +:User executes clearstats command; +:Model returns the previously filtered list; +:Search for flashcard matching the index given; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if () then ([given flashcard index is valid]) + :Get a copy of the flashcard with the + statistics set to zero for all attributes; + :Replace old flashcard with updated + flashcard; + :Pass the result to the UI; +else ([else]) + :Throw CommandException; + :Pass the CommandException to the UI; +endif + :UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/ClearStatsParserSequenceDiagram.puml b/docs/diagrams/ClearStatsParserSequenceDiagram.puml new file mode 100644 index 00000000000..87086de9442 --- /dev/null +++ b/docs/diagrams/ClearStatsParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse ClearStats Command +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":ClearStatsCommandParser" as ClearStatsCommandParser LOGIC_COLOR +participant "c:ClearStatsCommand" as ClearStatsCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("clearstats 1") +activate QuickCacheParser + +create ClearStatsCommandParser +QuickCacheParser -> ClearStatsCommandParser +activate ClearStatsCommandParser + +ClearStatsCommandParser -> QuickCacheParser +deactivate ClearStatsCommandParser + +QuickCacheParser -> ClearStatsCommandParser : parse("1") +activate ClearStatsCommandParser + +create ClearStatsCommand +ClearStatsCommandParser -> ClearStatsCommand +activate ClearStatsCommand + +ClearStatsCommand --> ClearStatsCommandParser : c +deactivate ClearStatsCommand + +ClearStatsCommandParser -> QuickCacheParser : c +deactivate ClearStatsCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +ClearStatsCommandParser -[hidden]-> QuickCacheParser +destroy ClearStatsCommandParser + +QuickCacheParser --> LogicManager : c +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/ClearStatsSequenceDiagram.puml b/docs/diagrams/ClearStatsSequenceDiagram.puml new file mode 100644 index 00000000000..3478b6bc5a2 --- /dev/null +++ b/docs/diagrams/ClearStatsSequenceDiagram.puml @@ -0,0 +1,64 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "c:ClearStatsCommand" as ClearStatsCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "lastShownList:ObservableList" as ObservableList MODEL_COLOR +participant "flashcardToClearStatistics:Flashcard" as Flashcard MODEL_COLOR +participant "updatedFlashcard:Flashcard" as UpdatedFlashcard MODEL_COLOR +end box + +[-> LogicManager : execute("clearstats 1") +activate LogicManager + +ref over LogicManager, ClearStatsCommand : Parse ClearStats Command + + +LogicManager -> ClearStatsCommand : execute() +activate ClearStatsCommand + +ClearStatsCommand -> Model : getFilteredFlashcardList() +activate Model + +Model --> ClearStatsCommand : lastShownList +deactivate Model + +ClearStatsCommand -> ObservableList : get(0) +activate ObservableList + +ObservableList --> ClearStatsCommand : flashcardToClearStatistics +deactivate ObservableList + +ClearStatsCommand -> Flashcard : getFlashcardAfterClearStatistics() +activate Flashcard + +create UpdatedFlashcard +Flashcard -> UpdatedFlashcard +activate UpdatedFlashcard + +UpdatedFlashcard --> Flashcard : updatedFlashcard +deactivate UpdatedFlashcard + +Flashcard --> ClearStatsCommand : updatedFlashcard +deactivate Flashcard + +ClearStatsCommand -> Model : setFlashcard(flashcardToClearStatistics, updatedFlashcard) +activate Model + +destroy Flashcard + +Model --> ClearStatsCommand +deactivate Model + +ClearStatsCommand --> LogicManager : result +deactivate ClearStatsCommand + +[<--LogicManager : result +deactivate LogicManager +destroy ClearStatsCommand +@enduml diff --git a/docs/diagrams/DeleteByIndexActivityDiagram.puml b/docs/diagrams/DeleteByIndexActivityDiagram.puml new file mode 100644 index 00000000000..38d2c712a28 --- /dev/null +++ b/docs/diagrams/DeleteByIndexActivityDiagram.puml @@ -0,0 +1,18 @@ +@startuml +scale max 300 height + +start + +:User executes delete by index command; +:QuickCache parses the user input; +if () then ([input is valid]) + :Delete the flashcard at the specified index; + :Pass the result to the UI; +else ([input is invalid]) + :Throw ParseException; + :Pass the ParseException to the UI; +endif +:UI displays the results to the User; + +stop +@enduml diff --git a/docs/diagrams/DeleteByTagActivityDiagram.puml b/docs/diagrams/DeleteByTagActivityDiagram.puml new file mode 100644 index 00000000000..ae8c5794c82 --- /dev/null +++ b/docs/diagrams/DeleteByTagActivityDiagram.puml @@ -0,0 +1,20 @@ +@startuml +scale max 300 height + +start + +:User executes delete by tag command; +:QuickCache parses the user input; +if () then ([input is valid]) + :Create predicates based on specified tags; + :Filter the model to get flashcards with the specified tags; + :Delete the flashcards; + :Pass the result to the UI; +else ([input is invalid]) + :Throw ParseException; + :Pass the ParseException to the UI; +endif +:UI displays the results to the User; + +stop +@enduml diff --git a/docs/diagrams/DeleteByTagParserSequenceDiagram.puml b/docs/diagrams/DeleteByTagParserSequenceDiagram.puml new file mode 100644 index 00000000000..60790cf39b1 --- /dev/null +++ b/docs/diagrams/DeleteByTagParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse DeleteByTagCommand +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR +participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("delete t/tag") +activate QuickCacheParser + +create DeleteCommandParser +QuickCacheParser -> DeleteCommandParser +activate DeleteCommandParser + +DeleteCommandParser -> QuickCacheParser +deactivate DeleteCommandParser + +QuickCacheParser -> DeleteCommandParser : parse("t/tag") +activate DeleteCommandParser + +create DeleteCommand +DeleteCommandParser -> DeleteCommand +activate DeleteCommand + +DeleteCommand --> DeleteCommandParser : d +deactivate DeleteCommand + +DeleteCommandParser -> QuickCacheParser : d +deactivate DeleteCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +DeleteCommandParser -[hidden]-> QuickCacheParser +destroy DeleteCommandParser + +QuickCacheParser --> LogicManager : d +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/DeleteByTagSequenceDiagram.puml b/docs/diagrams/DeleteByTagSequenceDiagram.puml new file mode 100644 index 00000000000..93bd83b688a --- /dev/null +++ b/docs/diagrams/DeleteByTagSequenceDiagram.puml @@ -0,0 +1,46 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box +[-> LogicManager : execute("delete t/tag") +activate LogicManager + +ref over LogicManager,DeleteCommand : Parse DeleteByTagCommand + +LogicManager -> DeleteCommand : execute() +activate DeleteCommand + +DeleteCommand -> Model : updateFilteredFlashcardList(pred) +activate Model +return + +DeleteCommand -> Model : getFilteredFlashcardList() +activate Model + +Model --> DeleteCommand : lastShownList +deactivate Model + +loop over each flashcard in lastShownList +DeleteCommand -> Model : deleteFlashcard(flashcard) +activate Model + +return + +end + +DeleteCommand -> LogicManager +deactivate DeleteCommand + +DeleteCommand -[hidden]-> LogicManager +destroy DeleteCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml index 1dc2311b245..fdded3fc473 100644 --- a/docs/diagrams/DeleteSequenceDiagram.puml +++ b/docs/diagrams/DeleteSequenceDiagram.puml @@ -48,7 +48,7 @@ deactivate AddressBookParser LogicManager -> DeleteCommand : execute() activate DeleteCommand -DeleteCommand -> Model : deletePerson(1) +DeleteCommand -> Model : deleteFlashcard(1) activate Model Model --> DeleteCommand diff --git a/docs/diagrams/EditActivityDiagram.puml b/docs/diagrams/EditActivityDiagram.puml new file mode 100644 index 00000000000..ef035aba4f8 --- /dev/null +++ b/docs/diagrams/EditActivityDiagram.puml @@ -0,0 +1,24 @@ +@startuml +scale max 500 height + +start +:User executes edit command; +:Model returns the previously filtered list; +:Search for flashcard matching the index given; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if () then ([given flashcard index is valid]) + :Create a new flashcard from + combining User-specified flashcard + and User-given descriptor; + :Replace User-specified flashcard with new flashcard; + :Pass edited flashcard to UI through feedback; +else ([else]) + :Throw CommandException; + :UI catches CommandException; +endif + :UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/EditParserSequenceDiagram.puml b/docs/diagrams/EditParserSequenceDiagram.puml new file mode 100644 index 00000000000..14a2ce8b0b1 --- /dev/null +++ b/docs/diagrams/EditParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse Edit Command +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":EditCommandParser" as EditCommandParser LOGIC_COLOR +participant "t:EditCommand" as EditCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("edit 1 ans/answer") +activate QuickCacheParser + +create EditCommandParser +QuickCacheParser -> EditCommandParser +activate EditCommandParser + +EditCommandParser -> QuickCacheParser +deactivate EditCommandParser + +QuickCacheParser -> EditCommandParser : parse("1 ans/answer") +activate EditCommandParser + +create EditCommand +EditCommandParser -> EditCommand +activate EditCommand + +EditCommand --> EditCommandParser : t +deactivate EditCommand + +EditCommandParser -> QuickCacheParser : t +deactivate EditCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +EditCommandParser -[hidden]-> QuickCacheParser +destroy EditCommandParser + +QuickCacheParser --> LogicManager : t +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/EditSequenceDiagram.puml b/docs/diagrams/EditSequenceDiagram.puml new file mode 100644 index 00000000000..8d84cb0d3d1 --- /dev/null +++ b/docs/diagrams/EditSequenceDiagram.puml @@ -0,0 +1,62 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "t:EditCommand" as EditCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant ":QuickCache" as QuickCache MODEL_COLOR +participant "flashcards:UniqueFlashcardList" as Flashcards MODEL_COLOR +participant "internalList:ObservableList" as ObservableList MODEL_COLOR +end box + +[-> LogicManager : execute("edit 1 ans/answer") +activate LogicManager + +ref over LogicManager, EditCommand : Parse Edit Command + +LogicManager -> EditCommand : execute() +activate EditCommand + +EditCommand -> Model : getFilteredFlashcardList() +activate Model + +Model --> EditCommand : lastShownList +deactivate Model + +EditCommand ->EditCommand : createEditedFlashcard(flashcard, descriptor) +activate EditCommand + +EditCommand ->EditCommand : editedFlashcard +deactivate EditCommand + +EditCommand -> Model : setFlashcard(flashcard, editedFlashcard) +activate Model + +Model -> QuickCache :setFlashcard(flashcard, editedFlashcard) +activate QuickCache + +QuickCache -> Flashcards :setFlashcard(flashcard, editedFlashcard) +activate Flashcards + +Flashcards -> ObservableList : setFlashcard(flashcard, editedFlashcard) +activate ObservableList +return + +return + +return + +return + +return result + +EditCommand -[hidden]-> LogicManager +destroy EditCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/ExportActivityDiagram.puml b/docs/diagrams/ExportActivityDiagram.puml new file mode 100644 index 00000000000..138e7bc5071 --- /dev/null +++ b/docs/diagrams/ExportActivityDiagram.puml @@ -0,0 +1,11 @@ +@startuml +start +:User executes export command; +:Model returns the previously filtered list; +:New QuickCache is created; +:Previously filtered list is copied into new QuickCache; +:Storage exports QuickCache into specified output file; +:Pass the result to the UI; +:UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/ExportParserSequenceDiagram.puml b/docs/diagrams/ExportParserSequenceDiagram.puml new file mode 100644 index 00000000000..0d87b243adb --- /dev/null +++ b/docs/diagrams/ExportParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse Export Command +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":ExportCommandParser" as ExportCommandParser LOGIC_COLOR +participant "t:ExportCommand" as ExportCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("export out.json") +activate QuickCacheParser + +create ExportCommandParser +QuickCacheParser -> ExportCommandParser +activate ExportCommandParser + +ExportCommandParser -> QuickCacheParser +deactivate ExportCommandParser + +QuickCacheParser -> ExportCommandParser : parse("out.json") +activate ExportCommandParser + +create ExportCommand +ExportCommandParser -> ExportCommand +activate ExportCommand + +ExportCommand --> ExportCommandParser : t +deactivate ExportCommand + +ExportCommandParser -> QuickCacheParser : t +deactivate ExportCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +ExportCommandParser -[hidden]-> QuickCacheParser +destroy ExportCommandParser + +QuickCacheParser --> LogicManager : t +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/ExportSequenceDiagram.puml b/docs/diagrams/ExportSequenceDiagram.puml new file mode 100644 index 00000000000..87b0a21f67c --- /dev/null +++ b/docs/diagrams/ExportSequenceDiagram.puml @@ -0,0 +1,65 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "t:ExportCommand" as ExportCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "lastShownList:ObservableList" as ObservableList MODEL_COLOR +participant ":Storage" as Storage MODEL_COLOR +participant "lastShownQC:QuickCache" as QuickCache MODEL_COLOR +end box +[-> LogicManager : execute("export out.json") +activate LogicManager + +ref over LogicManager, ExportCommand : Parse Export Command + +LogicManager -> ExportCommand : execute() +activate ExportCommand + +ExportCommand -> Model : getFilteredFlashcardList() +activate Model + +Model -> ObservableList +activate ObservableList + +ObservableList -> Model +deactivate ObservableList + +Model --> ExportCommand : lastShownList +deactivate Model + +create QuickCache +ExportCommand -> QuickCache +activate QuickCache + +QuickCache -> ExportCommand : lastShownQC +deactivate QuickCache + +ExportCommand -> QuickCache : setFlashcards(lastShownList) +activate QuickCache + +QuickCache -> ExportCommand +deactivate QuickCache + +ExportCommand -> Storage : saveQuickCache(lastShownQC) +activate Storage + +Storage -> ExportCommand +deactivate Storage + +ExportCommand --> LogicManager : result +deactivate ExportCommand +ExportCommand -[hidden]-> LogicManager : result +destroy QuickCache +destroy Storage +destroy ExportCommand + +[<--LogicManager +deactivate LogicManager + + +@enduml diff --git a/docs/diagrams/FindActivityDiagram.puml b/docs/diagrams/FindActivityDiagram.puml new file mode 100644 index 00000000000..513da715a49 --- /dev/null +++ b/docs/diagrams/FindActivityDiagram.puml @@ -0,0 +1,21 @@ +@startuml +scale max 500 height + +start + +:User executes find command; +:QuickCache parses the user input; +if () then ([input is valid]) + :Create predicate based on + specified tags and specified keywords; + :Filter the model to get flashcards with + both the specified tags + and keywords using the predicate; + :Command result is passed to UI; +else ([else]) + :Throw CommandException; + :UI catches CommandException; +endif + :UI displays filtered flashcard list to User; +stop +@enduml diff --git a/docs/diagrams/FindParserSequenceDiagram.puml b/docs/diagrams/FindParserSequenceDiagram.puml new file mode 100644 index 00000000000..269c7cef753 --- /dev/null +++ b/docs/diagrams/FindParserSequenceDiagram.puml @@ -0,0 +1,92 @@ +@startuml +!include style.puml + +group Parse Find Command + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":FindCommandParser" as FindCommandParser LOGIC_COLOR +participant "f:FindCommand" as FindCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":FlashcardContainsTagPredicate" as FlashcardContainsTagPredicate MODEL_COLOR +participant ":QuestionContainsKeywordsPredicate" as QuestionContainsKeywordsPredicate MODEL_COLOR +participant "predicate:FlashcardPredicate" as FlashcardPredicate MODEL_COLOR +end box + +LogicManager -> QuickCacheParser : parseCommand("find t/MCQ q/What") +activate QuickCacheParser + +create FindCommandParser +QuickCacheParser -> FindCommandParser +activate FindCommandParser + +FindCommandParser --> QuickCacheParser +deactivate FindCommandParser + +QuickCacheParser -> FindCommandParser : parse(" t/MCQ q/What") +activate FindCommandParser + +FindCommandParser -> FindCommandParser : getFlashcardPredicate(tags, keywords) +note left +Either opt +condition will +definitely be +fulfilled due to +parser constraints +end note +activate FindCommandParser + +opt findingTags + create FlashcardContainsTagPredicate + FindCommandParser -> FlashcardContainsTagPredicate : new FlashcardContainsTagPredicate(tags) + activate FlashcardContainsTagPredicate + + FlashcardContainsTagPredicate --> FindCommandParser + deactivate FlashcardContainsTagPredicate +end opt + +opt findingKeywords + create QuestionContainsKeywordsPredicate + FindCommandParser -> QuestionContainsKeywordsPredicate : new QuestionContainsKeywordsPredicate(keywords) + activate QuestionContainsKeywordsPredicate + + QuestionContainsKeywordsPredicate --> FindCommandParser + deactivate QuestionContainsKeywordsPredicate +end opt + +create FlashcardPredicate +FindCommandParser -> FlashcardPredicate : new FlashcardPredicate(predicates) +note left +FlashcardPredicate +compiles all created +predicates +end note +activate FlashcardPredicate + +FlashcardPredicate --> FindCommandParser : predicate +deactivate FlashcardPredicate + +FindCommandParser --> FindCommandParser : predicate +deactivate FindCommandParser + +create FindCommand +FindCommandParser -> FindCommand : new FindCommand(predicate) +activate FindCommand + +FindCommand --> FindCommandParser : f +deactivate FindCommand + +FindCommandParser --> QuickCacheParser: f +deactivate FindCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +FindCommandParser -[hidden]-> QuickCacheParser +destroy FindCommandParser + +QuickCacheParser --> LogicManager : f +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/FindSequenceDiagram.puml b/docs/diagrams/FindSequenceDiagram.puml new file mode 100644 index 00000000000..2d9642c78f0 --- /dev/null +++ b/docs/diagrams/FindSequenceDiagram.puml @@ -0,0 +1,40 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "f:FindCommand" as FindCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "filteredFlashcards:FilteredList" as FilteredList MODEL_COLOR +end box + +[-> LogicManager : execute("find t/MCQ q/What") +activate LogicManager + +ref over LogicManager, FindCommand : Parse Find Command + +LogicManager -> FindCommand : execute() +activate FindCommand + +FindCommand -> Model : updateFilteredFlashcardList(predicate) +activate Model + +Model -> FilteredList : setPredicate(predicate) +activate FilteredList + +FilteredList --> Model +deactivate FilteredList + +Model --> FindCommand +deactivate Model + +FindCommand --> LogicManager : result +deactivate FindCommand + +[<--LogicManager : result +deactivate LogicManager +destroy FindCommand +@enduml diff --git a/docs/diagrams/FlashcardClassDiagram.puml b/docs/diagrams/FlashcardClassDiagram.puml new file mode 100644 index 00000000000..181e3bf524d --- /dev/null +++ b/docs/diagrams/FlashcardClassDiagram.puml @@ -0,0 +1,36 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + + +package Flashcard <> { +class MultipleChoiceQuestion +class OpenEndedQuestion +interface Question <> +class Answer +class Choice +class Tag +class Difficulty +class Flashcard +class Statistics +} + +Class HiddenOutside #FFFFFF + +MultipleChoiceQuestion -[dashed]-|> Question +OpenEndedQuestion -[dashed]-|> Question +MultipleChoiceQuestion *--> "1..*" Choice +MultipleChoiceQuestion *--> "1" Answer +OpenEndedQuestion *--> "1" Answer + +Flashcard *--> "1" Question +Flashcard *--> "*" Tag +Flashcard *--> "1" Difficulty +Flashcard *--> "1" Statistics + + +UniqueFlashcardList o--> "*" Flashcard +QuickCache *--> "1" UniqueFlashcardList +@enduml diff --git a/docs/diagrams/ImportActivityDiagram.puml b/docs/diagrams/ImportActivityDiagram.puml new file mode 100644 index 00000000000..1f682a9cb7f --- /dev/null +++ b/docs/diagrams/ImportActivityDiagram.puml @@ -0,0 +1,9 @@ +@startuml +start +:User executes import command; +:Storage reads the specified import file; +:Flashcards from the read is added into local QuickCache; +:Pass the result to the UI; +:UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/ImportParserSequenceDiagram.puml b/docs/diagrams/ImportParserSequenceDiagram.puml new file mode 100644 index 00000000000..f00268602de --- /dev/null +++ b/docs/diagrams/ImportParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse Import Command +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":ImportCommandParser" as ImportCommandParser LOGIC_COLOR +participant "i:ImportCommand" as ImportCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("import in.json") +activate QuickCacheParser + +create ImportCommandParser +QuickCacheParser -> ImportCommandParser +activate ImportCommandParser + +ImportCommandParser -> QuickCacheParser +deactivate ImportCommandParser + +QuickCacheParser -> ImportCommandParser : parse("in.json") +activate ImportCommandParser + +create ImportCommand +ImportCommandParser -> ImportCommand +activate ImportCommand + +ImportCommand --> ImportCommandParser : i +deactivate ImportCommand + +ImportCommandParser -> QuickCacheParser : i +deactivate ImportCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +ImportCommandParser -[hidden]-> QuickCacheParser +destroy ImportCommandParser + +QuickCacheParser --> LogicManager : i +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/ImportSequenceDiagram.puml b/docs/diagrams/ImportSequenceDiagram.puml new file mode 100644 index 00000000000..58efdb45c6f --- /dev/null +++ b/docs/diagrams/ImportSequenceDiagram.puml @@ -0,0 +1,54 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "i:ImportCommand" as ImportCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant ":Storage" as Storage MODEL_COLOR +end box +[-> LogicManager : execute("import in.json") +activate LogicManager + +ref over LogicManager, ImportCommand : Parse Import Command + +LogicManager -> ImportCommand : execute() +activate ImportCommand + +ImportCommand -> Storage : readQuickCache() +activate Storage + +Storage -> ImportCommand : readBack +deactivate Storage + +loop over each flashcard in readBack +ImportCommand -> Model : hasFlashcard(flashcard) +activate Model + +Model -> ImportCommand : hasFlashcard +deactivate Model + +alt !hasFlashcard +ImportCommand -> Model : addFlashcard(flashcard) +activate Model + +Model -> ImportCommand +deactivate Model +end + +end + +ImportCommand --> LogicManager : result +deactivate ImportCommand +ImportCommand -[hidden]-> LogicManager : result +destroy Storage +destroy ImportCommand + +[<--LogicManager +deactivate LogicManager + + +@enduml diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml index 016ef33e2e2..1a8fe09d61c 100644 --- a/docs/diagrams/LogicClassDiagram.puml +++ b/docs/diagrams/LogicClassDiagram.puml @@ -8,7 +8,7 @@ package Logic { package Parser { Interface Parser <> -Class AddressBookParser +Class QuickCacheParser Class XYZCommandParser Class CliSyntax Class ParserUtil @@ -35,8 +35,8 @@ Class HiddenOutside #FFFFFF HiddenOutside ..> Logic LogicManager .up.|> Logic -LogicManager -->"1" AddressBookParser -AddressBookParser .left.> XYZCommandParser: creates > +LogicManager -->"1" QuickCacheParser +QuickCacheParser .left.> XYZCommandParser: creates > XYZCommandParser ..> XYZCommand : creates > XYZCommandParser ..|> Parser diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index e85a00d4107..40b948229da 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -4,53 +4,57 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR -Package Model <>{ -Interface ReadOnlyAddressBook <> +Package Model <> { +Class ModelManager Interface Model <> Interface ObservableList <> -Class AddressBook -Class ReadOnlyAddressBook -Class Model -Class ModelManager +Interface ReadOnlyQuickCache <> +Class QuickCache Class UserPrefs -Class ReadOnlyUserPrefs - -Package Person { -Class Person -Class Address -Class Email -Class Name -Class Phone -Class UniquePersonList -} - -Package Tag { -Class Tag +Interface ReadOnlyUserPrefs <> + +package Flashcard <> { +class MultipleChoiceQuestion +class OpenEndedQuestion +interface Question <> +class Answer +class Choice +class Tag +class Difficulty +class UniqueFlashcardList +class Flashcard +class Statistics } } Class HiddenOutside #FFFFFF -HiddenOutside ..> Model -AddressBook .up.|> ReadOnlyAddressBook +MultipleChoiceQuestion -[dashed]-|> Question +OpenEndedQuestion -[dashed]-|> Question +MultipleChoiceQuestion *--> "1..*" Choice +MultipleChoiceQuestion *--> "1" Answer +OpenEndedQuestion *--> "1" Answer -ModelManager .up.|> Model -Model .right.> ObservableList -ModelManager o--> "1" AddressBook -ModelManager o-left-> "1" UserPrefs -UserPrefs .up.|> ReadOnlyUserPrefs +Flashcard *--> "1" Question +Flashcard *--> "*" Tag +Flashcard *--> "1" Difficulty +Flashcard *--> "1" Statistics -AddressBook *--> "1" UniquePersonList -UniquePersonList o--> "*" Person -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address -Person *--> "*" Tag -Name -[hidden]right-> Phone -Phone -[hidden]right-> Address -Address -[hidden]right-> Email +UniqueFlashcardList o--> "*" Flashcard +QuickCache *--> "1" UniqueFlashcardList +QuickCache -[dashed]-|> ReadOnlyQuickCache + + +ModelManager o--> "1" QuickCache +ModelManager -[dashed]up-|> Model +ModelManager o-right-> "1" UserPrefs +ModelManager --> "*" Flashcard : filtered list +UserPrefs -[dashed]-|> ReadOnlyUserPrefs +Model -[dashed]-> ObservableList + +HiddenOutside ..> Model -ModelManager -->"1" Person : filtered list +hide empty members +hide circle @enduml diff --git a/docs/diagrams/OpenFlashcardActivityDiagram.puml b/docs/diagrams/OpenFlashcardActivityDiagram.puml new file mode 100644 index 00000000000..13f9c2095ed --- /dev/null +++ b/docs/diagrams/OpenFlashcardActivityDiagram.puml @@ -0,0 +1,19 @@ +@startuml +start +:User executes open command; +:QuickCache parse the input from user; +:Model returns the previously filtered list; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if () then ([index larger than size of the list]) + :Throw CommandException; + :Pass the CommandException to UI; +else ([else]) + :Get the flashcard from the list; + :Pass flashcard details to UI; +endif +:UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/OpenParserSequenceDiagram.puml b/docs/diagrams/OpenParserSequenceDiagram.puml new file mode 100644 index 00000000000..8e6c3efa21e --- /dev/null +++ b/docs/diagrams/OpenParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse Open Command +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":OpenCommandParser" as OpenCommandParser LOGIC_COLOR +participant "o:OpenCommand" as OpenCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("open 1") +activate QuickCacheParser + +create OpenCommandParser +QuickCacheParser -> OpenCommandParser +activate OpenCommandParser + +OpenCommandParser -> QuickCacheParser +deactivate OpenCommandParser + +QuickCacheParser -> OpenCommandParser : parse("1") +activate OpenCommandParser + +create OpenCommand +OpenCommandParser -> OpenCommand +activate OpenCommand + +OpenCommand --> OpenCommandParser : o +deactivate OpenCommand + +OpenCommandParser -> QuickCacheParser : o +deactivate OpenCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +OpenCommandParser -[hidden]-> QuickCacheParser +destroy OpenCommandParser + +QuickCacheParser --> LogicManager : o +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/OpenSequenceDiagram.puml b/docs/diagrams/OpenSequenceDiagram.puml new file mode 100644 index 00000000000..56dd20a3fd0 --- /dev/null +++ b/docs/diagrams/OpenSequenceDiagram.puml @@ -0,0 +1,47 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "o:OpenCommand" as OpenCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "lastShownList:ObservableList" as ObservableList MODEL_COLOR +participant "flashcardToOpen:Flashcard" as Flashcard MODEL_COLOR +end box + +[-> LogicManager : execute("open 1") +activate LogicManager + +ref over LogicManager, OpenCommand : Parse Open Command + +LogicManager -> OpenCommand : execute() +activate OpenCommand + +OpenCommand -> Model : getFilteredFlashcardList() +activate Model + +Model --> OpenCommand : lastShownList +deactivate Model + +OpenCommand -> ObservableList : get(0) +activate ObservableList + +ObservableList --> OpenCommand : flashcardToOpen +deactivate ObservableList + +OpenCommand -> Flashcard : getQuestion() +activate Flashcard + +Flashcard --> OpenCommand : question +deactivate Flashcard + +OpenCommand --> LogicManager : result +deactivate OpenCommand + +[<--LogicManager : result +deactivate LogicManager +destroy OpenCommand +@enduml diff --git a/docs/diagrams/StatsActivityDiagram.puml b/docs/diagrams/StatsActivityDiagram.puml new file mode 100644 index 00000000000..da1512139da --- /dev/null +++ b/docs/diagrams/StatsActivityDiagram.puml @@ -0,0 +1,19 @@ +@startuml +start +:User executes stats command; +:Model returns the previously filtered list; +:Search for flashcard matching the index given; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if () then ([given flashcard index is valid]) + :Get statistics of specified flashcard; + :Pass the result to the UI; +else ([else]) + :Throw CommandException; + :Pass the CommandException to the UI; +endif + :UI displays results to User; +stop +@enduml diff --git a/docs/diagrams/StatsByTagActivityDiagram.puml b/docs/diagrams/StatsByTagActivityDiagram.puml new file mode 100644 index 00000000000..2e91e782112 --- /dev/null +++ b/docs/diagrams/StatsByTagActivityDiagram.puml @@ -0,0 +1,20 @@ +@startuml +scale max 300 height + +start +:User executes stats by tag command; +:QuickCache parses the user input; + +if () then ([input is valid]) + :Create predicates based on specified tags; + :Filter the model to get flashcards with the specified tags; + :Get aggregated statistics of the flashcards; + :Pass the result to the UI; +else ([input is invalid]) + :Throw ParseException; + :Pass the ParseException to the UI; +endif +:UI displays the results to the User; + +stop +@enduml diff --git a/docs/diagrams/StatsByTagParserSequenceDiagram.puml b/docs/diagrams/StatsByTagParserSequenceDiagram.puml new file mode 100644 index 00000000000..d01f76610ed --- /dev/null +++ b/docs/diagrams/StatsByTagParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse StatsByTagCommand +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":StatsCommandParser" as StatsCommandParser LOGIC_COLOR +participant "s:StatsCommand" as StatsCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("stats t/tag") +activate QuickCacheParser + +create StatsCommandParser +QuickCacheParser -> StatsCommandParser +activate StatsCommandParser + +StatsCommandParser -> QuickCacheParser +deactivate StatsCommandParser + +QuickCacheParser -> StatsCommandParser : parse("t/tag") +activate StatsCommandParser + +create StatsCommand +StatsCommandParser -> StatsCommand +activate StatsCommand + +StatsCommand --> StatsCommandParser : s +deactivate StatsCommand + +StatsCommandParser -> QuickCacheParser : s +deactivate StatsCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +StatsCommandParser -[hidden]-> QuickCacheParser +destroy StatsCommandParser + +QuickCacheParser --> LogicManager : s +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/StatsByTagSequenceDiagram.puml b/docs/diagrams/StatsByTagSequenceDiagram.puml new file mode 100644 index 00000000000..f18ddc2e09f --- /dev/null +++ b/docs/diagrams/StatsByTagSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "d:StatsCommand" as StatsCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box +[-> LogicManager : execute("delete t/tag") +activate LogicManager + +ref over LogicManager,StatsCommand : Parse StatsByTagCommand + +LogicManager -> StatsCommand : execute() +activate StatsCommand + +StatsCommand -> Model : updateFilteredFlashcardList(pred) +activate Model +return + +StatsCommand -> Model : getFilteredFlashcardList() +activate Model + +Model --> StatsCommand : lastShownList +deactivate Model + +StatsCommand -> StatsCommand : getAggregatedStatistics(lastShownList) +activate StatsCommand + +StatsCommand -> StatsCommand +deactivate StatsCommand + +StatsCommand -> LogicManager : result +deactivate StatsCommand + +StatsCommand -[hidden]-> LogicManager +destroy StatsCommand + +[<--LogicManager : result +deactivate LogicManager +@enduml diff --git a/docs/diagrams/StatsParserSequenceDiagram.puml b/docs/diagrams/StatsParserSequenceDiagram.puml new file mode 100644 index 00000000000..f816e944840 --- /dev/null +++ b/docs/diagrams/StatsParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse Stats Command +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":StatsCommandParser" as StatsCommandParser LOGIC_COLOR +participant "s:StatsCommand" as StatsCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("stats 1") +activate QuickCacheParser + +create StatsCommandParser +QuickCacheParser -> StatsCommandParser +activate StatsCommandParser + +StatsCommandParser -> QuickCacheParser +deactivate StatsCommandParser + +QuickCacheParser -> StatsCommandParser : parse(" 1") +activate StatsCommandParser + +create StatsCommand +StatsCommandParser -> StatsCommand +activate StatsCommand + +StatsCommand --> StatsCommandParser : s +deactivate StatsCommand + +StatsCommandParser -> QuickCacheParser : s +deactivate StatsCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +StatsCommandParser -[hidden]-> QuickCacheParser +destroy StatsCommandParser + +QuickCacheParser --> LogicManager : s +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/StatsSequenceDiagram.puml b/docs/diagrams/StatsSequenceDiagram.puml new file mode 100644 index 00000000000..56707341e71 --- /dev/null +++ b/docs/diagrams/StatsSequenceDiagram.puml @@ -0,0 +1,53 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "s:StatsCommand" as StatsCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "lastShownList:ObservableList" as ObservableList MODEL_COLOR +participant "flashcardToDisplayStatistics:Flashcard" as Flashcard MODEL_COLOR +end box + +[-> LogicManager : execute("stats 1") +activate LogicManager + +ref over LogicManager, StatsCommand : Parse Stats Command + +LogicManager -> StatsCommand : execute() +activate StatsCommand + +StatsCommand -> Model : getFilteredFlashcardList() +activate Model + +Model --> StatsCommand : lastShownList +deactivate Model + +StatsCommand -> ObservableList : get(0) +activate ObservableList + +ObservableList --> StatsCommand : flashcardToDisplayStatistics +deactivate ObservableList + +StatsCommand -> Flashcard : getQuestion() +activate Flashcard + +Flashcard --> StatsCommand : question +deactivate Flashcard + +StatsCommand -> Flashcard : getStatistics() +activate Flashcard + +Flashcard --> StatsCommand : statistics +deactivate Flashcard + +StatsCommand --> LogicManager : result +deactivate StatsCommand + +[<--LogicManager : result +deactivate LogicManager +destroy StatsCommand +@enduml diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 6adb2e156bf..191c745a2a8 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -6,19 +6,19 @@ skinparam classBackgroundColor STORAGE_COLOR Interface Storage <> Interface UserPrefsStorage <> -Interface AddressBookStorage <> +Interface QuickCacheStorage <> Class StorageManager Class JsonUserPrefsStorage -Class JsonAddressBookStorage +Class JsonQuickCacheStorage StorageManager .left.|> Storage StorageManager o-right-> UserPrefsStorage -StorageManager o--> AddressBookStorage +StorageManager o--> QuickCacheStorage JsonUserPrefsStorage .left.|> UserPrefsStorage -JsonAddressBookStorage .left.|> AddressBookStorage -JsonAddressBookStorage .down.> JsonSerializableAddressBookStorage -JsonSerializableAddressBookStorage .right.> JsonSerializablePerson -JsonSerializablePerson .right.> JsonAdaptedTag +JsonQuickCacheStorage .left.|> QuickCacheStorage +JsonQuickCacheStorage .down.> JsonSerializableQuickCacheStorage +JsonSerializableQuickCacheStorage .right.> JsonSerializableQuickCache +JsonSerializableQuickCache .right.> JsonAdaptedTag @enduml diff --git a/docs/diagrams/TestActivityDiagram.puml b/docs/diagrams/TestActivityDiagram.puml new file mode 100644 index 00000000000..7c2f6fe25b3 --- /dev/null +++ b/docs/diagrams/TestActivityDiagram.puml @@ -0,0 +1,23 @@ +@startuml +start +:User executes test command; +:Model returns the previously filtered list; +:Search for flashcard matching the index given; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if () then ([given answer is correct]) + :Get updated flashcard reflecting + that a correct answer was given; + +else ([else]) + :Get updated flashcard reflecting + that an incorrect answer was given; +endif + :Replace old flashcard + with updated flashcard; + :Pass the result to the UI; + :UI displays the results to the User; +stop +@enduml diff --git a/docs/diagrams/TestParserSequenceDiagram.puml b/docs/diagrams/TestParserSequenceDiagram.puml new file mode 100644 index 00000000000..160d05b0eeb --- /dev/null +++ b/docs/diagrams/TestParserSequenceDiagram.puml @@ -0,0 +1,44 @@ +@startuml +!include style.puml + +group Parse Test Command +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":QuickCacheParser" as QuickCacheParser LOGIC_COLOR +participant ":TestCommandParser" as TestCommandParser LOGIC_COLOR +participant "t:TestCommand" as TestCommand LOGIC_COLOR +end box + +activate LogicManager + +LogicManager -> QuickCacheParser : parseCommand("test 1 ans/Example Answer") +activate QuickCacheParser + +create TestCommandParser +QuickCacheParser -> TestCommandParser +activate TestCommandParser + +TestCommandParser -> QuickCacheParser +deactivate TestCommandParser + +QuickCacheParser -> TestCommandParser : parse("1 ans/Example Answer") +activate TestCommandParser + +create TestCommand +TestCommandParser -> TestCommand +activate TestCommand + +TestCommand --> TestCommandParser : t +deactivate TestCommand + +TestCommandParser -> QuickCacheParser : t +deactivate TestCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +TestCommandParser -[hidden]-> QuickCacheParser +destroy TestCommandParser + +QuickCacheParser --> LogicManager : t +deactivate QuickCacheParser +end +@enduml diff --git a/docs/diagrams/TestSequenceDiagram.puml b/docs/diagrams/TestSequenceDiagram.puml new file mode 100644 index 00000000000..5d2e2a18f19 --- /dev/null +++ b/docs/diagrams/TestSequenceDiagram.puml @@ -0,0 +1,104 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "t:TestCommand" as TestCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "lastShownList:ObservableList" as ObservableList MODEL_COLOR +participant "flashcard:Flashcard" as Flashcard MODEL_COLOR +participant "updatedFlashcard:Flashcard" as UpdatedFlashcard MODEL_COLOR +end box +[-> LogicManager : execute("test 1 ans/Example answer") +activate LogicManager + +ref over LogicManager, TestCommand : Parse Test Command + +LogicManager -> TestCommand : execute() +activate TestCommand + +TestCommand -> Model : getFilteredFlashcardList() +activate Model + +Model -> ObservableList +activate ObservableList + +ObservableList -> Model +deactivate ObservableList + +Model --> TestCommand : lastShownList +deactivate Model + +TestCommand -> ObservableList : get(index) +activate ObservableList + +ObservableList -> Flashcard +activate Flashcard + +Flashcard -> ObservableList +deactivate Flashcard + +ObservableList -> TestCommand : flashcard +deactivate ObservableList + +TestCommand -> Flashcard : checkAnswer(answer) +activate Flashcard + +Flashcard -> TestCommand : isCorrect +deactivate Flashcard + +alt is correct + + TestCommand -> Flashcard : getFlashcardAfterTestSuccess() + activate Flashcard + + create UpdatedFlashcard + Flashcard -> UpdatedFlashcard : getFlashcardAfterTestSuccess() + activate UpdatedFlashcard + + UpdatedFlashcard -> Flashcard + deactivate UpdatedFlashcard + + Flashcard -> TestCommand : updatedFlashcard + deactivate Flashcard + +else is not correct + + TestCommand -> Flashcard : getFlashcardAfterTestFailure() + activate Flashcard + + create UpdatedFlashcard + Flashcard -> UpdatedFlashcard : getFlashcardAfterTestFailure() + activate UpdatedFlashcard + + UpdatedFlashcard -> Flashcard + deactivate UpdatedFlashcard + + Flashcard -> TestCommand : updatedFlashcard + deactivate Flashcard + +end + +TestCommand -> Model : setFlashcard(f, updated) +activate Model + +Model -> Flashcard +activate Flashcard + +Flashcard -> Model +destroy Flashcard + +Model -> TestCommand +deactivate Model + +TestCommand --> LogicManager : result +deactivate TestCommand +TestCommand -[hidden]-> LogicManager : result +destroy TestCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/TestState0.puml b/docs/diagrams/TestState0.puml new file mode 100644 index 00000000000..303a0cc6ba5 --- /dev/null +++ b/docs/diagrams/TestState0.puml @@ -0,0 +1,20 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title Initial state + +package States { + class State1 as "__initial:Flashcard__" + class State2 as "__afterCorrect:Flashcard__" + class State3 as "__afterWrong:Flashcard__" +} +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 +hide State2 +hide State3 + +class Pointer as "Current State" #FFFFF +Pointer -up-> State1 +@end diff --git a/docs/diagrams/TestState1.puml b/docs/diagrams/TestState1.puml new file mode 100644 index 00000000000..4793265d443 --- /dev/null +++ b/docs/diagrams/TestState1.puml @@ -0,0 +1,19 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title After command "test 1 ans/correct answer" + +package States { + class State1 as "__initial:Flashcard__" + class State2 as "__afterCorrect:Flashcard__" + class State3 as "__afterWrong:Flashcard__" +} +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 +hide State3 + +class Pointer as "Current State" #FFFFF +Pointer -up-> State2 +@end diff --git a/docs/diagrams/TestState2.puml b/docs/diagrams/TestState2.puml new file mode 100644 index 00000000000..cf8c0c1a836 --- /dev/null +++ b/docs/diagrams/TestState2.puml @@ -0,0 +1,19 @@ +@startuml +!include style.puml +skinparam ClassFontColor #000000 +skinparam ClassBorderColor #000000 + +title After command "test 1 ans/wrong answer" + +package States { + class State1 as "__initial:Flashcard__" + class State2 as "__afterCorrect:Flashcard__" + class State3 as "__afterWrong:Flashcard__" +} +State1 -[hidden]right-> State2 +State2 -[hidden]right-> State3 +hide State2 + +class Pointer as "Current State" #FFFFF +Pointer -up-> State3 +@end diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml index 92746f9fcf7..825936c5e54 100644 --- a/docs/diagrams/UiClassDiagram.puml +++ b/docs/diagrams/UiClassDiagram.puml @@ -11,10 +11,13 @@ Class UiManager Class MainWindow Class HelpWindow Class ResultDisplay -Class PersonListPanel -Class PersonCard +Class FlashcardListPanel +Class FlashcardDisplay Class StatusBarFooter Class CommandBox +Class OptionListPanel +Class OptionCard +Class PieChartDisplay } package Model <> { @@ -33,25 +36,33 @@ UiManager -down-> MainWindow MainWindow --> HelpWindow MainWindow *-down-> CommandBox MainWindow *-down-> ResultDisplay -MainWindow *-down-> PersonListPanel +MainWindow *-down-> FlashcardListPanel MainWindow *-down-> StatusBarFooter +MainWindow *-down-> OptionListPanel +MainWindow *-down-> PieChartDisplay -PersonListPanel -down-> PersonCard +FlashcardListPanel -down-> FlashcardDisplay +OptionListPanel -down-> OptionCard MainWindow -left-|> UiPart ResultDisplay --|> UiPart CommandBox --|> UiPart -PersonListPanel --|> UiPart -PersonCard --|> UiPart +FlashcardListPanel --|> UiPart +FlashcardDisplay --|> UiPart StatusBarFooter --|> UiPart HelpWindow -down-|> UiPart +OptionListPanel --|> UiPart +PieChartDisplay --|> UiPart -PersonCard ..> Model +FlashcardDisplay ..> Model UiManager -right-> Logic MainWindow -left-> Logic -PersonListPanel -[hidden]left- HelpWindow + +OptionListPanel -[hidden]left- FlashcardListPanel +FlashcardListPanel -[hidden]left- PieChartDisplay +PieChartDisplay -[hidden]left- HelpWindow HelpWindow -[hidden]left- CommandBox CommandBox -[hidden]left- ResultDisplay ResultDisplay -[hidden]left- StatusBarFooter diff --git a/docs/diagrams/plantuml.jar b/docs/diagrams/plantuml.jar new file mode 100644 index 00000000000..f98d59548f4 Binary files /dev/null and b/docs/diagrams/plantuml.jar differ diff --git a/docs/diagrams/tracing/LogicSequenceDiagram.puml b/docs/diagrams/tracing/LogicSequenceDiagram.puml index fdcbe1c0ccc..aa7b04b5759 100644 --- a/docs/diagrams/tracing/LogicSequenceDiagram.puml +++ b/docs/diagrams/tracing/LogicSequenceDiagram.puml @@ -13,7 +13,7 @@ create ecp abp -> ecp abp -> ecp ++: parse(arguments) create ec -ecp -> ec ++: index, editPersonDescriptor +ecp -> ec ++: index, editFlashcardDescriptor ec --> ecp -- ecp --> abp --: command abp --> logic --: command diff --git a/docs/favicon.png b/docs/favicon.png new file mode 100644 index 00000000000..7c19e86da3d Binary files /dev/null and b/docs/favicon.png differ diff --git a/docs/images/AddMcqActivityDiagram.png b/docs/images/AddMcqActivityDiagram.png new file mode 100644 index 00000000000..2fb7a50a6a8 Binary files /dev/null and b/docs/images/AddMcqActivityDiagram.png differ diff --git a/docs/images/AddMcqParserSequenceDiagram.png b/docs/images/AddMcqParserSequenceDiagram.png new file mode 100644 index 00000000000..1cf5d237354 Binary files /dev/null and b/docs/images/AddMcqParserSequenceDiagram.png differ diff --git a/docs/images/AddMcqSequenceDiagram.png b/docs/images/AddMcqSequenceDiagram.png new file mode 100644 index 00000000000..b0d2b438bda Binary files /dev/null and b/docs/images/AddMcqSequenceDiagram.png differ diff --git a/docs/images/AddOpenEndedActivityDiagram.png b/docs/images/AddOpenEndedActivityDiagram.png new file mode 100644 index 00000000000..69fb1f4e319 Binary files /dev/null and b/docs/images/AddOpenEndedActivityDiagram.png differ diff --git a/docs/images/AddOpenEndedParserSequenceDiagram.png b/docs/images/AddOpenEndedParserSequenceDiagram.png new file mode 100644 index 00000000000..957bb993060 Binary files /dev/null and b/docs/images/AddOpenEndedParserSequenceDiagram.png differ diff --git a/docs/images/AddOpenEndedSequenceDiagram.png b/docs/images/AddOpenEndedSequenceDiagram.png new file mode 100644 index 00000000000..0ba1217ab8c Binary files /dev/null and b/docs/images/AddOpenEndedSequenceDiagram.png differ diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png index 2f1346869d0..a257bef1576 100644 Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png index bc7ed18ae29..380c501b8f8 100644 Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ diff --git a/docs/images/ClearActivityDiagram.png b/docs/images/ClearActivityDiagram.png new file mode 100644 index 00000000000..9b18817a69f Binary files /dev/null and b/docs/images/ClearActivityDiagram.png differ diff --git a/docs/images/ClearSequenceDiagram.png b/docs/images/ClearSequenceDiagram.png new file mode 100644 index 00000000000..3b4a7f2e6bb Binary files /dev/null and b/docs/images/ClearSequenceDiagram.png differ diff --git a/docs/images/ClearStatsActivityDiagram.png b/docs/images/ClearStatsActivityDiagram.png new file mode 100644 index 00000000000..5b37e3de98e Binary files /dev/null and b/docs/images/ClearStatsActivityDiagram.png differ diff --git a/docs/images/ClearStatsParserSequenceDiagram.png b/docs/images/ClearStatsParserSequenceDiagram.png new file mode 100644 index 00000000000..6bed2dcae74 Binary files /dev/null and b/docs/images/ClearStatsParserSequenceDiagram.png differ diff --git a/docs/images/ClearStatsSequenceDiagram.png b/docs/images/ClearStatsSequenceDiagram.png new file mode 100644 index 00000000000..5cead493296 Binary files /dev/null and b/docs/images/ClearStatsSequenceDiagram.png differ diff --git a/docs/images/ClearstatsIndexStep1.png b/docs/images/ClearstatsIndexStep1.png new file mode 100644 index 00000000000..13813c3e576 Binary files /dev/null and b/docs/images/ClearstatsIndexStep1.png differ diff --git a/docs/images/ClearstatsIndexStep2.png b/docs/images/ClearstatsIndexStep2.png new file mode 100644 index 00000000000..7e4502c9895 Binary files /dev/null and b/docs/images/ClearstatsIndexStep2.png differ diff --git a/docs/images/ClearstatsIndexStep3.png b/docs/images/ClearstatsIndexStep3.png new file mode 100644 index 00000000000..ead2d0eaafd Binary files /dev/null and b/docs/images/ClearstatsIndexStep3.png differ diff --git a/docs/images/ClearstatsIndexStepOptional1.png b/docs/images/ClearstatsIndexStepOptional1.png new file mode 100644 index 00000000000..e6f64530251 Binary files /dev/null and b/docs/images/ClearstatsIndexStepOptional1.png differ diff --git a/docs/images/ClearstatsIndexStepOptional2.png b/docs/images/ClearstatsIndexStepOptional2.png new file mode 100644 index 00000000000..92211a4ea81 Binary files /dev/null and b/docs/images/ClearstatsIndexStepOptional2.png differ diff --git a/docs/images/DeleteByIndexActivityDiagram.png b/docs/images/DeleteByIndexActivityDiagram.png new file mode 100644 index 00000000000..fd363dedbc8 Binary files /dev/null and b/docs/images/DeleteByIndexActivityDiagram.png differ diff --git a/docs/images/DeleteByTagActivityDiagram.png b/docs/images/DeleteByTagActivityDiagram.png new file mode 100644 index 00000000000..71f348088ea Binary files /dev/null and b/docs/images/DeleteByTagActivityDiagram.png differ diff --git a/docs/images/DeleteByTagParserSequenceDiagram.png b/docs/images/DeleteByTagParserSequenceDiagram.png new file mode 100644 index 00000000000..fcbc31fe63b Binary files /dev/null and b/docs/images/DeleteByTagParserSequenceDiagram.png differ diff --git a/docs/images/DeleteByTagSequenceDiagram.png b/docs/images/DeleteByTagSequenceDiagram.png new file mode 100644 index 00000000000..79af60608a2 Binary files /dev/null and b/docs/images/DeleteByTagSequenceDiagram.png differ diff --git a/docs/images/DeleteIndexStep1.png b/docs/images/DeleteIndexStep1.png new file mode 100644 index 00000000000..a9e5c25ef28 Binary files /dev/null and b/docs/images/DeleteIndexStep1.png differ diff --git a/docs/images/DeleteIndexStep2.png b/docs/images/DeleteIndexStep2.png new file mode 100644 index 00000000000..0d15481faef Binary files /dev/null and b/docs/images/DeleteIndexStep2.png differ diff --git a/docs/images/DeleteIndexStep3.png b/docs/images/DeleteIndexStep3.png new file mode 100644 index 00000000000..160818548ed Binary files /dev/null and b/docs/images/DeleteIndexStep3.png differ diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png index fa327b39618..0c1fdfd8c93 100644 Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ diff --git a/docs/images/DeleteTagStep1.png b/docs/images/DeleteTagStep1.png new file mode 100644 index 00000000000..f045d2440c7 Binary files /dev/null and b/docs/images/DeleteTagStep1.png differ diff --git a/docs/images/DeleteTagStep2.png b/docs/images/DeleteTagStep2.png new file mode 100644 index 00000000000..4752a8ed503 Binary files /dev/null and b/docs/images/DeleteTagStep2.png differ diff --git a/docs/images/DeleteTagStep3.png b/docs/images/DeleteTagStep3.png new file mode 100644 index 00000000000..b3d852cca9f Binary files /dev/null and b/docs/images/DeleteTagStep3.png differ diff --git a/docs/images/Edit.png b/docs/images/Edit.png new file mode 100644 index 00000000000..42913a17e57 Binary files /dev/null and b/docs/images/Edit.png differ diff --git a/docs/images/Edit2.png b/docs/images/Edit2.png new file mode 100644 index 00000000000..cd9f608a805 Binary files /dev/null and b/docs/images/Edit2.png differ diff --git a/docs/images/Edit3.png b/docs/images/Edit3.png new file mode 100644 index 00000000000..08a21b9986c Binary files /dev/null and b/docs/images/Edit3.png differ diff --git a/docs/images/EditActivityDiagram.png b/docs/images/EditActivityDiagram.png new file mode 100644 index 00000000000..cae196e4132 Binary files /dev/null and b/docs/images/EditActivityDiagram.png differ diff --git a/docs/images/EditParserSequenceDiagram.png b/docs/images/EditParserSequenceDiagram.png new file mode 100644 index 00000000000..c1885eee7c0 Binary files /dev/null and b/docs/images/EditParserSequenceDiagram.png differ diff --git a/docs/images/EditSequenceDiagram.png b/docs/images/EditSequenceDiagram.png new file mode 100644 index 00000000000..1e0e4d8a4f3 Binary files /dev/null and b/docs/images/EditSequenceDiagram.png differ diff --git a/docs/images/ExportActivityDiagram.png b/docs/images/ExportActivityDiagram.png new file mode 100644 index 00000000000..80eb678426e Binary files /dev/null and b/docs/images/ExportActivityDiagram.png differ diff --git a/docs/images/ExportParserSequenceDiagram.png b/docs/images/ExportParserSequenceDiagram.png new file mode 100644 index 00000000000..38840513f93 Binary files /dev/null and b/docs/images/ExportParserSequenceDiagram.png differ diff --git a/docs/images/ExportSequenceDiagram.png b/docs/images/ExportSequenceDiagram.png new file mode 100644 index 00000000000..6f14925aa66 Binary files /dev/null and b/docs/images/ExportSequenceDiagram.png differ diff --git a/docs/images/ExportStep1.png b/docs/images/ExportStep1.png new file mode 100644 index 00000000000..f591d631684 Binary files /dev/null and b/docs/images/ExportStep1.png differ diff --git a/docs/images/ExportStep2.png b/docs/images/ExportStep2.png new file mode 100644 index 00000000000..780cd111494 Binary files /dev/null and b/docs/images/ExportStep2.png differ diff --git a/docs/images/ExportStep3a.png b/docs/images/ExportStep3a.png new file mode 100644 index 00000000000..9035717b1c3 Binary files /dev/null and b/docs/images/ExportStep3a.png differ diff --git a/docs/images/ExportStep3b.png b/docs/images/ExportStep3b.png new file mode 100644 index 00000000000..588a367a6d5 Binary files /dev/null and b/docs/images/ExportStep3b.png differ diff --git a/docs/images/ExportStep3bW.png b/docs/images/ExportStep3bW.png new file mode 100644 index 00000000000..5a65d2c6ca7 Binary files /dev/null and b/docs/images/ExportStep3bW.png differ diff --git a/docs/images/ExportStep3c.png b/docs/images/ExportStep3c.png new file mode 100644 index 00000000000..dfb3a97448b Binary files /dev/null and b/docs/images/ExportStep3c.png differ diff --git a/docs/images/ExportStep3cW.png b/docs/images/ExportStep3cW.png new file mode 100644 index 00000000000..3385ac671c9 Binary files /dev/null and b/docs/images/ExportStep3cW.png differ diff --git a/docs/images/FindActivityDiagram.png b/docs/images/FindActivityDiagram.png new file mode 100644 index 00000000000..fdb341da79d Binary files /dev/null and b/docs/images/FindActivityDiagram.png differ diff --git a/docs/images/FindParserSequenceDiagram.png b/docs/images/FindParserSequenceDiagram.png new file mode 100644 index 00000000000..8ef75148897 Binary files /dev/null and b/docs/images/FindParserSequenceDiagram.png differ diff --git a/docs/images/FindQuestionAndTagsStep1.png b/docs/images/FindQuestionAndTagsStep1.png new file mode 100644 index 00000000000..a9e5c25ef28 Binary files /dev/null and b/docs/images/FindQuestionAndTagsStep1.png differ diff --git a/docs/images/FindQuestionAndTagsStep2.png b/docs/images/FindQuestionAndTagsStep2.png new file mode 100644 index 00000000000..021dcc70eca Binary files /dev/null and b/docs/images/FindQuestionAndTagsStep2.png differ diff --git a/docs/images/FindQuestionAndTagsStep3.png b/docs/images/FindQuestionAndTagsStep3.png new file mode 100644 index 00000000000..f437bc6f2c7 Binary files /dev/null and b/docs/images/FindQuestionAndTagsStep3.png differ diff --git a/docs/images/FindQuestionStep1.png b/docs/images/FindQuestionStep1.png new file mode 100644 index 00000000000..f033ea367fd Binary files /dev/null and b/docs/images/FindQuestionStep1.png differ diff --git a/docs/images/FindQuestionStep2.png b/docs/images/FindQuestionStep2.png new file mode 100644 index 00000000000..0b85721cc80 Binary files /dev/null and b/docs/images/FindQuestionStep2.png differ diff --git a/docs/images/FindQuestionStep3.png b/docs/images/FindQuestionStep3.png new file mode 100644 index 00000000000..947a090959e Binary files /dev/null and b/docs/images/FindQuestionStep3.png differ diff --git a/docs/images/FindSequenceDiagram.png b/docs/images/FindSequenceDiagram.png new file mode 100644 index 00000000000..05156b06875 Binary files /dev/null and b/docs/images/FindSequenceDiagram.png differ diff --git a/docs/images/FindTagsStep1.png b/docs/images/FindTagsStep1.png new file mode 100644 index 00000000000..a9e5c25ef28 Binary files /dev/null and b/docs/images/FindTagsStep1.png differ diff --git a/docs/images/FindTagsStep2.png b/docs/images/FindTagsStep2.png new file mode 100644 index 00000000000..a4ad962f5d4 Binary files /dev/null and b/docs/images/FindTagsStep2.png differ diff --git a/docs/images/FindTagsStep3.png b/docs/images/FindTagsStep3.png new file mode 100644 index 00000000000..61e7e809423 Binary files /dev/null and b/docs/images/FindTagsStep3.png differ diff --git a/docs/images/FlashcardClassDiagram.png b/docs/images/FlashcardClassDiagram.png new file mode 100644 index 00000000000..77d24df6d90 Binary files /dev/null and b/docs/images/FlashcardClassDiagram.png differ diff --git a/docs/images/ImportActivityDiagram.png b/docs/images/ImportActivityDiagram.png new file mode 100644 index 00000000000..5a02f3f7aef Binary files /dev/null and b/docs/images/ImportActivityDiagram.png differ diff --git a/docs/images/ImportParserSequenceDiagram.png b/docs/images/ImportParserSequenceDiagram.png new file mode 100644 index 00000000000..9a3a983c8c0 Binary files /dev/null and b/docs/images/ImportParserSequenceDiagram.png differ diff --git a/docs/images/ImportSequenceDiagram.png b/docs/images/ImportSequenceDiagram.png new file mode 100644 index 00000000000..35bfddde9d0 Binary files /dev/null and b/docs/images/ImportSequenceDiagram.png differ diff --git a/docs/images/ImportStep1.png b/docs/images/ImportStep1.png new file mode 100644 index 00000000000..0f0d79b9af0 Binary files /dev/null and b/docs/images/ImportStep1.png differ diff --git a/docs/images/ImportStep1W.png b/docs/images/ImportStep1W.png new file mode 100644 index 00000000000..b81b684e814 Binary files /dev/null and b/docs/images/ImportStep1W.png differ diff --git a/docs/images/ImportStep2.png b/docs/images/ImportStep2.png new file mode 100644 index 00000000000..d4606b790f7 Binary files /dev/null and b/docs/images/ImportStep2.png differ diff --git a/docs/images/ImportStep2W.png b/docs/images/ImportStep2W.png new file mode 100644 index 00000000000..af89bcf5c18 Binary files /dev/null and b/docs/images/ImportStep2W.png differ diff --git a/docs/images/ImportStep3.png b/docs/images/ImportStep3.png new file mode 100644 index 00000000000..15c032325ed Binary files /dev/null and b/docs/images/ImportStep3.png differ diff --git a/docs/images/ImportStep4.png b/docs/images/ImportStep4.png new file mode 100644 index 00000000000..0ceb7fb2ea6 Binary files /dev/null and b/docs/images/ImportStep4.png differ diff --git a/docs/images/ListIndexStep1.png b/docs/images/ListIndexStep1.png new file mode 100644 index 00000000000..7fdb07f64e9 Binary files /dev/null and b/docs/images/ListIndexStep1.png differ diff --git a/docs/images/ListIndexStep2.png b/docs/images/ListIndexStep2.png new file mode 100644 index 00000000000..5c20cbd86fe Binary files /dev/null and b/docs/images/ListIndexStep2.png differ diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png index b9e853cef12..afc8778df5b 100644 Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png index 280064118cf..8b07ec8230f 100644 Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ diff --git a/docs/images/OpenFlashcardActivityDiagram.png b/docs/images/OpenFlashcardActivityDiagram.png new file mode 100644 index 00000000000..c62c5c04f77 Binary files /dev/null and b/docs/images/OpenFlashcardActivityDiagram.png differ diff --git a/docs/images/OpenIndexStep1.png b/docs/images/OpenIndexStep1.png new file mode 100644 index 00000000000..f1a6e287077 Binary files /dev/null and b/docs/images/OpenIndexStep1.png differ diff --git a/docs/images/OpenIndexStep2.png b/docs/images/OpenIndexStep2.png new file mode 100644 index 00000000000..9b886ad65b6 Binary files /dev/null and b/docs/images/OpenIndexStep2.png differ diff --git a/docs/images/OpenIndexStep3.png b/docs/images/OpenIndexStep3.png new file mode 100644 index 00000000000..e4cd29491d5 Binary files /dev/null and b/docs/images/OpenIndexStep3.png differ diff --git a/docs/images/OpenParserSequenceDiagram.png b/docs/images/OpenParserSequenceDiagram.png new file mode 100644 index 00000000000..6634f82f7b7 Binary files /dev/null and b/docs/images/OpenParserSequenceDiagram.png differ diff --git a/docs/images/OpenSequenceDiagram.png b/docs/images/OpenSequenceDiagram.png new file mode 100644 index 00000000000..81f04162aea Binary files /dev/null and b/docs/images/OpenSequenceDiagram.png differ diff --git a/docs/images/SeEduLogo.png b/docs/images/SeEduLogo.png deleted file mode 100644 index 31ad50b6f88..00000000000 Binary files a/docs/images/SeEduLogo.png and /dev/null differ diff --git a/docs/images/StatsActivityDiagram.png b/docs/images/StatsActivityDiagram.png new file mode 100644 index 00000000000..db4eeea7d18 Binary files /dev/null and b/docs/images/StatsActivityDiagram.png differ diff --git a/docs/images/StatsByTagActivityDiagram.png b/docs/images/StatsByTagActivityDiagram.png new file mode 100644 index 00000000000..313a35d14f9 Binary files /dev/null and b/docs/images/StatsByTagActivityDiagram.png differ diff --git a/docs/images/StatsByTagParserSequenceDiagram.png b/docs/images/StatsByTagParserSequenceDiagram.png new file mode 100644 index 00000000000..91ef20472aa Binary files /dev/null and b/docs/images/StatsByTagParserSequenceDiagram.png differ diff --git a/docs/images/StatsByTagSequenceDiagram.png b/docs/images/StatsByTagSequenceDiagram.png new file mode 100644 index 00000000000..e430bf2c068 Binary files /dev/null and b/docs/images/StatsByTagSequenceDiagram.png differ diff --git a/docs/images/StatsIndexStep1.png b/docs/images/StatsIndexStep1.png new file mode 100644 index 00000000000..c2d8ab81a6e Binary files /dev/null and b/docs/images/StatsIndexStep1.png differ diff --git a/docs/images/StatsIndexStep2.png b/docs/images/StatsIndexStep2.png new file mode 100644 index 00000000000..ddb56f07057 Binary files /dev/null and b/docs/images/StatsIndexStep2.png differ diff --git a/docs/images/StatsIndexStep3.png b/docs/images/StatsIndexStep3.png new file mode 100644 index 00000000000..72338489632 Binary files /dev/null and b/docs/images/StatsIndexStep3.png differ diff --git a/docs/images/StatsParserSequenceDiagram.png b/docs/images/StatsParserSequenceDiagram.png new file mode 100644 index 00000000000..9a50d5ba503 Binary files /dev/null and b/docs/images/StatsParserSequenceDiagram.png differ diff --git a/docs/images/StatsSequenceDiagram.png b/docs/images/StatsSequenceDiagram.png new file mode 100644 index 00000000000..07805dce1a7 Binary files /dev/null and b/docs/images/StatsSequenceDiagram.png differ diff --git a/docs/images/StatsTagsStep1.png b/docs/images/StatsTagsStep1.png new file mode 100644 index 00000000000..f67625359f2 Binary files /dev/null and b/docs/images/StatsTagsStep1.png differ diff --git a/docs/images/StatsTagsStep2.png b/docs/images/StatsTagsStep2.png new file mode 100644 index 00000000000..dc916bbdd14 Binary files /dev/null and b/docs/images/StatsTagsStep2.png differ diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png index d87c1216820..da9c646172f 100644 Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ diff --git a/docs/images/TestActivityDiagram.png b/docs/images/TestActivityDiagram.png new file mode 100644 index 00000000000..9e99a3907c5 Binary files /dev/null and b/docs/images/TestActivityDiagram.png differ diff --git a/docs/images/TestMCQStep2.png b/docs/images/TestMCQStep2.png new file mode 100644 index 00000000000..fd952286219 Binary files /dev/null and b/docs/images/TestMCQStep2.png differ diff --git a/docs/images/TestMCQStep3.png b/docs/images/TestMCQStep3.png new file mode 100644 index 00000000000..16fab48a142 Binary files /dev/null and b/docs/images/TestMCQStep3.png differ diff --git a/docs/images/TestMCQStep4.png b/docs/images/TestMCQStep4.png new file mode 100644 index 00000000000..4b1cb19fcb9 Binary files /dev/null and b/docs/images/TestMCQStep4.png differ diff --git a/docs/images/TestOpenStep2.png b/docs/images/TestOpenStep2.png new file mode 100644 index 00000000000..8f6e3f84b3a Binary files /dev/null and b/docs/images/TestOpenStep2.png differ diff --git a/docs/images/TestOpenStep3.png b/docs/images/TestOpenStep3.png new file mode 100644 index 00000000000..e12d068ecc4 Binary files /dev/null and b/docs/images/TestOpenStep3.png differ diff --git a/docs/images/TestParserSequenceDiagram.png b/docs/images/TestParserSequenceDiagram.png new file mode 100644 index 00000000000..b5f455485ca Binary files /dev/null and b/docs/images/TestParserSequenceDiagram.png differ diff --git a/docs/images/TestSequenceDiagram.png b/docs/images/TestSequenceDiagram.png new file mode 100644 index 00000000000..b0e5bcf3d41 Binary files /dev/null and b/docs/images/TestSequenceDiagram.png differ diff --git a/docs/images/TestState0.png b/docs/images/TestState0.png new file mode 100644 index 00000000000..3bab5f4d98e Binary files /dev/null and b/docs/images/TestState0.png differ diff --git a/docs/images/TestState1.png b/docs/images/TestState1.png new file mode 100644 index 00000000000..b694436a08f Binary files /dev/null and b/docs/images/TestState1.png differ diff --git a/docs/images/TestState2.png b/docs/images/TestState2.png new file mode 100644 index 00000000000..7c2a71a0e92 Binary files /dev/null and b/docs/images/TestState2.png differ diff --git a/docs/images/TestStep1.png b/docs/images/TestStep1.png new file mode 100644 index 00000000000..c2fd85962a6 Binary files /dev/null and b/docs/images/TestStep1.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5bd77847aa2..133a2cfd5bc 100644 Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 7b4b3dbea45..9815b3bb5e0 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/docs/images/addMCQ.png b/docs/images/addMCQ.png new file mode 100644 index 00000000000..7cd1da00222 Binary files /dev/null and b/docs/images/addMCQ.png differ diff --git a/docs/images/addMCQ2.png b/docs/images/addMCQ2.png new file mode 100644 index 00000000000..92508ea8239 Binary files /dev/null and b/docs/images/addMCQ2.png differ diff --git a/docs/images/addOpenEnded.png b/docs/images/addOpenEnded.png new file mode 100644 index 00000000000..e766738daf8 Binary files /dev/null and b/docs/images/addOpenEnded.png differ diff --git a/docs/images/addOpenEnded2.png b/docs/images/addOpenEnded2.png new file mode 100644 index 00000000000..f8d34915b7a Binary files /dev/null and b/docs/images/addOpenEnded2.png differ diff --git a/docs/images/chenxj98.png b/docs/images/chenxj98.png new file mode 100644 index 00000000000..88cd0c519c1 Binary files /dev/null and b/docs/images/chenxj98.png differ diff --git a/docs/images/clearstats.png b/docs/images/clearstats.png new file mode 100644 index 00000000000..7a16f68a982 Binary files /dev/null and b/docs/images/clearstats.png differ diff --git a/docs/images/fh-30.png b/docs/images/fh-30.png new file mode 100644 index 00000000000..7f19ad5c862 Binary files /dev/null and b/docs/images/fh-30.png differ diff --git a/docs/images/findAlexDavidResult.png b/docs/images/findAlexDavidResult.png deleted file mode 100644 index 235da1c273e..00000000000 Binary files a/docs/images/findAlexDavidResult.png and /dev/null differ diff --git a/docs/images/gilberttan19.png b/docs/images/gilberttan19.png new file mode 100644 index 00000000000..65dfba129a4 Binary files /dev/null and b/docs/images/gilberttan19.png differ diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png index b1f70470137..2eca5305c99 100644 Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ diff --git a/docs/images/johndoe.png b/docs/images/johndoe.png deleted file mode 100644 index 1ce7ce16dc8..00000000000 Binary files a/docs/images/johndoe.png and /dev/null differ diff --git a/docs/images/joshtyf.png b/docs/images/joshtyf.png new file mode 100644 index 00000000000..3354a731034 Binary files /dev/null and b/docs/images/joshtyf.png differ diff --git a/docs/images/josiahkhoo.png b/docs/images/josiahkhoo.png new file mode 100644 index 00000000000..c164b8e0011 Binary files /dev/null and b/docs/images/josiahkhoo.png differ diff --git a/docs/images/test.png b/docs/images/test.png new file mode 100644 index 00000000000..6e8ca616fc7 Binary files /dev/null and b/docs/images/test.png differ diff --git a/docs/index.md b/docs/index.md index 7601dbaad0d..9d116c08331 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,17 +1,17 @@ --- layout: page -title: AddressBook Level-3 +title: QuickCache --- -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) -[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3) +[![CI Status](https://github.com/AY2021S1-CS2103T-T13-2/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2021S1-CS2103T-T13-2/tp/actions) +[![codecov](https://codecov.io/gh/AY2021S1-CS2103T-T13-2/tp/branch/master/graph/badge.svg)](https://codecov.io/gh/AY2021S1-CS2103T-T13-2/tp) ![Ui](images/Ui.png) -**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). +**QuickCache is a desktop application for managing flashcards.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). -* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). -* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. +* If you are interested in using QuickCache, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). +* If you are interested about developing QuickCache, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. **Acknowledgements** diff --git a/docs/team/PPP.css b/docs/team/PPP.css new file mode 100644 index 00000000000..458ac00ee4c --- /dev/null +++ b/docs/team/PPP.css @@ -0,0 +1,31 @@ +/* This solution is adapted from +https://stackoverflow.com/questions/4098195/can-ordered-list- +produce-result-that-looks-like-1-1-1-2-1-3-instead-of-just-1 +*/ + +ol { + list-style-type: none; + counter-reset: item; + margin: 0; + padding: 0; +} + +ol > li { + display: table; + counter-increment: item; + margin-bottom: 0.6em; +} + +ol > li:before { + content: counters(item, ".") ". "; + display: table-cell; + padding-right: 0.6em; +} + +li ol > li { + margin: 0; +} + +li ol > li:before { + content: counters(item, ".") " "; +} diff --git a/docs/team/chenxj98.md b/docs/team/chenxj98.md new file mode 100644 index 00000000000..52059207910 --- /dev/null +++ b/docs/team/chenxj98.md @@ -0,0 +1,125 @@ +--- +layout: page +title: Xingjian's Project Portfolio Page +--- + + + +## Xingjian Chen - Project Portfolio for QuickCache (tP) + +### Table of Contents +1. [Introduction](#introduction) + 1. [About the team](#about-the-team) + 2. [About the project](#about-the-project) +2. [Summary of contributions](#summary-of-contributions) + 1. [Enhancements and new features added](#enhancements-and-new-features-added) + 1. [Difficulty functionality for flashcards](#difficulty-of-a-flashcard) + 2. [Sample flashcards for starting users](#sample-flashcards) + 3. [Maintaining storage system](#storage) + 4. [GUI colour scheme](#gui-colour) + 2. [Code contributed](#code-contributed) + 3. [Other contributions](#other-contributions) + 1. [Project management](#project-management) + 2. [Enhancements to existing features](#enhancements-to-existing-features) + 3. [Documentation](#documentation) + 1. [User Guide](#user-guide) + 2. [Developer Guide](#developer-guide) + 4. [Community](#community) + + +### 1. Introduction + +This is my project portfolio for QuickCache. The document outlines my contributions to the project, including the enhancements and features that I have implemented. + + +#### 1.1 About the team + +Our team consists of five Year 2 Computer Science students from National University of Singapore, who were all taking CS2103T Software Engineering at the time of this project. + + +#### 1.2 About the project + +QuickCache is developed as part of our team project for our module CS2103T Software Engineering. QuickCache is designed to be a desktop application (Windows/macOS/Linux) for managing flashcards, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). The software is adapted and expanded from [AddressBook Level 3](https://github.com/nus-cs2103-AY2021S1/tp). + + +### 2. Summary of contributions + +I served as Integration Lead for the project, and my team responsibilities include: +* Taking charge of versioning of the code, maintaining the code repository, integrating various parts of the software to create a whole. +* Facilitating the merging of code into the production branch. +* Ensuring that integration tests are performed properly and on time. + +My responsibilities as a developer also include maintaining QuickCache's storage system, creating features for users to set difficulty levels to their flashcards, and creating a set of starting sample flashcards for users to experiment on. + +In the following sections, I will illustrate the above-mentioned enhancements in greater detail, along with the corresponding documentation that I have written for them within the user and developer guides. + + +#### 2.1 Enhancements and features added + +The following describes the enhancements and new features that I added to the project. + + +**2.1.1 Feature: Difficulty functionality for flashcards** + * What it does: allows the user to set a specific difficulty level for created flashcards. Difficulty level of a flashcard can be specified during creation through the `add` commands or during editing through the `edit` command. A difficulty tag with specified colouring corresponding to the difficulty level will then be seen under the flashcard in the GUI. + * Justification: This feature improves the organisation of flashcards for the user as the user can more easily differentiate the flashcards that he/she has more difficulty in. + * Highlights: This feature affects existing commands and commands to be added in the future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands, such as `add`, `edit`. GUI was also adjusted to fit the functionality. + + +**2.1.2 Feature: Sample flashcards for starting users** + * What it does: provides a set of sample flashcards containing sample questions and answers for new users who open QuickCache for the first time. + * Justification: This feature provides a more user-friendly experience for the new user as he/she can play around with the sample flashcards and get familiar with the application. + * Highlights: This feature checks for the existence of the data file stored in QuickCache. A new data file containing the sample flashcards will be added if there is no present data file. + + +**2.1.3 Enhancement: Maintaining storage system** + * What it does: manages QuickCache's storage system by updating the application's data file with the current set of flashcards. + * Justification: This enhancement ensures that the application's data file is properly updated and checks for corrupted information within the data file. + * Highlights: This enhancement required an in-depth analysis of design alternatives and how we represent data in the json file. The storage has to be updated as functionalities are added or changed. + + +**2.1.4 Enhancement: GUI colour scheme** + * What it does: changes the colour of the application's GUI. + * Justification: Sets a suitable theme for our application that reflects our vision for the project. + + +#### 2.2 Code contributed + +Click on the following links to view the code that I have contributed: + + * [RepoSense](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=ChenXJ98&sort=groupTitle&sortWithin=title&since=2020-08-14&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&zFR=false&tabType=authorship&until=2020-11-09&tabAuthor=ChenXJ98&tabRepo=AY2021S1-CS2103T-T13-2%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code) + * [Functional Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/main/java/quickcache) + * [Test Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/test/java/quickcache) + + +#### 2.3. Other contributions + + The following describes the various other contributions that I have made to the project. + + + * **Project management**: + * Managed 36 issues on GitHub + * Reviewed 77 pull requests on GitHub + + + * **Enhancements to existing features**: + * Wrote additional tests for existing features (Pull request [\#140](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/140)) + * Wrote tests for difficulty feature (Pull request [\#127](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/127)) + * Refactored remnant code from AddressBook package into the QuickCache package (Pull request [\#231](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/231)) + + + * **Documentation**: + + * User Guide: + * Added documentation for the features `difficulty`, `tag` (Pull requests [\#30](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/30), [\#159](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/159)) + * Added introduction message and table of contents of the user guide (Pull requests [\#168](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/168)) + * Added user stories (Pull request [\#231](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/231)) + + * Developer Guide: + * Added implementation details of the `difficulty`, `tag` and `storage` features (Pull requests [\#135](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/135), [\#171](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/171)) + * Added UML diagrams for `storage` and `open` features ([\#171](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/171), [\#284](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/284)) + * Added manual testing instructions (Pull requests [\#274](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/274)) + + + * **Community**: + * PRs reviewed (with non-trivial review comments): [\#21](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/21), [\#69](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/69), [\#136](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/136), [\#137](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/137), [\#153](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/153) + * Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/AY2021S1-CS2103T-T09-4/tp/issues/176), [2](https://github.com/AY2021S1-CS2103T-T09-4/tp/issues/175), [3](https://github.com/AY2021S1-CS2103T-T09-4/tp/issues/174), [4](https://github.com/AY2021S1-CS2103T-T09-4/tp/issues/173), [5](https://github.com/AY2021S1-CS2103T-T09-4/tp/issues/172)) diff --git a/docs/team/fh-30.md b/docs/team/fh-30.md new file mode 100644 index 00000000000..4889360af8a --- /dev/null +++ b/docs/team/fh-30.md @@ -0,0 +1,139 @@ +--- +:layout: page +title: Francis' Project Portfolio Page +--- + + + +## Francis Hodianto - Project Portfolio for QuickCache (tp) +### Table of Contents +1. [Introduction](#introduction) + 1. [About the team](#about-the-team) + 2. [About the project](#about-the-project) +2. [Summary of contributions](#summary-of-contributions) + 1. [Enhancements and new features added](#enhancements-and-new-features-added) + 1. [Open a flashcard](#open-a-flashcard) + 2. [Statistics of a flashcard](#statistics-of-a-flashcard) + 3. [Clear the statistics of a flashcard](#clear-the-statistics-of-a-flashcard) + 4. [Find a flashcard](#find-a-flashcard) + 5. [Navigate to previous commands](#navigate-to-previous-commands) + 2. [Code contributed](#code-contributed) + 3. [Other contributions](#other-contributions) + 1. [Project management](#project-management) + 2. [Enhancements to existing features](#enhancements-to-existing-features) + 3. [Documentation](#documentation) + 1. [User Guide](#user-guide) + 2. [Developer Guide](#developer-guide) + 4. [Community](#community) + + +### 1. Introduction + +This document serves as a project portfolio for QuickCache, and outlines my contributions to the project, including the features that I have implemented. + + +#### 1.1 About the team + +My team of five consists of five Year 2 Computer Science students, all taking the module CS2103T Software Engineering. + + +### 1.2 About the project + +This project was developed as part of the module CS2103T Software Engineering. We were tasked to develop a desktop application (Windows/macOS/Linux) with a Command Line Interface (that is, the program operates via text input from the user, called commands). Additionally, we were required to use an existing application, called AddressBook Level 3, as the starting point for building our application. + +My team decided to a create an application that helps students manage their flashcards, test themselves, and view their performance over time. To do so, we incorporated the existing people management features of AddressBook and used it as a starting point to build QuickCache. + +In total, QuickCache took a total of 10 weeks to complete. + + +### 2. Summary of contributions + +My main role in the team was to manage testing and my responsibilities included implementing features such as the ability to open the flashcard, enabling the user to view and clear the statistics of the flashcard and allowing the user to find flashcards using both or either their tags and questions. I also voluntarily added a history command that allows the user to navigate to previous commands using up/down keys. + +In the following sections, I will elaborate on the above-mentioned enhancements, along with the corresponding documentation that I have written about them within the user and developer guides. + + +#### 2.1 Enhancements and new features added + +The following describes the feature and enhancement I have already done in the project. + + +#### 2.1.1 Added the ability to open a flashcard + +* What it does: This command allows the user to open a flashcard based on its index in the list. Opening a flashcard displays the question of the flashcard and its choices provided that the flashcard's question is a multiple-choice question. +* Justification: This feature is integral for the product to be effective because a user can forget the choices to answering the question associated with the flashcard if the question is multiple choice and the app should provide a convenient way for the user to refer to them. +
    +* Highlights: This enhancement affects the existing GUI and functionalities to be added in the future. It required careful consideration of how it is to be implemented. The implementation too was challenging as it required changes to the existing GUI and needs to ensure backward compatibility with it. + + +#### 2.1.2 Added the ability to display the statistics of a flashcard +* What it does: This command allows the user to request to display a flashcard's statistics based on its index in the list. The statistics are displayed to the user in the form of a pie chart. +* Justification: This feature is necessary for the app to achieve it's purpose of helping users improve in their academics because a user needs to know where he/she stands to decide on the amount of effort they need to put in ahead and the app should provide a simple way for the user to evaluate his/her performance. +* Highlights: This enhancement affects the existing GUI and functionalities to be added in the future. It required careful consideration of how it is to be implemented. The implementation too was challenging as it required changes to the existing GUI and needs to ensure backward compatibility with it. +* Credits: *{I referred to this [video](https://www.youtube.com/watch?v=bpHmrgvpEDQ) on how to make a pie chart using JavaFX, this [link](https://stackoverflow.com/questions/43433639/set-javafx-piechart-label-color-via-css) on getting the CSS of the pie chart and this [link](https://gist.github.com/jewelsea/1422628) on how to make the pie chart's legend look nicer}* + + +#### 2.1.3 Added the ability to clear the statistics of a flashcard +* What it does: This command allows the user to clear a flashcard's statistics based on its index in the list. The statistics are reset back to zero for all attributes that are tracked for each flashcard. +* Justification: This feature is necessary as the user might want to get rid of the previous statistics associated with a flashcard as it may no longer be a relevant gauge of his current performance and therefore the app needs to provide a way for the user to achieve that. +* Highlights: This enhancement is relatively simple as it just needs to replace the current statistics associated with the flashcard with a default one set to all zeros. The implementation did not take too much time and effort. + + +#### 2.1.4 Added the ability to find a flashcard by tags and/or keywords +* What it does: This command allows the user to find a flashcard by specifying keywords in its question and/or tags associated with it. The flashcards matching the specified criteria are displayed in a list to the user. +
    +* Justification: This feature is necessary as the user might have a lot of flashcards and doesn't want to spend too much time scrolling through the list searching for the flashcard. The app therefore needs to cater for this by providing a simple and efficient way for the user to filter the flashcards in the list based on its attributes such as the keywords or tags associated with it. +* Highlights: This enhancement affects the existing implementation of the find command. It required careful consideration of how it is to be implemented. The implementation too was challenging as it required changes to the existing find command which only accepted keywords and allowing finding using both tags and keywords proved to be a non trivial task. +* Credits: *{I referred to this [link](https://stackoverflow.com/questions/86780) in order to allow for a case-insensitive "contains" implementation for finding with keywords. In simple words, this allows keywords such as "HEL" to pick up a flashcard which has "Hello world" as its question.}* + + +#### 2.1.5 Added a history command that allows the user to navigate to previous commands using up/down keys [Bonus Feature] + + +### 2.2 Code contributed + +You can refer to this [link](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=fh-30) to view the code that I have contributed. + + +### 2.3 Other contributions + +Given below are other contributions that I have made to the project. + + +#### 2.3.1 Project management + +Managed releases `v1.2` - `v1.4` (4 releases) on GitHub + + +#### 2.3.2 Enhancements to existing features + +* Morphed the GUI to display flashcards instead of people ([Pull request \#59](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/59)) +* Refactored statistics into its own class ([Pull request \#80](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/80)) +* Updated the find command to allow searching using keywords and/or tags, increased abstraction by introducing `FlashcardPredicate` ([Pull request \#110](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/110)) +* Renamed all instances of Addressbook and Person into QuickCache and Flashcard in the test code, added various test code to improve code coverage ([Pull request \#86](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/86), [Pull request \#94](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/94), [Pull request \#222](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/222), [Pull request \#255](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/255)) + + +#### 2.3.3 Documentation + +Below are the details of the contributions I made to documenting the app + + +##### 2.3.3.1 User Guide + +* Added documentation for the features `open`, `stats`, `clearstats` and `find` ([Pull request \#160](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/160)) +* Updated the command summary section to make it clearer. Built the table using HTML from scratch as it provided more features as compared to markdown's table. ([Pull request \#160](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/160)) +* Updated all the images in the User Guide to reflect the latest implementation of the app and to ensure that they are all of the same size and appearance ([Pull request \#236](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/236)) +* Updated the table of contents in the User Guide to provide multilevel numbering for added clarity ([Pull request \#236](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/236)) +* Updated FAQ section of User Guide to improve user experience ([Pull request \#252](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/252)) + + +##### 2.3.3.2 Developer Guide + +* Added implementation details for the features `open`, `stats`, `clearstats` and `find` ([Pull request \#136](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/136)) +* Added Use Cases for the features `open`, `stats`, `clearstats` and `find` ([Pull request \#243](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/243)) + + +#### 2.3.4 Community + +* PRs reviewed (with non-trivial review comments): [\#37](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/37), [\#95](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/95), [\#97](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/97), [\#140](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/140), [\#229](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/229) +* Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/FH-30/ped/issues/1), [2](https://github.com/FH-30/ped/issues/2), [3](https://github.com/FH-30/ped/issues/3), [4](https://github.com/FH-30/ped/issues/4)) diff --git a/docs/team/gilberttan19.md b/docs/team/gilberttan19.md new file mode 100644 index 00000000000..a7be5647491 --- /dev/null +++ b/docs/team/gilberttan19.md @@ -0,0 +1,116 @@ +--- +layout: page +title: Gilbert's Project Portfolio Page +--- + +## Gilbert Tan - Project Portfolio for QuickCache (tP) + +-- + +## Table of Contents + +1. [Introduction](#introduction) + 1. [About the team](#about-the-team) + 2. [About the project](#about-the-project) +2. [Summary of contributions](#summary-of-contributions) + 1. [Enhancements and new features added](#enhancements-and-new-features-added) + 1. [Add a flashcard](#add-a-flashcard) + 2. [Edit a flashcard](#edit-a-flashcard) + 3. [Delete a flashcard by index](#delete-a-flashcard) + 2. [Code contributed](#code-contributed) + 3. [Other contributions](#other-contributions) + 1. [Project management](#project-management) + 2. [Enhancements to existing features](#enhancements-to-existing-features) + 3. [documentation](#documentation) + 1. [User Guide](#user-guide) + 2. [Developer Guide](#developer-guide) + 4. [Community](#community) + +-- + + +### 1.Introduction + +This document serves as a project portfolio for QuickCache, and outlines my contributions to the project, including the features that I have implemented. + + +### 1.1. About the team + +My team of five consists of five Year 2 Computer Science students, all taking the module CS2103T Software Engineering. + + +### 1.2. About the project + +This project was developed as part of the module CS2103T Software Engineering. We were tasked to develop a desktop application (Windows/macOS/Linux) with a Command Line Interface (that is, the program operates via text input from the user, called commands). Additionally, we were required to use an existing application, called AddressBook Level 3, as the starting point for building our application. + +My team decided to a create an application that helps students manage their flashcards, test themselves, and view their performance over time. To do so, we incorporated the existing people management features of AddressBook and used it as a starting point to build QuickCache. + +In total, QuickCache took a total of 10 weeks to complete. + + +### 2. Summary of Contributions + +I am in charge of code quality in the team, and I am responsible for creating features such as adding flashcard with both open ended and multiple choice question, editing the flashcard and deleting the flashcard. + +Given below are my contributions to the project in greater detail with the documentation for the features that I have already written in developer guide and user guide. + + +#### 2.1. Enhancements and new features added +The following describes the feature and enhancement I have already done in the project. + + +#### 2.1.1 Added the ability to add a flashcard with both open ended question and multiple choice question + * What it does: This command allows the user to add flashcard one at a time. The flashcard can contains either open ended question or multiple choice question. + * Justification: This feature is the a core function in the application and most of the feature depend on the creation of the flashcard. + * Highlights: The implementation of this enhancement follow closely the OOP principle and use the polymorphism concept in OOP. + + +#### 2.1.2 Added the ability to edit a flashcard. + * What it does: This command allows the user to edit flashcard one at a time. The flashcard can contains either open ended question or multiple choice question. + * Justification: This feature is the one of the feature in 1.3 as edit is basically create and delete. + * Justification: This feature improves the product significantly because a user can make mistakes when creating a flashcard or the user want to update the flashcard and the app should provide a convenient way to rectify them. + * Highlights: The implementation of this command uses defensive programming as it copy the flashcard before updating the internal state of the flashcard and set the udpated flashcard on the list. + + +#### 2.1.3 Added the ability to delete a flashcard by index. + * What it does: This command allows the user to delete flashcard one at a time. + * Justification: This feature improves the product significantly because as there will be too many flashcards as time goes on and the app should provide a convenient way to delete them. + * Highlights: This command updates the internal state of the list and update them accordingly to the storage. + + +### 2.2. Code contributed + Given below is the link to the code that I have contributed. + * [RepoSense link](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=gilberttan19) + * [Functional Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/main/java/quickcache) + * [Test Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/test/java/quickcache) + + +### 2.3. Other contribution + +Given below is other contributions that I have made to the project. + + +#### 2.3.1 Project management + * Managed 30 issues on GitHub + * Helped in checking the code quality + + +#### 2.3.2 Enhancements to existing features + * Wrote additional tests for existing features to increase coverage (Pull requests [\#203](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/203), [\#221](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/221) + * Morph the Logic and Model of AddressBook to have a UniqueFlashcardList. (Pull requests [\#37](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/37)) + * Refactored remnant code from Person to Flashcard. (Pull requests [\#248](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/248)) + + +#### 2.3.3 Documentation + +##### 2.3.3.1 User Guide + * Added the documentation for the features `delete`, `add`, `edit`, and `addmcq` (Pull requests [\#137](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/137 ),[\#152](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/152)) + * Added the preface for the quick start section. (Pull requests [\#141](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/141)) + +##### 2.3.3.2 Developer Guide + * Added implementation details of the `delete`, `add`, `edit`, abd `addmcq` feature. (Pull requests [\#128](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/128), [\#229](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/229)) + + +#### 2.3.4 Community + * PRs reviewed (with non-trivial review comments): (Pull requests [\#115](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/115), [\#85](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/85), [\#227](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/227)) + * Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/GilbertTan19/ped/issues/1), [2](https://github.com/GilbertTan19/ped/issues/2), [3](https://github.com/GilbertTan19/ped/issues/3)) diff --git a/docs/team/joshtyf.md b/docs/team/joshtyf.md new file mode 100644 index 00000000000..22b89c9f45b --- /dev/null +++ b/docs/team/joshtyf.md @@ -0,0 +1,178 @@ +--- +layout: page +title: Joshua's Project Portfolio Page +--- + +## Joshua Tan - Project Portfolio for QuickCache(tP) + +### Table of contents + +* [Introduction](#introduction) + * [About the team](#about-the-team) + * [About the project](#about-the-project) +* [Summary of Contributions](#summary-of-contributions) +* [Code Contributions](#code-contributions) + * [Creation of base classes](#creation-of-base-classes) + * [Find flashcards](#find-flashcards) + * [Delete by tag](#delete-by-tag) + * [Improve the GUI](#improved-the-gui) +* [Documentation Contributions](#documentation-contributions) + * [Management of overall documentation and website](#management-of-overall-documentation-and-website) + * [Creation of diagrams](#creation-of-diagrams) +* [Other notable contributions](#other-notable-contributions) + * [Team management](#team-management) + * [Defensive coding and bug fixes](#defensive-coding-and-bug-fixes) + * [Community Contributions](#community-contributions) + +### Introduction + +This document serves as a project portfolio for QuickCache, and outlines my contributions to the project, including the features that I have implemented. + +#### About the team + +My team of five consists of five Year 2 Computer Science students, all taking the module CS2103T Software Engineering. + +#### About the project + +This was a project part of the module CS2103T Software Engineering. The main aim of the project was to develop a Command +Line Interface (CLI) desktop application. The application had to capitalise on the speed and efficiency of using a CLI. +My team then decided to create an application that would allow students to create, use and manage flashcards. + +QuickCache was built on top of an existing CLI application called [AddressBook3](https://se-education.org/addressbook-level3/) (AB3). +We took the entire semester (13 weeks) to build QuickCache and added 15,000 lines of new code to the existing codebase. + +### Summary of Contributions + +My primary role was to help develop these enhancements for QuickCache: + + * Develop a system to organise the flashcards in QuickCache + * Delete flashcards based on their categories + * Find flashcards based on their categories + * Improve the GUI from the original AB3 + +In addition, I served as the Documentation Lead and my responsibilities included: + + * Managing the accuracy and correctness of UML diagrams + * Planning the overall structure of both the User Guide and Developer Guide + * Coordinating and delegating jobs to my teammates to ensure proper documentation + * Ensuring the correctness of the contents of all documentations + +### Code Contributions + +This section describes my detailed code contributions to the project. + +Click on the following links to view the code that I have contributed: + * [RepoSense link](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=joshtyf) + * [Functional Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/main/java/quickcache) + * [Test Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/test/java/quickcache) + +#### Creation of base classes + +**Description:** I kickstarted the project by creating the `Flashcard` class and other dependencies classes. +The design architecture was inspired by the original `AddressBook3` design. In order to follow the original design, the whole team +had to spend a considerable amount of time understanding the architecture of AB3. + +**Highlights:** As we had to follow an OOP design principle and to reduce coupling across classes, we had to plan ahead +as to how we wanted to build our classes. This lead to me creating the base classes such as `Answer`, `Question`, `Tag` +and `Choice` classes for us to use in the future for other purposes such as searching and testing of flashcards. + +Pull requests: [\#35](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/35), [\#62](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/62) + +#### Find flashcards + +**Description:** A user of QuickCache would want to be able to search for flashcards based on their categories. This was +implemented through the use of the `Tag` organisational system. The user would be using our tagging system to label +flashcards accordingly such as by their modules. Designing a search and filter system would also be a necessity for +future enhancements such as (deleting by categories)[#delete-by-tag]. + +**Highlights:** Implementing this enhancement was pretty straight forward as the original AB3 had such a feature. I had to implement +a `FlashcardContainsTagPredicate` class and additional tests to make sure that the feature worked as intended. + +Pull requests: [\#60](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/60) + +#### Delete by Tag + +**Description:** A user of QuickCache would want to delete flashcards based on categories. I developed the enhancement +to allow QuickCache to search and delete for flashcards using the `Tag` organisational system. This feature enhances the + existing delete by index mechanism as the user can now mass delete flashcards. + + **Highlights:** This enhancement was slightly challenging to implement as I had to consider whether or not to create a seperate command + or to merge together with the original delete by index command. After much deliberation, I decided to merge both functionalities together into + the delete command. As a result, I had to tweak the `DeleteCommand` and `DeleteCommandParser` classes accordingly to ensure proper implementation of + both features. I also had to design extensive tests to make sure that there wouldn't be any problems from this added enhancement. + +Pull requests: [\#129](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/129) + +#### Improved the GUI + +**Description:** The original GUI was built using [JavaFx](https://openjfx.io). In order to make it original to AB3, I tweaked +the layout of the GUI. In addition, I worked with my teammate Xing Jian to pick the colour scheme. + +**Highlights:** I had to consider the UX of the application and design it such that the information presented could be +viewed easily. I also got to work on JavaFx and CSS. + +Pull requests: [\#214](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/214) + +### Documentation Contributions + +This section describes my contributions as the Documentation Lead as well as other notable documentations. + +#### Management of overall documentation and website + +Our team website is hosted on Github pages and I was primarily in charge of managing the contents. +Part of my responsibilites included ensuring the accuracy of diagrams and information presented in our User Guide (UG) +and Developer Guide (DG). Being the documentation lead, I also took the initiative to learn how to use [PlantUml](https://plantuml.com) +and taught the rest of my team how to use it. + +Pull requests but not limited to: [\#170](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/170), +[\#245](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/245), +[\#253](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/253), +[\#254](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/254), +[\#280](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/280) + +In addition, I also had to plan the overall look and structure of the UG and DGs. As such, I was in charge of +delegating documentation jobs to my teammates and telling them what needed to be included. In total, I managed 23 issues +(not limited to Documentation) on Github. + +Issues created but not limited to: [\#149](https://github.com/AY2021S1-CS2103T-T13-2/tp/issues/149), +[\#165](https://github.com/AY2021S1-CS2103T-T13-2/tp/issues/165), [\#279](https://github.com/AY2021S1-CS2103T-T13-2/tp/issues/279) + +#### Creation of diagrams + +In addition, I played my part in the creation of UML diagrams for our DG. + +Pull requests: [\#81](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/81), [\#278](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/278) + +### Other notable contributions + +This section describes other contributions I made to the team that I believe were noteworthy. + +#### Team management + +I helped to organise our weekly zoom meetings which included reminders and creation of the zoom calls. In addition, +I also assisted our team lead, Josiah, in setting the agenda for meetings. + +#### Defensive coding and bug fixes + +During the course of development, my team adopted a strong defensive coding approach. We worked hard in ensuring that we left little +room for errors. In addition, we developed extensive tests to ensure that our features were working as intended. Nevertheless, we still +found bugs and I managed to fix some of the bugs. + +Pull requests: [\#227](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/227), +[\#228](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/228), +[\#234](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/234), +[\#235](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/235), +[\#258](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/258) + +#### Community Contributions + +Working together as a team, we had to consciously put in effort to give good feedback to each other's code. In addition, +we were also tasked to test other teams applications and to find bugs. + +PRs reviewed (with non-trivial review comments): [\#69](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/69), +[\#37](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/37) + +Reported bugs and suggestions for other teams in the class: +[1](https://github.com/AY2021S1-CS2103T-T11-2/tp/issues/188), +[2](https://github.com/AY2021S1-CS2103T-T11-2/tp/issues/187), +[3](https://github.com/AY2021S1-CS2103T-T11-2/tp/issues/186) diff --git a/docs/team/josiahkhoo.md b/docs/team/josiahkhoo.md new file mode 100644 index 00000000000..0c086652c00 --- /dev/null +++ b/docs/team/josiahkhoo.md @@ -0,0 +1,451 @@ +--- +layout: page +title: Josiah's Project Portfolio Page +--- + + + +## Josiah Khoo - Project Portfolio for QuickCache (tP) + +### Table of Contents + +1. [Introduction](#introduction) + 1. [About the team](#about-the-team) + 2. [About the project](#about-the-project) +2. [Summary of contributions](#summary-of-contributions) + 1. [Enhancements and new features added](#enhancements-and-new-features-added) + 1. [Test a flashcard](#test-a-flashcard) + 2. [Export a set of flashcards](#export-a-set-of-flashcards) + 3. [Import a set of flashcards](#import-a-set-of-flashcards) + 4. [Display statistics of a set of flashcards by tag](#display-statistics-of-flashcards-by-tag) + 2. [Code contributed](#code-contributed) + 3. [Other contributions](#other-contributions) + 1. [Project management](#project-management) + 2. [Enhancements to existing features](#enhancements-to-existing-features) + 3. [documentation](#documentation) + 1. [User Guide](#user-guide) + 2. [Developer Guide](#developer-guide) + 3. [About Us](#about-us) + 4. [Miscellaneous](#miscellaneous) + 4. [Community](#community) +3. [Contributions to User Guide](#contributions-to-user-guide) +4. [Contributions to Developer Guide](#contributions-to-developer-guide) + +--- + + +### 1. Introduction + +This document serves as a project portfolio for QuickCache, and outlines my contributions to the project, including the features that I have implemented. + + +#### 1.1. About the team + +My team of five consists of five Year 2 Computer Science students, all taking the module CS2103T Software Engineering. + + +#### 1.2. About the project + +This project was developed as part of the module CS2103T Software Engineering. We were tasked to develop a desktop application (Windows/macOS/Linux) with a Command Line Interface (that is, the program operates via text input from the user, called commands). Additionally, we were required to use an existing application, called AddressBook Level 3, as the starting point for building our application. + +My team decided to a create an application that helps students manage their flashcards, test themselves, and view their performance over time. To do so, we incorporated the existing people management features of AddressBook and used it as a starting point to build QuickCache. +A screenshot of QuickCache is shown below: + +![Ui](../images/Ui.png) + +In total, QuickCache took a total of 10 weeks to complete. + + +### 2. Summary of Contributions + +I served as Team Lead for the project, and my team responsibilities include: +* Coordinating the overall project. +* Defining, assigning, and tracking project tasks. +* Ensuring that project deliverables are done on time and are in the right format. + +My user-facing responsibilities include: +* Creating features for users to test their created flashcards +* Enabling the users to share their flashcards with one another. + +In the following sections, I will illustrate the above-mentioned enhancements in greter detail, along with the corresponding documentation that I have written fro them within the user and developer guides. + + +#### 2.1. Enhancements and new features added + +The following describes the enhancements and new features that I added to the project. + + +#### 2.1.1 Test a flashcard (Feature) + +- What it does: The test command allows the user to test their created flashcards with what they think the answer for the flashcard is. +- Justification: This command is essential to the core of our application in allowing students to revise from the flashcards that they have created. +- Highlights: The test command updates the internal state of the flashcard that is being tested to allow for useful statistics to be generated from it. It also works for any question type (open-ended question and multiple choice questions) + + +#### 2.1.2 Export a set of flashcards (Feature) + +- What it does: The export command allows the user to export a specified set of flashcards from QuickCache into a file that the user can store or share with others. +- Justification: This commands works in tandem with the import command to facilitate sharing as well as for the user to back his/her flashcards up. +- Highlights: The export command uses the `QuickCacheStorage` interface to write the file into the users storage. + + +#### 2.1.3 Import a set of flashcards (Feature) + +- What it does: The import command allows the user to import a specified set of flashcards from the user's local storage into QuickCache. +- Justification: This command works in tandem with the export command to facilitate sharing as well as allow for the user to import his/her flashcards from a file in local storage. + +* Highlights: The import command uses the `QuickCacheStorage` and checks whether a flashcard has been imported before prior to deciding to import it. This prevents the user from importing duplicate flashcards. + + +#### 2.1.4 Display statistics of a set of flashcards by tag (Enhancement) + +- What it does: The statistics by tags command allows the user to view aggregated statistics of a set of flashcards through the use of tags. +- Justification: This command saves the user time when he/she wants to view statistics of all questions with a certain tag. Instead of having to manually view statistics for each question, the user can now view them all at a go. +- Highlights: The statistics by tags command were implemented over the existing statistics command by overloading the constructor. This allows for minimal repetition of code and for variations of the command to use similar logic, allowing for ease of debugging. + + +### 2.2. Code contributed + +Click on the following links to view the code that I have contributed: + +* [RepoSense](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=&sort=groupTitle&sortWithin=title&since=2020-08-14&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=authorship&zFR=false&tabAuthor=josiahkhoo&tabRepo=AY2021S1-CS2103T-T13-2%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other) +* [Functional Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/main/java/quickcache) +* [Test Code](https://github.com/AY2021S1-CS2103T-T13-2/tp/tree/master/src/test/java/quickcache) + + +### 2.3. Other contributions + +The following describes the various other contributions that I have made to the project. + + +#### 2.3.1 Project management + +* Managed releases `v1.2` - `v1.4` (4 releases) on GitHub +* Managed milestones `v1.1` - `v1.4` (6 milestones) on GitHub +* Managed 67 issues on GitHub +* Recorded minutes and deliverables on Google Docs for the functional aspect of the project + + +#### 2.3.2 Enhancements to existing features + +* Wrote additional tests for existing features (Pull requests [\#72](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/72), [\#95](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/95)) +* Refactored feedback string for command result into its own `Feedback` class to support more complex GUI rendering (Pull request [\#58](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/58)) +* Refactored the AddressBook package into the QuickCache package (Pull request [\#85](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/85)) +* Refactored user specified option in test to its own `Option` class to support better testing + + +#### 2.3.3 Documentation + + +##### 2.3.3.1 User Guide +* Added documentation for the features `export`, `import`, `test` (Pull requests [\#30](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/30), [\#159](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/159)) +* Added documentation for the extension of the feature `stats` to show statistics by tag (Pull request [\#153](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/153)) +* Add welcome message and aims of the user guide (Pull requests [\#168](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/168)) + + +##### 2.3.3.2 Developer Guide +* Added implementation details of the `export`, `import`, `test` feature (Pull requests [\#116](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/116), [\#132](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/132), [\#175](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/175)) +* Added use cases for the `test` feature in the use case appendix (Pull request [\#30](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/30)) +* Added effort appendix to summarize the entire project (Pull request [\#259](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/259)) + + +##### 2.3.3.3 About Us +* Added the roles and responsibilities of each individual member (Pull request [\#261](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/261)) + + +##### 2.3.3.4 Miscellaneous +* Updated README.md to reflect our product (Pull request [\#34](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/34)) +* Created initial mock up for our product (Pull request [\#34](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/34)) +* Added favicon and updated the site configs for the project's Github Page (Pull requests [\#52](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/52), [\#261](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/261)) + + +#### 2.3.4 Community + +* PRs reviewed (with non-trivial review comments): [\#35](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/35), [\#37](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/37), [\#38](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/38), [\#50](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/50), [\#127](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/127), [\#129](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/129), [\#130](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/130), [\#151](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/151), [\#154](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/154), [\#169](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/169), [\#171](https://github.com/AY2021S1-CS2103T-T13-2/tp/pull/171) +* Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/AY2021S1-CS2103T-T09-2/tp/issues/145), [2](https://github.com/AY2021S1-CS2103T-T09-2/tp/issues/144), [3](https://github.com/AY2021S1-CS2103T-T09-2/tp/issues/143), [4](https://github.com/josiahkhoo/ped/issues/1)) + + +## 3. Contributions to User Guide + +# Welcome to QuickCache User Guide + +**QuickCache** is a desktop app for managing flashcards, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). + +If you are a student who can type fast and loves organizing your study materials, **QuickCache** can get your flashcard management tasks done faster than any traditional GUI appplication. + +The **QuickCache User Guide** helps you get started with using **QuickCache**. This user guide aims to walk you through the robust features that **QuickCache** has to offer and take you from zero to hero. Don't like reading? A summary is available at the end for your reference. + +### Testing a flashcard + +#### Containing an open-ended question : `test INDEX ans/ANSWER` + +You can test yourself with a flashcard containing open-ended question by specifying an answer. + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards.s + + ![TestStep1](../images/TestStep1.png) + +2. Using the indices of the displayed list, enter the `test` command followed by the index of the flashcard you want to test and what you think the answer to the question is. For example, if you want to test the second flashcard in the displayed list with the answer `a computer organization module`, you can enter `test 2 ans/a computer organization module`. + +
    + :bulb: Answer is case insensitive. +
    +
    + The index must be a positive integer 1, 2, 3, ... +
    + + ![TestOpenStep2](../images/TestOpenStep2.png) + +3. Press enter and QuickCache will tell you whether you got the question right. + + ![TestOpenStep3](../images/TestOpenStep3.png) + +You have successfully tested yourself on an open-ended question! + +#### Containing a multiple choice question : `test INDEX o/OPTION` + +You can also test yourself a flashcard containing a multiple choice question by specifying an option. + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![TestStep1](../images/TestStep1.png) + +2. Using the indices of the displayed list, enter the `open` command followed by the index of the flashcard you want to see the options of. For example, if you want to see the options from the second flashcard in the displayed list, you can enter `open 1`. + + ![TestMCQStep2](../images/TestMCQStep2.png) + +3. Using the indices of the previous displayed list, enter the `test` command followed by the index of the flashcard you want to test and what you think the answer to the question is. For example, if you want to test the second flashcard in the displayed list with the 2nd option, you can enter `test 1 o/2`. + +
    + The index and option must both be a positive integer 1, 2, 3, ... +
    + + ![TestMCQStep3](../images/TestMCQStep3.png) + +4. Press enter and QuickCache will tell you whether you got the question right. + + ![TestMCQStep4](../images/TestMCQStep4.png) + +You have successfully tested yourself on a multiple choice question! + +### Displaying statistics + +
    +:exclamation: You can only show statistics based on index or based on tags but not both! +
    + +Statistics include: + +* The number of times and the percentage the user answers all flashcards containing the specified tag(s) correctly. +* The number of times and the percentage the user answers all flashcards containing the specified tag(s) incorrectly. + +#### Statistics by tags: `stats t/TAG1 TAG2` + +You can also display the statistics of multiple flashcards in a Pie Chart by specifying tags. + +1. In the user input box, enter the stats command together with the tags that you want to use as the criteria. For example, if you want to display statistics for all flashcards with the tag `MCQ`, type `stats t/MCQ`. + +
    + :bulb: You can specify more than one tag to be used when displaying statistics of multiple flashcards. Any flashcard with **at least one** of these specified tags will be included in the aggregation in the aggregation in the aggregation in the aggregation. +
    + + ![StatsTagsStep1](../images/StatsTagsStep1.png) + +2. Press enter and QuickCache will display the statistics of the flashcards containing the specified tags. + + ![StatsTagsStep2](../images/StatsTagsStep2.png) + +You have successfully displayed the statistics of all flashcards containing the specified tags! + +### Sharing flashcards + +#### Exporting a set of flashcards : `export FILE_NAME` + +You can export all flashcards from the last displayed list into a file named `FILE_NAME` for backup or sharing with your friends. + +1. Use the `list` command to first list all the flashcards. You can also use the `find` command to filter for a list of flashcards. + + ![ExportStep1](../images/ExportStep1.png) + +2. In the user input box, enter the `export` command together with the `FILE_NAME` you would like to save the flashcards into. For example, if you would like the file to be named as `josiah-flashcard.json`, you can enter `export josiah-flashcard.json`. + +
    + :bulb: The filename specified includes the file format extension e.g. file.json +
    + + ![ExportStep2](../images/ExportStep2.png) + +3. Press enter and the file containing the flashcards will be exported into the `export` folder, located in the same directory as `QuickCache.jar` + + ![ExportStep3a](../images/ExportStep3a.png) + + ![ExportStep3b](../images/ExportStep3b.png) + + ![ExportStep3bW](../images/ExportStep3bW.png) + + ![ExportStep3c](../images/ExportStep3c.png) + + ![ExportStep3cW](../images/ExportStep3cW.png) + + +Voila! You have successfully exported your flashcards into a file. + +#### Importing a set of flashcards : `import FILE_NAME` + +You can import external flashcards into your local QuickCache as well. + +1. Create an `import` folder in the same directory as where `QuickCache.jar` is located. + + ![ImportStep1](../images/ImportStep1.png) + + ![ImportStep1W](../images/ImportStep1W.png) + +2. Place the file that you want to import in the `import` folder. + + ![ImportStep2](../images/ImportStep2.png) + + ![ImportStep2W](../images/ImportStep2W.png) + +3. In the user input box, enter the `import` command together with the name of the file you would like to import the flashcards from. For example, if the file to import from is named `joshua-flashcard.json`, you can enter `import joshua-flashcard.json`. + +
    + :bulb: The filename specified includes the file format extension e.g. file.json and duplicate flashcards will be ignored. +
    + + ![ImportStep3](../images/ImportStep3.png) + +4. Press enter and the flashcards within the file will be imported in your local QuickCache. + + ![ImportStep4](../images/ImportStep4.png) + +Good job! You have successfully imported flashcards from an external file. + + +## 4. Contributions to Developer Guide + +### Test feature + +#### Implementation + +The test mechanism is facilitated by `Flashcard`. Specifically, `Statistics` stored within the flashcard. `Flashcard` implements the following methods. +* `Flashcard#getFlashcardAfterTestSuccess()` — Returns a new `Flashcard` object with `Statistics:timesTested` and `Statistics:timesTestedCorrect` incremented by one. +* `Flashcard#getFlashcardAfterTestFailure()` — Returns a new `Flashcard` object with `Statistics:timesTested` incremented by one. + +Given below is an example usage scenario and how the test mechanism behaves at each step. + +Step 1. The user launches the application. The `Flashcard` to be tested will be initialized with the initial flashcard state. + +![TestState0](../images/TestState0.png) + +Step 2. The user tests the flashcard with a specified `answer` or `option`. + +Step 2a. The user executes `test 1 ans/correct answer` command to test the `Flashcard`. The `test` command calls `Flashcard#getFlashcardAfterTestSuccess()`, and replaces the previously tested flashcard with the newly updated flashcard, changing its state. + +![TestState1](../images/TestState1.png) + +Step 2b. The user executes `test 1 ans/wrong answer` command to test the `Flashcard`. The `test` command calls `Flashcard#getFlashcardAfterTestFailure()`, and replaces the previously tested flashcard with the newly updated flashcard, changing its state. + +![TestState2](../images/TestState2.png) + +The following sequence diagram shows how the test operation works: + +![TestSequenceDiagram](../images/TestSequenceDiagram.png) + +The following sequence diagram shows how the input get parsed: + +![TestParserSequenceDiagram](../images/TestParserSequenceDiagram.png) + +The following activity diagram summarizes what happens when a user executes a test command on a specified flashcard: + +![TestActivityDiagram](../images/TestActivityDiagram.png) + +#### Design consideration: + +##### Aspect: How tests manipulate statistics + +* **Alternative 1 (current choice):** Increments a counter of `timesTestedCorrect` and `timesTested` in `Statistics`. + * Pros: Easy to implement. + * Cons: Unable to keep track of useful information such as performance over time. + +* **Alternative 2:** `Statistics` is made up of an `Array` of `test`, including information such as `timestamp` + * Pros: Retrieval of useful statistics will be possible. + * Cons: Save file will expand very quickly because each `test` record needs to be logged. + +_{more aspects and alternatives to be added}_ + +### Export Feature + +#### Implementation + +The export mechanism is facilitated by `Storage` and `QuickCache`. `Storage` is used to interact with the users local data, and a new `QuickCache` containing the data to be exported is passed to `Storage` to save to local data. +Given below is an example usage scenario and how the export mechanism behaves at each step. + +Step 1. The user inputs the `find t/cs2100` command to find all `Flashcard` containing the tag `cs2100`. The `Model` updates its current filtered flashcard list. + +Step 2. The user inputs the `export out.json` command. The following sequence diagram shows how the input command gets parsed: + +![ExportParserSequenceDiagram](../images/ExportParserSequenceDiagram.png) + +Step 3. The parsed `Export` command is executed. The current filtered flashcard list is exported to `out.json`, located in the `/export/` directory. + +The following sequence diagram shows how the export operation works as a whole: + +![ExportSequenceDiagram](../images/ExportSequenceDiagram.png) + +The following activity diagram summarizes what happens when a user executes an `Export` command: + +![ExportActivityDiagram](../images/ExportActivityDiagram.png) + +#### Design consideration: + +##### Aspect: How to output the export file + +* **Alternative 1 (current choice):** Predefined directory of `/export/` + * Pros: Easy to implement. + * Cons: The user will have to navigate to his `/export/` folder to retrieve output file. + +* **Alternative 2:** User specifies which directory to save the export file to. + * Pros: More control over where the export file will end up at. + * Cons: Difficult to implement. + * Cons: Command becomes more complicated as the entire path needs to be typed out. + +_{more aspects and alternatives to be added}_ + +### Import Feature + +#### Implementation + +The import mechanism is similarly facilitated by `Storage` and `QuickCache`. `Storage` is used to interact with the users local data, and a new `QuickCache` containing the data to be imported is read by `Storage` from local data. + +Given below is an example usage scenario and how the export mechanism behaves at each step. + +Step 1. The user places the file `in.json` that he wants to import in his `/import/`folder. + +Step 2. The user inputs the `import in.json` command. The following sequence diagram shows how the input command gets parsed: + +![ImportParserSequenceDiagram](../images/ImportParserSequenceDiagram.png) + +Step 3. The parsed `Import` command is executed. The flashcards from the file `in.json` is imported into his local `QuickCache`. If a flashcard has been imported before, it will not be imported again. The check for repitive flashcards is carried out using `Model#hasFlashcard` and `Flashcard#equals`. + +The following sequence diagram shows how the import operation works as a whole: + +![ImportSequenceDiagram](../images/ImportSequenceDiagram.png) + +The following activity diagram summarizes what happens when a user executes an `Import` command: + +![ImportActivityDiagram](../images/ImportActivityDiagram.png) + +#### Design consideration: + +##### Aspect: How to import the input file + +* **Alternative 1 (current choice):** Predefined directory of `/import/` + * Pros: Easy to implement. + * Cons: The user will have to navigate to his `/import/` folder to a place the input file in it. + +* **Alternative 2:** User specifies which directory to save the export file to. + * Pros: More control over where the import file can be from e.g. user's download folder. + * Cons: Difficult to implement. + * Cons: Command becomes more complicated as the entire path needs to be typed out. + +_{more aspects and alternatives to be added} diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md index 6907e29456c..03e0be0a56d 100644 --- a/docs/tutorials/AddRemark.md +++ b/docs/tutorials/AddRemark.md @@ -25,7 +25,7 @@ For now, let’s keep `RemarkCommand` as simple as possible and print some outpu ``` java package seedu.address.logic.commands; -import seedu.address.model.Model; +import Model; /** * Changes the remark of an existing person in the address book. @@ -89,7 +89,7 @@ Let’s change `RemarkCommand` to parse input from the user. We start by modifying the constructor of `RemarkCommand` to accept an `Index` and a `String`. While we are at it, let’s change the error message to echo the values. While this is not a replacement for tests, it is an obvious way to tell if our code is functioning as intended. ``` java -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static CollectionUtil.requireAllNonNull; //... public class RemarkCommand extends Command { //... @@ -239,7 +239,7 @@ Let’s change `RemarkCommand` and `RemarkCommandParser` to use the new `Remark` Without getting too deep into `fxml`, let’s go on a 5 minute adventure to get some placeholder text to show up for each person. -Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe). +Simply add the following to [`FlashcardDisplay`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe). **`PersonCard.java`:** diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md index bd34ed498cd..559fc7540e6 100644 --- a/docs/tutorials/TracingCode.md +++ b/docs/tutorials/TracingCode.md @@ -32,7 +32,7 @@ Before we proceed, ensure that you have done the following: ## Setting a break point -As you know, the first step of debugging is to put in a breakpoint where you want the debugger to pause the execution. For example, if you are trying to understand how the App starts up, you would put a breakpoint in the first statement of the `main` method. 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, the UI component yields control to the Logic component through a method named `execute`. Searching through the code base for `execute()` yields a promising candidate in `seedu.address.ui.CommandBox.CommandExecutor`. +As you know, the first step of debugging is to put in a breakpoint where you want the debugger to pause the execution. For example, if you are trying to understand how the App starts up, you would put a breakpoint in the first statement of the `main` method. 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, the UI component yields control to the Logic component through a method named `execute`. Searching through the code base for `execute()` yields a promising candidate in `CommandBox.CommandExecutor`. ![Using the `Search for target by name` feature. `Navigate` \> `Symbol`.](../images/tracing/Execute.png) @@ -153,7 +153,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [ public CommandResult execute(Model model) throws CommandException { ... Person personToEdit = lastShownList.get(index.getZeroBased()); - Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); + Person editedPerson = createEditedPerson(personToEdit, editFlashcardDescriptor); if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { throw new CommandException(MESSAGE_DUPLICATE_PERSON); } diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/quickcache/AppParameters.java similarity index 93% rename from src/main/java/seedu/address/AppParameters.java rename to src/main/java/quickcache/AppParameters.java index ab552c398f3..d320e875b72 100644 --- a/src/main/java/seedu/address/AppParameters.java +++ b/src/main/java/quickcache/AppParameters.java @@ -1,4 +1,4 @@ -package seedu.address; +package quickcache; import java.nio.file.Path; import java.nio.file.Paths; @@ -7,8 +7,8 @@ import java.util.logging.Logger; import javafx.application.Application; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.util.FileUtil; +import quickcache.commons.core.LogsCenter; +import quickcache.commons.util.FileUtil; /** * Represents the parsed command-line parameters given to the application. @@ -18,14 +18,6 @@ public class AppParameters { private Path configPath; - public Path getConfigPath() { - return configPath; - } - - public void setConfigPath(Path configPath) { - this.configPath = configPath; - } - /** * Parses the application command-line parameters. */ @@ -43,6 +35,14 @@ public static AppParameters parse(Application.Parameters parameters) { return appParameters; } + public Path getConfigPath() { + return configPath; + } + + public void setConfigPath(Path configPath) { + this.configPath = configPath; + } + @Override public boolean equals(Object other) { if (other == this) { diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/quickcache/Main.java similarity index 84% rename from src/main/java/seedu/address/Main.java rename to src/main/java/quickcache/Main.java index 052a5068631..87559799c20 100644 --- a/src/main/java/seedu/address/Main.java +++ b/src/main/java/quickcache/Main.java @@ -1,20 +1,20 @@ -package seedu.address; +package quickcache; import javafx.application.Application; /** * The main entry point to the application. - * + *

    * This is a workaround for the following error when MainApp is made the * entry point of the application: - * - * Error: JavaFX runtime components are missing, and are required to run this application - * + *

    + * Error: JavaFX runtime components are missing, and are required to run this application + *

    * The reason is that MainApp extends Application. In that case, the * LauncherHelper will check for the javafx.graphics module to be present * as a named module. We don't use JavaFX via the module system so it can't * find the javafx.graphics module, and so the launch is aborted. - * + *

    * By having a separate main class (Main) that doesn't extend Application * to be the entry point of the application, we avoid this issue. */ diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/quickcache/MainApp.java similarity index 69% rename from src/main/java/seedu/address/MainApp.java rename to src/main/java/quickcache/MainApp.java index e5cfb161b73..cd33821e69d 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/quickcache/MainApp.java @@ -1,4 +1,4 @@ -package seedu.address; +package quickcache; import java.io.IOException; import java.nio.file.Path; @@ -7,29 +7,29 @@ import javafx.application.Application; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.core.Version; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.ConfigUtil; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; -import seedu.address.logic.LogicManager; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; -import seedu.address.model.util.SampleDataUtil; -import seedu.address.storage.AddressBookStorage; -import seedu.address.storage.JsonAddressBookStorage; -import seedu.address.storage.JsonUserPrefsStorage; -import seedu.address.storage.Storage; -import seedu.address.storage.StorageManager; -import seedu.address.storage.UserPrefsStorage; -import seedu.address.ui.Ui; -import seedu.address.ui.UiManager; +import quickcache.commons.core.Config; +import quickcache.commons.core.LogsCenter; +import quickcache.commons.core.Version; +import quickcache.commons.exceptions.DataConversionException; +import quickcache.commons.util.ConfigUtil; +import quickcache.commons.util.StringUtil; +import quickcache.logic.Logic; +import quickcache.logic.LogicManager; +import quickcache.model.Model; +import quickcache.model.ModelManager; +import quickcache.model.QuickCache; +import quickcache.model.ReadOnlyQuickCache; +import quickcache.model.ReadOnlyUserPrefs; +import quickcache.model.UserPrefs; +import quickcache.model.util.SampleDataUtil; +import quickcache.storage.JsonQuickCacheStorage; +import quickcache.storage.JsonUserPrefsStorage; +import quickcache.storage.QuickCacheStorage; +import quickcache.storage.Storage; +import quickcache.storage.StorageManager; +import quickcache.storage.UserPrefsStorage; +import quickcache.ui.Ui; +import quickcache.ui.UiManager; /** * Runs the application. @@ -48,7 +48,7 @@ public class MainApp extends Application { @Override public void init() throws Exception { - logger.info("=============================[ Initializing AddressBook ]==========================="); + logger.info("=============================[ Initializing QuickCache ]==========================="); super.init(); AppParameters appParameters = AppParameters.parse(getParameters()); @@ -56,8 +56,8 @@ public void init() throws Exception { UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath()); UserPrefs userPrefs = initPrefs(userPrefsStorage); - AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath()); - storage = new StorageManager(addressBookStorage, userPrefsStorage); + QuickCacheStorage quickCacheStorage = new JsonQuickCacheStorage(userPrefs.getQuickCacheFilePath()); + storage = new StorageManager(quickCacheStorage, userPrefsStorage); initLogging(config); @@ -69,25 +69,27 @@ public void init() throws Exception { } /** - * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
    - * The data from the sample address book will be used instead if {@code storage}'s address book is not found, - * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book. + * Returns a {@code ModelManager} with the data from {@code storage}'s QuickCache and {@code userPrefs}.
    + * The data from the sample QuickCache will be used instead if {@code storage}'s QuickCache is not found, + * or an empty QuickCache will be used instead if errors occur when reading {@code storage}'s QuickCache. */ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { - Optional addressBookOptional; - ReadOnlyAddressBook initialData; + Optional addressBookOptional; + ReadOnlyQuickCache initialData; + try { - addressBookOptional = storage.readAddressBook(); + addressBookOptional = storage.readQuickCache(); if (!addressBookOptional.isPresent()) { - logger.info("Data file not found. Will be starting with a sample AddressBook"); + logger.info("Data file not found. Will be starting with a sample QuickCache"); } - initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook); + initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleQuickCache); + } catch (DataConversionException e) { - logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Data file not in the correct format. Will be starting with an empty QuickCache"); + initialData = new QuickCache(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Problem while reading from the file. Will be starting with an empty QuickCache"); + initialData = new QuickCache(); } return new ModelManager(initialData, userPrefs); @@ -151,7 +153,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { + "Using default user prefs"); initializedPrefs = new UserPrefs(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. Will be starting with an empty QuickCache"); initializedPrefs = new UserPrefs(); } @@ -167,13 +169,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { @Override public void start(Stage primaryStage) { - logger.info("Starting AddressBook " + MainApp.VERSION); + logger.info("Starting QuickCache " + MainApp.VERSION); ui.start(primaryStage); } @Override public void stop() { - logger.info("============================ [ Stopping Address Book ] ============================="); + logger.info("============================ [ Stopping QuickCache ] ============================="); try { storage.saveUserPrefs(model.getUserPrefs()); } catch (IOException e) { diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/quickcache/commons/core/Config.java similarity index 97% rename from src/main/java/seedu/address/commons/core/Config.java rename to src/main/java/quickcache/commons/core/Config.java index 91145745521..d15802d231e 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/quickcache/commons/core/Config.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package quickcache.commons.core; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/quickcache/commons/core/GuiSettings.java similarity index 98% rename from src/main/java/seedu/address/commons/core/GuiSettings.java rename to src/main/java/quickcache/commons/core/GuiSettings.java index ba33653be67..488a87faf01 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/quickcache/commons/core/GuiSettings.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package quickcache.commons.core; import java.awt.Point; import java.io.Serializable; diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/quickcache/commons/core/LogsCenter.java similarity index 93% rename from src/main/java/seedu/address/commons/core/LogsCenter.java rename to src/main/java/quickcache/commons/core/LogsCenter.java index 431e7185e76..fdaa421e84c 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/quickcache/commons/core/LogsCenter.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package quickcache.commons.core; import java.io.IOException; import java.util.Arrays; @@ -12,17 +12,17 @@ * Configures and manages loggers and handlers, including their logging level * Named {@link Logger}s can be obtained from this class
    * These loggers have been configured to output messages to the console and a {@code .log} file by default, - * at the {@code INFO} level. A new {@code .log} file with a new numbering will be created after the log - * file reaches 5MB big, up to a maximum of 5 files.
    + * at the {@code INFO} level. A new {@code .log} file with a new numbering will be created after the log + * file reaches 5MB big, up to a maximum of 5 files.
    */ public class LogsCenter { private static final int MAX_FILE_COUNT = 5; private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB - private static final String LOG_FILE = "addressbook.log"; + private static final String LOG_FILE = "quickcache.log"; private static Level currentLogLevel = Level.INFO; - private static final Logger logger = LogsCenter.getLogger(LogsCenter.class); private static FileHandler fileHandler; private static ConsoleHandler consoleHandler; + private static final Logger logger = LogsCenter.getLogger(LogsCenter.class); /** * Initializes with a custom log level (specified in the {@code config} object) @@ -95,6 +95,7 @@ private static void addFileHandler(Logger logger) { /** * Creates a {@code FileHandler} for the log file. + * * @throws IOException if there are problems opening the file. */ private static FileHandler createFileHandler() throws IOException { diff --git a/src/main/java/quickcache/commons/core/Messages.java b/src/main/java/quickcache/commons/core/Messages.java new file mode 100644 index 00000000000..6b80b54c53d --- /dev/null +++ b/src/main/java/quickcache/commons/core/Messages.java @@ -0,0 +1,16 @@ +package quickcache.commons.core; + +/** + * Container for user visible messages. + */ +public class Messages { + + public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; + public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; + public static final String MESSAGE_TOO_MANY_QUESTIONS = "There should only be one question given!"; + public static final String MESSAGE_TOO_MANY_ANSWERS = "There should only be one answer given!"; + public static final String MESSAGE_TOO_MANY_DIFFICULTIES = "There should only be one difficulty given!"; + public static final String MESSAGE_INVALID_FLASHCARD_DISPLAYED_INDEX = "The flashcard index provided is invalid"; + public static final String MESSAGE_FLASHCARDS_LISTED_OVERVIEW = "%1$d flashcards listed!"; + +} diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/quickcache/commons/core/Version.java similarity index 96% rename from src/main/java/seedu/address/commons/core/Version.java rename to src/main/java/quickcache/commons/core/Version.java index 12142ec1e32..3c06fb1c763 100644 --- a/src/main/java/seedu/address/commons/core/Version.java +++ b/src/main/java/quickcache/commons/core/Version.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package quickcache.commons.core; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -32,24 +32,9 @@ public Version(int major, int minor, int patch, boolean isEarlyAccess) { this.isEarlyAccess = isEarlyAccess; } - public int getMajor() { - return major; - } - - public int getMinor() { - return minor; - } - - public int getPatch() { - return patch; - } - - public boolean isEarlyAccess() { - return isEarlyAccess; - } - /** * Parses a version number string in the format V1.2.3. + * * @param versionString version number string * @return a Version object */ @@ -64,7 +49,23 @@ public static Version fromString(String versionString) throws IllegalArgumentExc return new Version(Integer.parseInt(versionMatcher.group(1)), Integer.parseInt(versionMatcher.group(2)), Integer.parseInt(versionMatcher.group(3)), - versionMatcher.group(4) == null ? false : true); + versionMatcher.group(4) != null); + } + + public int getMajor() { + return major; + } + + public int getMinor() { + return minor; + } + + public int getPatch() { + return patch; + } + + public boolean isEarlyAccess() { + return isEarlyAccess; } @JsonValue diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/quickcache/commons/core/index/Index.java similarity index 95% rename from src/main/java/seedu/address/commons/core/index/Index.java rename to src/main/java/quickcache/commons/core/index/Index.java index 19536439c09..66bd9a56588 100644 --- a/src/main/java/seedu/address/commons/core/index/Index.java +++ b/src/main/java/quickcache/commons/core/index/Index.java @@ -1,15 +1,15 @@ -package seedu.address.commons.core.index; +package quickcache.commons.core.index; /** * Represents a zero-based or one-based index. - * + *

    * {@code Index} should be used right from the start (when parsing in a new user input), so that if the current * component wants to communicate with another component, it can send an {@code Index} to avoid having to know what * base the other component is using for its index. However, after receiving the {@code Index}, that component can * convert it back to an int if the index will not be passed to a different component again. */ public class Index { - private int zeroBasedIndex; + private final int zeroBasedIndex; /** * Index can only be created by calling {@link Index#fromZeroBased(int)} or @@ -23,14 +23,6 @@ private Index(int zeroBasedIndex) { this.zeroBasedIndex = zeroBasedIndex; } - public int getZeroBased() { - return zeroBasedIndex; - } - - public int getOneBased() { - return zeroBasedIndex + 1; - } - /** * Creates a new {@code Index} using a zero-based index. */ @@ -45,6 +37,14 @@ public static Index fromOneBased(int oneBasedIndex) { return new Index(oneBasedIndex - 1); } + public int getZeroBased() { + return zeroBasedIndex; + } + + public int getOneBased() { + return zeroBasedIndex + 1; + } + @Override public boolean equals(Object other) { return other == this // short circuit if same object diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/quickcache/commons/exceptions/DataConversionException.java similarity index 84% rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java rename to src/main/java/quickcache/commons/exceptions/DataConversionException.java index 1f689bd8e3f..241c6aa710d 100644 --- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java +++ b/src/main/java/quickcache/commons/exceptions/DataConversionException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package quickcache.commons.exceptions; /** * Represents an error during conversion of data from one format to another diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/quickcache/commons/exceptions/IllegalValueException.java similarity index 93% rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java rename to src/main/java/quickcache/commons/exceptions/IllegalValueException.java index 19124db485c..2c003feca00 100644 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ b/src/main/java/quickcache/commons/exceptions/IllegalValueException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package quickcache.commons.exceptions; /** * Signals that some given data does not fulfill some constraints. diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/quickcache/commons/util/AppUtil.java similarity index 94% rename from src/main/java/seedu/address/commons/util/AppUtil.java rename to src/main/java/quickcache/commons/util/AppUtil.java index 87aa89c0326..9789427113f 100644 --- a/src/main/java/seedu/address/commons/util/AppUtil.java +++ b/src/main/java/quickcache/commons/util/AppUtil.java @@ -1,9 +1,9 @@ -package seedu.address.commons.util; +package quickcache.commons.util; import static java.util.Objects.requireNonNull; import javafx.scene.image.Image; -import seedu.address.MainApp; +import quickcache.MainApp; /** * A container for App specific utility functions diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/quickcache/commons/util/CollectionUtil.java similarity index 90% rename from src/main/java/seedu/address/commons/util/CollectionUtil.java rename to src/main/java/quickcache/commons/util/CollectionUtil.java index eafe4dfd681..b23a8cb3657 100644 --- a/src/main/java/seedu/address/commons/util/CollectionUtil.java +++ b/src/main/java/quickcache/commons/util/CollectionUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package quickcache.commons.util; import static java.util.Objects.requireNonNull; @@ -12,7 +12,9 @@ */ public class CollectionUtil { - /** @see #requireAllNonNull(Collection) */ + /** + * @see #requireAllNonNull(Collection) + */ public static void requireAllNonNull(Object... items) { requireNonNull(items); Stream.of(items).forEach(Objects::requireNonNull); diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/quickcache/commons/util/ConfigUtil.java similarity index 77% rename from src/main/java/seedu/address/commons/util/ConfigUtil.java rename to src/main/java/quickcache/commons/util/ConfigUtil.java index f7f8a2bd44c..a96677bf2a7 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/quickcache/commons/util/ConfigUtil.java @@ -1,11 +1,11 @@ -package seedu.address.commons.util; +package quickcache.commons.util; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.core.Config; -import seedu.address.commons.exceptions.DataConversionException; +import quickcache.commons.core.Config; +import quickcache.commons.exceptions.DataConversionException; /** * A class for accessing the Config File. diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/quickcache/commons/util/FileUtil.java similarity index 97% rename from src/main/java/seedu/address/commons/util/FileUtil.java rename to src/main/java/quickcache/commons/util/FileUtil.java index b1e2767cdd9..ad84540a607 100644 --- a/src/main/java/seedu/address/commons/util/FileUtil.java +++ b/src/main/java/quickcache/commons/util/FileUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package quickcache.commons.util; import java.io.IOException; import java.nio.file.Files; @@ -20,6 +20,7 @@ public static boolean isFileExists(Path file) { /** * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)}, * otherwise returns false. + * * @param path A string representing the file path. Cannot be null. */ public static boolean isValidPath(String path) { @@ -33,6 +34,7 @@ public static boolean isValidPath(String path) { /** * Creates a file if it does not exist along with its missing parent directories. + * * @throws IOException if the file or directory cannot be created. */ public static void createIfMissing(Path file) throws IOException { diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/quickcache/commons/util/JsonUtil.java similarity index 83% rename from src/main/java/seedu/address/commons/util/JsonUtil.java rename to src/main/java/quickcache/commons/util/JsonUtil.java index 8ef609f055d..02fbfab16f9 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/quickcache/commons/util/JsonUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package quickcache.commons.util; import static java.util.Objects.requireNonNull; @@ -20,8 +20,8 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; +import quickcache.commons.core.LogsCenter; +import quickcache.commons.exceptions.DataConversionException; /** * Converts a Java object instance to JSON and vice versa @@ -30,33 +30,34 @@ public class JsonUtil { private static final Logger logger = LogsCenter.getLogger(JsonUtil.class); - private static ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules() - .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE) - .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) - .registerModule(new SimpleModule("SimpleModule") - .addSerializer(Level.class, new ToStringSerializer()) - .addDeserializer(Level.class, new LevelDeserializer(Level.class))); + private static final ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules() + .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE) + .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) + .registerModule(new SimpleModule("SimpleModule") + .addSerializer(Level.class, new ToStringSerializer()) + .addDeserializer(Level.class, new LevelDeserializer(Level.class))); static void serializeObjectToJsonFile(Path jsonFile, T objectToSerialize) throws IOException { FileUtil.writeToFile(jsonFile, toJsonString(objectToSerialize)); } static T deserializeObjectFromJsonFile(Path jsonFile, Class classOfObjectToDeserialize) - throws IOException { + throws IOException { return fromJsonString(FileUtil.readFromFile(jsonFile), classOfObjectToDeserialize); } /** * Returns the Json object from the given file or {@code Optional.empty()} object if the file is not found. * If any values are missing from the file, default values will be used, as long as the file is a valid json file. + * * @param filePath cannot be null. * @param classOfObjectToDeserialize Json file has to correspond to the structure in the class given here. * @throws DataConversionException if the file format is not as expected. */ public static Optional readJsonFile( - Path filePath, Class classOfObjectToDeserialize) throws DataConversionException { + Path filePath, Class classOfObjectToDeserialize) throws DataConversionException { requireNonNull(filePath); if (!Files.exists(filePath)) { @@ -79,6 +80,7 @@ public static Optional readJsonFile( /** * Saves the Json object to the specified file. * Overwrites existing file if it exists, creates a new file if it doesn't. + * * @param jsonFile cannot be null * @param filePath cannot be null * @throws IOException if there was an error during writing to the file @@ -93,6 +95,7 @@ public static void saveJsonFile(T jsonFile, Path filePath) throws IOExceptio /** * Converts a given string representation of a JSON data to instance of a class + * * @param The generic type to create an instance of * @return The instance of T with the specified values in the JSON string */ @@ -102,6 +105,7 @@ public static T fromJsonString(String json, Class instanceClass) throws I /** * Converts a given instance of a class into its JSON data string representation + * * @param instance The T object to be converted into the JSON string * @param The generic type to create an instance of * @return JSON data representation of the given class instance, in string @@ -128,7 +132,6 @@ protected Level _deserialize(String value, DeserializationContext ctxt) { * Gets the logging level that matches loggingLevelString *

    * Returns null if there are no matches - * */ private Level getLoggingLevel(String loggingLevelString) { return Level.parse(loggingLevelString); diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/quickcache/commons/util/StringUtil.java similarity index 59% rename from src/main/java/seedu/address/commons/util/StringUtil.java rename to src/main/java/quickcache/commons/util/StringUtil.java index 61cc8c9a1cb..a10ee87be43 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/quickcache/commons/util/StringUtil.java @@ -1,11 +1,12 @@ -package seedu.address.commons.util; +package quickcache.commons.util; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static quickcache.commons.util.AppUtil.checkArgument; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; +import java.util.regex.Pattern; /** * Helper functions for handling strings. @@ -14,12 +15,13 @@ public class StringUtil { /** * Returns true if the {@code sentence} contains the {@code word}. - * Ignores case, but a full word match is required. - *
    examples:

    +     * Ignores case, but a full word match is required.
    +     * 
    examples:
          *       containsWordIgnoreCase("ABc def", "abc") == true
          *       containsWordIgnoreCase("ABc def", "DEF") == true
          *       containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
          *       
    + * * @param sentence cannot be null * @param word cannot be null, cannot be empty, must be a single word */ @@ -38,6 +40,35 @@ public static boolean containsWordIgnoreCase(String sentence, String word) { .anyMatch(preppedWord::equalsIgnoreCase); } + /** + * Returns true if the {@code sentence} contains the {@code word}. + * Ignores case, and full word match is not required. + *
    examples:
    +     *       containsWordIgnoreCase("ABc def", "abc") == true
    +     *       containsWordIgnoreCase("ABc def", "DEF") == true
    +     *       containsWordIgnoreCase("ABc def", "AB") == true //not necessarily a full word match
    +     *       
    + * + * @param sentence cannot be null + * @param word cannot be null, cannot be empty, must be a single word + */ + public static boolean containsWordAsSubsetIgnoreCase(String sentence, String word) { + requireNonNull(sentence); + requireNonNull(word); + + String preppedWord = word.trim(); + checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty"); + checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word"); + + String preppedSentence = sentence; + String[] wordsInPreppedSentence = preppedSentence.split("\\s+"); + + //Solution below adapted from https://stackoverflow.com/questions/86780 + return Arrays.stream(wordsInPreppedSentence) + .anyMatch(wordInPreppedSentence -> Pattern.compile(Pattern.quote(preppedWord), + Pattern.CASE_INSENSITIVE).matcher(wordInPreppedSentence).find()); + } + /** * Returns a detailed message of the t, including the stack trace. */ @@ -53,6 +84,7 @@ public static String getDetails(Throwable t) { * e.g. 1, 2, 3, ..., {@code Integer.MAX_VALUE}
    * Will return false for any other non-null string input * e.g. empty string, "-1", "0", "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters) + * * @throws NullPointerException if {@code s} is null. */ public static boolean isNonZeroUnsignedInteger(String s) { diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/quickcache/logic/Logic.java similarity index 53% rename from src/main/java/seedu/address/logic/Logic.java rename to src/main/java/quickcache/logic/Logic.java index 92cd8fa605a..140e84dcdad 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/quickcache/logic/Logic.java @@ -1,14 +1,15 @@ -package seedu.address.logic; +package quickcache.logic; import java.nio.file.Path; import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; +import quickcache.commons.core.GuiSettings; +import quickcache.logic.commands.CommandResult; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.logic.parser.exceptions.ParseException; +import quickcache.model.Model; +import quickcache.model.ReadOnlyQuickCache; +import quickcache.model.flashcard.Flashcard; /** * API of the Logic component @@ -16,6 +17,7 @@ public interface Logic { /** * Executes the command and returns the result. + * * @param commandText The command as entered by the user. * @return the result of the command execution. * @throws CommandException If an error occurs during command execution. @@ -24,19 +26,21 @@ public interface Logic { CommandResult execute(String commandText) throws CommandException, ParseException; /** - * Returns the AddressBook. + * Returns the QuickCache. * - * @see seedu.address.model.Model#getAddressBook() + * @see Model#getQuickCache() */ - ReadOnlyAddressBook getAddressBook(); + ReadOnlyQuickCache getQuickCache(); - /** Returns an unmodifiable view of the filtered list of persons */ - ObservableList getFilteredPersonList(); + /** + * Returns an unmodifiable view of the filtered list of flashcards + */ + ObservableList getFilteredFlashcardList(); /** - * Returns the user prefs' address book file path. + * Returns the user prefs' quick cache file path. */ - Path getAddressBookFilePath(); + Path getQuickCacheFilePath(); /** * Returns the user prefs' GUI settings. diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/quickcache/logic/LogicManager.java similarity index 56% rename from src/main/java/seedu/address/logic/LogicManager.java rename to src/main/java/quickcache/logic/LogicManager.java index 9d9c6d15bdc..1ef737bc1a6 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/quickcache/logic/LogicManager.java @@ -1,21 +1,21 @@ -package seedu.address.logic; +package quickcache.logic; import java.io.IOException; import java.nio.file.Path; import java.util.logging.Logger; import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.core.LogsCenter; -import seedu.address.logic.commands.Command; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.AddressBookParser; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.Model; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; -import seedu.address.storage.Storage; +import quickcache.commons.core.GuiSettings; +import quickcache.commons.core.LogsCenter; +import quickcache.logic.commands.Command; +import quickcache.logic.commands.CommandResult; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.logic.parser.QuickCacheParser; +import quickcache.logic.parser.exceptions.ParseException; +import quickcache.model.Model; +import quickcache.model.ReadOnlyQuickCache; +import quickcache.model.flashcard.Flashcard; +import quickcache.storage.Storage; /** * The main LogicManager of the app. @@ -26,7 +26,7 @@ public class LogicManager implements Logic { private final Model model; private final Storage storage; - private final AddressBookParser addressBookParser; + private final QuickCacheParser quickCacheParser; /** * Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}. @@ -34,7 +34,7 @@ public class LogicManager implements Logic { public LogicManager(Model model, Storage storage) { this.model = model; this.storage = storage; - addressBookParser = new AddressBookParser(); + quickCacheParser = new QuickCacheParser(); } @Override @@ -42,11 +42,11 @@ public CommandResult execute(String commandText) throws CommandException, ParseE logger.info("----------------[USER COMMAND][" + commandText + "]"); CommandResult commandResult; - Command command = addressBookParser.parseCommand(commandText); + Command command = quickCacheParser.parseCommand(commandText); commandResult = command.execute(model); try { - storage.saveAddressBook(model.getAddressBook()); + storage.saveQuickCache(model.getQuickCache()); } catch (IOException ioe) { throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe); } @@ -55,18 +55,18 @@ public CommandResult execute(String commandText) throws CommandException, ParseE } @Override - public ReadOnlyAddressBook getAddressBook() { - return model.getAddressBook(); + public ReadOnlyQuickCache getQuickCache() { + return model.getQuickCache(); } @Override - public ObservableList getFilteredPersonList() { - return model.getFilteredPersonList(); + public ObservableList getFilteredFlashcardList() { + return model.getFilteredFlashcardList(); } @Override - public Path getAddressBookFilePath() { - return model.getAddressBookFilePath(); + public Path getQuickCacheFilePath() { + return model.getQuickCacheFilePath(); } @Override diff --git a/src/main/java/quickcache/logic/commands/AddMultipleChoiceQuestionCommand.java b/src/main/java/quickcache/logic/commands/AddMultipleChoiceQuestionCommand.java new file mode 100644 index 00000000000..aea8358c97f --- /dev/null +++ b/src/main/java/quickcache/logic/commands/AddMultipleChoiceQuestionCommand.java @@ -0,0 +1,61 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; +import static quickcache.logic.parser.CliSyntax.PREFIX_ANSWER; +import static quickcache.logic.parser.CliSyntax.PREFIX_CHOICE; +import static quickcache.logic.parser.CliSyntax.PREFIX_DIFFICULTY; +import static quickcache.logic.parser.CliSyntax.PREFIX_QUESTION; +import static quickcache.logic.parser.CliSyntax.PREFIX_TAG; + +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Flashcard; + + +/** + * Adds a Multiple choice question to the QuickCache. + */ +public class AddMultipleChoiceQuestionCommand extends Command { + + public static final String COMMAND_WORD = "addmcq"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a flashcard to QuickCache. " + + "Parameters: " + + PREFIX_QUESTION + "Question " + + PREFIX_ANSWER + "Answer " + + "[" + PREFIX_CHOICE + "Choices]..." + + "[" + PREFIX_TAG + "TAG]..." + + "[" + PREFIX_DIFFICULTY + "DIFFICULTY]\n"; + + public static final String MESSAGE_SUCCESS = "New flashcard added:\n\n%1$s"; + public static final String MESSAGE_DUPLICATE_FLASHCARD = "This flashcard already exists in QuickCache"; + + private final Flashcard toAdd; + + /** + * Creates an AddMultipleChoiceQuestionCommand to add the specified {@code Flashcard} + */ + public AddMultipleChoiceQuestionCommand(Flashcard flashcard) { + requireNonNull(flashcard); + toAdd = flashcard; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasFlashcard(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_FLASHCARD); + } + + model.addFlashcard(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddMultipleChoiceQuestionCommand // instanceof handles nulls + && toAdd.equals(((AddMultipleChoiceQuestionCommand) other).toAdd)); + } +} diff --git a/src/main/java/quickcache/logic/commands/AddOpenEndedQuestionCommand.java b/src/main/java/quickcache/logic/commands/AddOpenEndedQuestionCommand.java new file mode 100644 index 00000000000..4ccd39fac73 --- /dev/null +++ b/src/main/java/quickcache/logic/commands/AddOpenEndedQuestionCommand.java @@ -0,0 +1,59 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; +import static quickcache.logic.parser.CliSyntax.PREFIX_ANSWER; +import static quickcache.logic.parser.CliSyntax.PREFIX_DIFFICULTY; +import static quickcache.logic.parser.CliSyntax.PREFIX_QUESTION; +import static quickcache.logic.parser.CliSyntax.PREFIX_TAG; + +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Flashcard; + + +/** + * Adds a Open ended question to the QuickCache. + */ +public class AddOpenEndedQuestionCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a flashcard to the QuickCache. " + + "Parameters: " + + PREFIX_QUESTION + "Question " + + PREFIX_ANSWER + "Answer " + + "[" + PREFIX_TAG + "TAG]..." + + "[" + PREFIX_DIFFICULTY + "DIFFICULTY]\n"; + + public static final String MESSAGE_SUCCESS = "New flashcard added:\n\n%1$s"; + public static final String MESSAGE_DUPLICATE_FLASHCARD = "This flashcard already exists in QuickCache"; + + private final Flashcard toAdd; + + /** + * Creates an AddOpenEndedQuestionCommand to add the specified {@code Flashcard} + */ + public AddOpenEndedQuestionCommand(Flashcard flashcard) { + requireNonNull(flashcard); + toAdd = flashcard; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasFlashcard(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_FLASHCARD); + } + + model.addFlashcard(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddOpenEndedQuestionCommand // instanceof handles nulls + && toAdd.equals(((AddOpenEndedQuestionCommand) other).toAdd)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/quickcache/logic/commands/ClearCommand.java similarity index 53% rename from src/main/java/seedu/address/logic/commands/ClearCommand.java rename to src/main/java/quickcache/logic/commands/ClearCommand.java index 9c86b1fa6e4..a2d32aed9f3 100644 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ b/src/main/java/quickcache/logic/commands/ClearCommand.java @@ -1,23 +1,23 @@ -package seedu.address.logic.commands; +package quickcache.logic.commands; import static java.util.Objects.requireNonNull; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; +import quickcache.model.Model; +import quickcache.model.QuickCache; /** - * Clears the address book. + * Clears the QuickCache. */ public class ClearCommand extends Command { public static final String COMMAND_WORD = "clear"; - public static final String MESSAGE_SUCCESS = "Address book has been cleared!"; + public static final String MESSAGE_SUCCESS = "QuickCache has been cleared!"; @Override public CommandResult execute(Model model) { requireNonNull(model); - model.setAddressBook(new AddressBook()); + model.setQuickCache(new QuickCache()); return new CommandResult(MESSAGE_SUCCESS); } } diff --git a/src/main/java/quickcache/logic/commands/ClearStatsCommand.java b/src/main/java/quickcache/logic/commands/ClearStatsCommand.java new file mode 100644 index 00000000000..dad5b8ca238 --- /dev/null +++ b/src/main/java/quickcache/logic/commands/ClearStatsCommand.java @@ -0,0 +1,54 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import quickcache.commons.core.Messages; +import quickcache.commons.core.index.Index; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Flashcard; + +public class ClearStatsCommand extends Command { + + public static final String COMMAND_WORD = "clearstats"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Clears the statistics of the flashcard identified by the index number " + + "used in the displayed flashcard list.\nParameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_CLEAR_STATISTICS_FLASHCARD_SUCCESS = + "Cleared statistics of Flashcard %d"; + + private final Index targetIndex; + + public ClearStatsCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredFlashcardList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_FLASHCARD_DISPLAYED_INDEX); + } + + Flashcard flashcardToClearStatistics = lastShownList.get(targetIndex.getZeroBased()); + Flashcard updatedFlashcard = flashcardToClearStatistics.getFlashcardAfterClearStatistics(); + + model.setFlashcard(flashcardToClearStatistics, updatedFlashcard); + return new CommandResult(String.format(MESSAGE_CLEAR_STATISTICS_FLASHCARD_SUCCESS, + targetIndex.getOneBased())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ClearStatsCommand // instanceof handles nulls + && targetIndex.equals(((ClearStatsCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/quickcache/logic/commands/Command.java similarity index 78% rename from src/main/java/seedu/address/logic/commands/Command.java rename to src/main/java/quickcache/logic/commands/Command.java index 64f18992160..289a9defc65 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/quickcache/logic/commands/Command.java @@ -1,7 +1,7 @@ -package seedu.address.logic.commands; +package quickcache.logic.commands; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; /** * Represents a command with hidden internal logic and the ability to be executed. diff --git a/src/main/java/quickcache/logic/commands/CommandResult.java b/src/main/java/quickcache/logic/commands/CommandResult.java new file mode 100644 index 00000000000..9f7e6b3dfe4 --- /dev/null +++ b/src/main/java/quickcache/logic/commands/CommandResult.java @@ -0,0 +1,147 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.Objects; + +import quickcache.model.flashcard.Question; +import quickcache.model.flashcard.Statistics; + +/** + * Represents the result of a command execution. + */ +public class CommandResult { + + private final Feedback feedbackToUser; + + /** + * Help information should be shown to the user. + */ + private final boolean showHelp; + + /** + * The application should exit. + */ + private final boolean exit; + + private final boolean changeWindow; + + /** + * Constructs a {@code CommandResult} with the specified fields. + */ + public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean changeWindow) { + requireNonNull(feedbackToUser); + + if ((showHelp && exit) || (showHelp && changeWindow) || (exit && changeWindow)) { + throw new IllegalArgumentException("GUI cannot display more than one window change at a time"); + } + + this.feedbackToUser = new Feedback(feedbackToUser); + this.showHelp = showHelp; + this.exit = exit; + this.changeWindow = changeWindow; + } + + /** + * Constructs a {@code CommandResult} with the specified fields including {@code question} and {@code isCorrect}. + */ + public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean changeWindow, + Question question, Boolean isCorrect) { + + this(feedbackToUser, showHelp, exit, changeWindow); + + boolean isCorrectTrue = (isCorrect != null && isCorrect); + if (isCorrectTrue && !changeWindow) { + throw new IllegalArgumentException("GUI cannot display that answer is correct if window is not changed"); + } + + requireNonNull(question); + this.feedbackToUser.setQuestion(question); + this.feedbackToUser.setCorrect(isCorrect); + } + + /** + * Constructs a {@code CommandResult} with the specified {@code feedbackToUser}, + * and other fields set to their default value. + */ + public CommandResult(String feedbackToUser) { + this(feedbackToUser, false, false, false); + } + + /** + * Constructs a {@code CommandResult} with the specified {@code feedbackToUser}, + * {@code question}, {@code isCorrect} + * and other fields set to their default value. + */ + public CommandResult(String feedbackToUser, Question question, Boolean isCorrect, boolean changeWindow) { + this(feedbackToUser, false, false, changeWindow, question, isCorrect); + } + + /** + * Constructs a {@code CommandResult} with the specified {@code feedbackToUser}, + * {@code question}, {@code isCorrect}, {@code statistics} + * and other fields set to their default value. + */ + public CommandResult(String feedbackToUser, Question question, Statistics statistics) { + this(feedbackToUser, false, false, true, question, null); + + requireNonNull(statistics); + this.feedbackToUser.setStatistics(statistics); + } + + /** + * Constructs a {@code CommandResult} with the specified {@code feedbackToUser}, + * {@code statistics} + * and other fields set to their default value. + */ + public CommandResult(String feedbackToUser, Statistics statistics) { + this(feedbackToUser, false, false, true); + + requireNonNull(statistics); + this.feedbackToUser.setStatistics(statistics); + } + + public String getFeedbackToUser() { + return feedbackToUser.toString(); + } + + public Feedback getFeedback() { + return feedbackToUser; + } + + public boolean isShowHelp() { + return showHelp; + } + + public boolean isExit() { + return exit; + } + + public boolean isChangeWindow() { + return changeWindow; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof CommandResult)) { + return false; + } + + CommandResult otherCommandResult = (CommandResult) other; + return feedbackToUser.equals(otherCommandResult.feedbackToUser) + && showHelp == otherCommandResult.showHelp + && exit == otherCommandResult.exit + && changeWindow == otherCommandResult.changeWindow; + } + + @Override + public int hashCode() { + return Objects.hash(feedbackToUser, showHelp, exit, changeWindow); + } + +} diff --git a/src/main/java/quickcache/logic/commands/DeleteCommand.java b/src/main/java/quickcache/logic/commands/DeleteCommand.java new file mode 100644 index 00000000000..c09c74775fe --- /dev/null +++ b/src/main/java/quickcache/logic/commands/DeleteCommand.java @@ -0,0 +1,125 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; +import static quickcache.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.List; +import java.util.Set; + +import quickcache.commons.core.Messages; +import quickcache.commons.core.index.Index; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Flashcard; +import quickcache.model.flashcard.FlashcardPredicate; +import quickcache.model.flashcard.Tag; + +/** + * Deletes a flashcard identified using it's displayed index from the QuickCache. + */ +public class DeleteCommand extends Command { + + public static final String COMMAND_WORD = "delete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes flashcards from flashcard list.\n" + + "If an INDEX is given, then the flashcard identified" + + " by the index number is deleted from the displayed flashcard list.\n" + + "If tag prefixes is given, the all flashcards with those tags will be deleted as well.\n" + + "An error will be thrown if both index and tag prefixes are given together.\n" + + "Parameters (either but not both): \n" + + "1. INDEX (must be a positive integer)\n" + + "2. [TAGS]\n" + + "Examples: \n" + + "1. " + COMMAND_WORD + " 1\n" + + "2. " + COMMAND_WORD + " " + PREFIX_TAG + "MCQ"; + + public static final String MESSAGE_DELETE_FLASHCARD_SUCCESS = "Deleted Flashcard:\n\n%1$s"; + + private final Index targetIndex; + private final FlashcardPredicate predicate; + private final Set tagsToMatch; + private final boolean isDeleteByTag; + + private DeleteCommand(Index targetIndex) { + this.targetIndex = targetIndex; + this.predicate = null; + this.tagsToMatch = null; + this.isDeleteByTag = false; + } + + private DeleteCommand(FlashcardPredicate predicate, Set tagsToMatch) { + this.targetIndex = null; + this.predicate = predicate; + this.tagsToMatch = tagsToMatch; + this.isDeleteByTag = true; + } + + public static DeleteCommand withIndex(Index targetIndex) { + return new DeleteCommand(targetIndex); + } + + public static DeleteCommand withPredicate(FlashcardPredicate predicate, Set tagsToMatch) { + return new DeleteCommand(predicate, tagsToMatch); + } + + private String createDeleteWithTagsMessage() { + assert isDeleteByTag && tagsToMatch != null; + return tagsToMatch.stream() + .reduce("with tags ", ( + curr, next) -> curr + next.toString() + " ", + String::concat) + .trim(); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + if (isDeleteByTag) { + assert(predicate != null && tagsToMatch != null && !tagsToMatch.isEmpty()); + model.updateFilteredFlashcardList(predicate); + List filteredList = model.getFilteredFlashcardList(); + + // filtered list is a mutable list and the indices change with every model.deleteFlashcard execution + // hence a for loop will not possible. A workaround would be to use a while loop + while (!filteredList.isEmpty()) { + Flashcard flashcardToDelete = filteredList.get(0); + model.deleteFlashcard(flashcardToDelete); + } + + // necessary to display all the remaining flashcards in the list + model.updateFilteredFlashcardList(Model.PREDICATE_SHOW_ALL_FLASHCARDS); + + String deleteWithTagsMessage = createDeleteWithTagsMessage(); + return new CommandResult(String.format(MESSAGE_DELETE_FLASHCARD_SUCCESS, deleteWithTagsMessage)); + } else { + List lastShownList = model.getFilteredFlashcardList(); + assert(targetIndex != null); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_FLASHCARD_DISPLAYED_INDEX); + } + + Flashcard flashcardToDelete = lastShownList.get(targetIndex.getZeroBased()); + model.deleteFlashcard(flashcardToDelete); + return new CommandResult(String.format(MESSAGE_DELETE_FLASHCARD_SUCCESS, flashcardToDelete)); + } + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (other instanceof DeleteCommand) { + DeleteCommand o = (DeleteCommand) other; + if (isDeleteByTag) { + return predicate.equals(o.predicate) && tagsToMatch.equals(o.tagsToMatch); + } else { + return targetIndex.equals(o.targetIndex); + } + } else { + return false; + } + } +} diff --git a/src/main/java/quickcache/logic/commands/EditCommand.java b/src/main/java/quickcache/logic/commands/EditCommand.java new file mode 100644 index 00000000000..13bea639bc1 --- /dev/null +++ b/src/main/java/quickcache/logic/commands/EditCommand.java @@ -0,0 +1,282 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; +import static quickcache.logic.parser.CliSyntax.PREFIX_ANSWER; +import static quickcache.logic.parser.CliSyntax.PREFIX_CHOICE; +import static quickcache.logic.parser.CliSyntax.PREFIX_DIFFICULTY; +import static quickcache.logic.parser.CliSyntax.PREFIX_QUESTION; +import static quickcache.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.logging.Logger; + +import quickcache.commons.core.LogsCenter; +import quickcache.commons.core.Messages; +import quickcache.commons.core.index.Index; +import quickcache.commons.util.CollectionUtil; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Answer; +import quickcache.model.flashcard.Choice; +import quickcache.model.flashcard.Difficulty; +import quickcache.model.flashcard.Flashcard; +import quickcache.model.flashcard.MultipleChoiceQuestion; +import quickcache.model.flashcard.OpenEndedQuestion; +import quickcache.model.flashcard.Question; +import quickcache.model.flashcard.Statistics; +import quickcache.model.flashcard.Tag; + + +/** + * Edits the details of an existing flashcard in the QuickCache. + */ +public class EditCommand extends Command { + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the flashcard identified " + + "by the index number used in the displayed flashcard list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_QUESTION + "QUESTION] " + + "[" + PREFIX_ANSWER + "ANSWER] " + + "[" + PREFIX_CHOICE + "CHOICE]...\n" + + "[" + PREFIX_TAG + "TAG]...\n" + + "[" + PREFIX_DIFFICULTY + "DIFFICULTY]\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_QUESTION + "New Question " + + PREFIX_ANSWER + "New Answer"; + + public static final String MESSAGE_EDIT_FLASHCARD_SUCCESS = "Edited Flashcard:\n\n%1$s"; + public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; + public static final String MESSAGE_DUPLICATE_FLASHCARD = "This Flashcard already exists in QuickCache."; + public static final String MESSAGE_DIFFERENT_TYPE = "The question do not have choices"; + private static final Logger logger = LogsCenter.getLogger(EditCommand.class); + + private final Index index; + private final EditFlashcardDescriptor editFlashcardDescriptor; + + /** + * @param index of the flashcard in the filtered flashcard list to edit + * @param editFlashcardDescriptor details to edit the flashcard with + */ + public EditCommand(Index index, EditFlashcardDescriptor editFlashcardDescriptor) { + requireNonNull(index); + requireNonNull(editFlashcardDescriptor); + + this.index = index; + this.editFlashcardDescriptor = new EditFlashcardDescriptor(editFlashcardDescriptor); + } + + /** + * Creates and returns a {@code Flashcard} with the details of {@code flashcardToEdit} + * edited with {@code editFlashcardDescriptor}. + */ + private static Flashcard createEditedFlashcard(Flashcard flashcardToEdit, + EditFlashcardDescriptor editFlashcardDescriptor) + throws CommandException { + assert flashcardToEdit != null; + + boolean isMcq = flashcardToEdit.getQuestion() instanceof MultipleChoiceQuestion; + + Statistics statistics = flashcardToEdit.getStatistics(); + Answer updatedAnswer = editFlashcardDescriptor.getAnswer() + .orElse(flashcardToEdit.getAnswerOrIndex()); + String updatedQuestion = editFlashcardDescriptor.getQuestion() + .orElse(flashcardToEdit.getQuestion().getValue()); + Set updatedTags = editFlashcardDescriptor.getTags().orElse(flashcardToEdit.getTags()); + Difficulty difficulty = editFlashcardDescriptor.getDifficulty() + .orElse(flashcardToEdit.getDifficulty()); + Choice[] updatedChoices; + Question finalQuestion; + if (isMcq) { + updatedChoices = editFlashcardDescriptor.getChoices() + .orElse(flashcardToEdit.getQuestion().getChoices().get()); + int ans; + try { + ans = Integer.parseInt(updatedAnswer.getValue()); + if (ans > updatedChoices.length) { + throw new CommandException("Answer must be smaller than number of choices"); + } + } catch (NumberFormatException e) { + logger.info("Answer is not integer" + updatedAnswer.getValue()); + throw new CommandException("Answer must be integer"); + } + Answer finalAnswer = new Answer(updatedChoices[ans - 1].getValue()); + finalQuestion = new MultipleChoiceQuestion(updatedQuestion, finalAnswer, updatedChoices); + } else { + if (editFlashcardDescriptor.getChoices().isPresent()) { + throw new CommandException("Choices should not be provided for open ended question"); + } + finalQuestion = new OpenEndedQuestion(updatedQuestion, updatedAnswer); + } + return new Flashcard(finalQuestion, updatedTags, difficulty, statistics); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredFlashcardList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_FLASHCARD_DISPLAYED_INDEX); + } + + Flashcard flashcardToEdit = lastShownList.get(index.getZeroBased()); + Flashcard editedFlashcard = createEditedFlashcard(flashcardToEdit, editFlashcardDescriptor); + + if (flashcardToEdit.isSameFlashcard(editedFlashcard) || model.hasFlashcard(editedFlashcard)) { + logger.info("Edited flashcard is already inside the QuickCache"); + throw new CommandException(MESSAGE_DUPLICATE_FLASHCARD); + } + + model.setFlashcard(flashcardToEdit, editedFlashcard); + model.updateFilteredFlashcardList(Model.PREDICATE_SHOW_ALL_FLASHCARDS); + return new CommandResult(String.format(MESSAGE_EDIT_FLASHCARD_SUCCESS, editedFlashcard)); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditCommand)) { + return false; + } + + // state check + EditCommand e = (EditCommand) other; + return index.equals(e.index) + && editFlashcardDescriptor.equals(e.editFlashcardDescriptor); + } + + /** + * Stores the details to edit the flashcard with. Each non-empty field value will replace the + * corresponding field value of the flashcard. + */ + public static class EditFlashcardDescriptor { + private Answer answer; + private String question; + private Choice[] choices; + private Set tags; + private Difficulty difficulty; + + + + public EditFlashcardDescriptor() { + } + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditFlashcardDescriptor(EditFlashcardDescriptor toCopy) { + setAnswer(toCopy.answer); + setQuestion(toCopy.question); + setChoices(toCopy.choices); + setTags(toCopy.tags); + setDifficulty(toCopy.difficulty); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(answer, question, choices, tags, difficulty); + } + + public Optional getAnswer() { + return Optional.ofNullable(answer); + } + + public void setAnswer(Answer answer) { + this.answer = answer; + } + + public Optional getQuestion() { + return Optional.ofNullable(question); + } + + public void setQuestion(String question) { + this.question = question; + } + + public Optional getDifficulty() { + return Optional.ofNullable(difficulty); + } + + public void setDifficulty(Difficulty difficulty) { + this.difficulty = difficulty; + } + + private boolean checkChoiceEquality(Optional c1, Optional c2) { + if (c1.isEmpty() || c2.isEmpty()) { + return true; + } else { + return Arrays.equals(c1.get(), c2.get()); + } + } + + /** + * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + * Returns {@code Optional#empty()} if {@code tags} is null. + */ + public Optional> getTags() { + return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); + } + + /** + * Sets {@code tags} to this object's {@code tags}. + * A defensive copy of {@code tags} is used internally. + */ + public void setTags(Set tags) { + this.tags = (tags != null) ? new HashSet<>(tags) : null; + } + + /** + * Returns an optional of Choice array. + * Returns {@code Optional#empty()} if {@code choices} is null. + */ + public Optional getChoices() { + return (choices != null) ? Optional.of(choices) : Optional.empty(); + } + + /** + * Sets {@code choices} to this object's {@code choices}. + */ + public void setChoices(Choice[] choices) { + this.choices = choices; + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditFlashcardDescriptor)) { + return false; + } + + // state check + EditFlashcardDescriptor e = (EditFlashcardDescriptor) other; + + return getAnswer().equals(e.getAnswer()) + && getQuestion().equals(e.getQuestion()) + && checkChoiceEquality(getChoices(), e.getChoices()) + && getTags().equals(e.getTags()) + && getDifficulty().equals(e.getDifficulty()); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/quickcache/logic/commands/ExitCommand.java similarity index 73% rename from src/main/java/seedu/address/logic/commands/ExitCommand.java rename to src/main/java/quickcache/logic/commands/ExitCommand.java index 3dd85a8ba90..32477fb34ac 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/quickcache/logic/commands/ExitCommand.java @@ -1,6 +1,6 @@ -package seedu.address.logic.commands; +package quickcache.logic.commands; -import seedu.address.model.Model; +import quickcache.model.Model; /** * Terminates the program. @@ -9,11 +9,11 @@ public class ExitCommand extends Command { public static final String COMMAND_WORD = "exit"; - public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ..."; + public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting QuickCache as requested ..."; @Override public CommandResult execute(Model model) { - return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true); + return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true, false); } } diff --git a/src/main/java/quickcache/logic/commands/ExportCommand.java b/src/main/java/quickcache/logic/commands/ExportCommand.java new file mode 100644 index 00000000000..c153ace96ca --- /dev/null +++ b/src/main/java/quickcache/logic/commands/ExportCommand.java @@ -0,0 +1,88 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.logging.Logger; + +import quickcache.commons.core.LogsCenter; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.QuickCache; +import quickcache.model.flashcard.Flashcard; +import quickcache.storage.JsonQuickCacheStorage; +import quickcache.storage.QuickCacheStorage; + +/** + * Saves the last shown flashcard list into a specified file. + */ +public class ExportCommand extends Command { + + public static final String COMMAND_WORD = "export"; + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Exports the last opened set of flashcards to specified file. " + + "Parameters: FILE_NAME\n" + + "Example: " + COMMAND_WORD + " CS2103_Flashcards.json"; + public static final String MESSAGE_EXPORT_FLASHCARDS_SUCCESS = + "Flashcards exported to: %1$s"; + public static final String MESSAGE_EXPORT_FLASHCARDS_FAILURE = + "Flashcards were unable to be exported to: %1$s"; + private static final Logger logger = LogsCenter.getLogger(ExportCommand.class); + private final Path path; + private final QuickCacheStorage storage; + + /** + * Instantiates an export command. + * + * @param path Path representation of the destination to save last shown flashcard list to. + */ + public ExportCommand(Path path) { + requireNonNull(path); + this.path = path; + this.storage = new JsonQuickCacheStorage(path); + } + + /** + * Instantiates an export command. + * + * @param path Path representation of the destination to save last shown flashcard list to. + * @param storage Storage class to use for saving operations. + */ + public ExportCommand(Path path, QuickCacheStorage storage) { + requireNonNull(path); + this.path = path; + this.storage = storage; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredFlashcardList(); + // Initialize storage at user defined file name + QuickCache lastShownQuickCache = new QuickCache(); + lastShownQuickCache.setFlashcards(lastShownList); + try { + storage.saveQuickCache(lastShownQuickCache); + return new CommandResult(String.format(MESSAGE_EXPORT_FLASHCARDS_SUCCESS, path)); + } catch (IOException ioe) { + logger.info("Error saving into " + path); + throw new CommandException(String.format(MESSAGE_EXPORT_FLASHCARDS_FAILURE, path)); + } + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + ExportCommand that = (ExportCommand) object; + return Objects.equals(path, that.path); + } + +} diff --git a/src/main/java/quickcache/logic/commands/Feedback.java b/src/main/java/quickcache/logic/commands/Feedback.java new file mode 100644 index 00000000000..b75b9eb4d40 --- /dev/null +++ b/src/main/java/quickcache/logic/commands/Feedback.java @@ -0,0 +1,76 @@ +package quickcache.logic.commands; + +import java.util.Objects; +import java.util.Optional; + +import quickcache.model.flashcard.Question; +import quickcache.model.flashcard.Statistics; + +public class Feedback { + + private Boolean isCorrect; + private String body; + private Question question; + private Statistics statistics; + + public Feedback(String body) { + this.body = body; + } + + public Optional getQuestion() { + return Optional.ofNullable(question); + } + + public void setQuestion(Question question) { + this.question = question; + } + + public Optional getStatistics() { + return Optional.ofNullable(statistics); + } + + public void setStatistics(Statistics statistics) { + this.statistics = statistics; + } + + public Optional getBody() { + return Optional.ofNullable(body); + } + + public void setBody(String body) { + this.body = body; + } + + public Optional isCorrect() { + return Optional.ofNullable(isCorrect); + } + + public void setCorrect(Boolean correct) { + isCorrect = correct; + } + + @Override + public String toString() { + return body; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + Feedback otherFeedback = (Feedback) object; + return isCorrect == otherFeedback.isCorrect + && Objects.equals(body, otherFeedback.body) + && Objects.equals(question, otherFeedback.question) + && Objects.equals(statistics, otherFeedback.statistics); + } + + @Override + public int hashCode() { + return Objects.hash(isCorrect, body, question, statistics); + } +} diff --git a/src/main/java/quickcache/logic/commands/FindCommand.java b/src/main/java/quickcache/logic/commands/FindCommand.java new file mode 100644 index 00000000000..79d4d8586eb --- /dev/null +++ b/src/main/java/quickcache/logic/commands/FindCommand.java @@ -0,0 +1,49 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; +import static quickcache.logic.parser.CliSyntax.PREFIX_QUESTION; +import static quickcache.logic.parser.CliSyntax.PREFIX_TAG; + +import quickcache.commons.core.Messages; +import quickcache.model.Model; +import quickcache.model.flashcard.FlashcardPredicate; + +/** + * Finds and lists all flashcards in QuickCache with tags equivalent to any of the argument keywords. + * Keyword matching is case insensitive. + */ +public class FindCommand extends Command { + + public static final String COMMAND_WORD = "find"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all flashcards whose question " + + "and tags respectively contains all of\n" + + "[" + PREFIX_QUESTION + "KEYWORD]...\n" + + "[" + PREFIX_TAG + "TAG]...\n" + + " and displays them as a list with index numbers.\n" + + "Parameters: [" + PREFIX_QUESTION + "KEYWORD]..." + " [" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_QUESTION + "What " + + PREFIX_TAG + "CS2100"; + + private final FlashcardPredicate predicate; + + public FindCommand(FlashcardPredicate predicate) { + this.predicate = predicate; + } + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredFlashcardList(predicate); + return new CommandResult( + String.format(Messages.MESSAGE_FLASHCARDS_LISTED_OVERVIEW, model.getFilteredFlashcardList().size())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof FindCommand // instanceof handles nulls + && predicate.equals(((FindCommand) other).predicate)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/quickcache/logic/commands/HelpCommand.java similarity index 87% rename from src/main/java/seedu/address/logic/commands/HelpCommand.java rename to src/main/java/quickcache/logic/commands/HelpCommand.java index bf824f91bd0..7a17719e762 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/quickcache/logic/commands/HelpCommand.java @@ -1,6 +1,6 @@ -package seedu.address.logic.commands; +package quickcache.logic.commands; -import seedu.address.model.Model; +import quickcache.model.Model; /** * Format full help instructions for every command for display. @@ -16,6 +16,6 @@ public class HelpCommand extends Command { @Override public CommandResult execute(Model model) { - return new CommandResult(SHOWING_HELP_MESSAGE, true, false); + return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false); } } diff --git a/src/main/java/quickcache/logic/commands/ImportCommand.java b/src/main/java/quickcache/logic/commands/ImportCommand.java new file mode 100644 index 00000000000..fac1d15b432 --- /dev/null +++ b/src/main/java/quickcache/logic/commands/ImportCommand.java @@ -0,0 +1,105 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.logging.Logger; + +import quickcache.commons.core.LogsCenter; +import quickcache.commons.exceptions.DataConversionException; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.ReadOnlyQuickCache; +import quickcache.model.flashcard.Flashcard; +import quickcache.storage.JsonQuickCacheStorage; +import quickcache.storage.QuickCacheStorage; + +/** + * Imports the set of flashcards from a specified file. + */ +public class ImportCommand extends Command { + + public static final String COMMAND_WORD = "import"; + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Imports the flashcards from a specified file into your local QuickCache. " + + "Parameters: FILE_NAME\n" + + "Example: " + COMMAND_WORD + " CS2103_Flashcards.json"; + public static final String MESSAGE_IMPORT_FLASHCARD_SUCCESS = + "Flashcards from %1$s has been successfully imported."; + public static final String MESSAGE_IMPORT_FLASHCARD_CORRUPTED_FILE_FAILURE = + "Flashcards from %1$s are corrupted."; + public static final String MESSAGE_IMPORT_FLASHCARD_EMPTY_FILE_FAILURE = + "The file %1$s is empty or does not exist."; + public static final String MESSAGE_IMPORT_FLASHCARD_ERROR_READING_FAILURE = + "There was an error reading the file %1$s."; + private static final Logger logger = LogsCenter.getLogger(ImportCommand.class); + private final Path path; + private final QuickCacheStorage storage; + + /** + * Instantiates an import command. + * + * @param path {@code Path} representation of the destination file to import from. + */ + public ImportCommand(Path path) { + requireNonNull(path); + this.path = path; + this.storage = new JsonQuickCacheStorage(path); + } + + /** + * Instantiates an import command. + * + * @param path {@code Path} representation of the destination file to import from. + * @param storage {@code QuickCacheStorage} to use for saving operations. + */ + public ImportCommand(Path path, QuickCacheStorage storage) { + requireNonNull(path); + this.path = path; + this.storage = storage; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + try { + Optional readBack = storage.readQuickCache(); + if (readBack.isEmpty()) { + throw new CommandException(String.format(MESSAGE_IMPORT_FLASHCARD_EMPTY_FILE_FAILURE, path)); + } + List additionalFlashcards = readBack.get().getFlashcardList(); + additionalFlashcards.forEach((flashcard -> checkAndAddFlashcardToModel(flashcard, model))); + return new CommandResult(String.format(MESSAGE_IMPORT_FLASHCARD_SUCCESS, path)); + } catch (DataConversionException dce) { + logger.info(path + " is corrupted"); + throw new CommandException(String.format(MESSAGE_IMPORT_FLASHCARD_CORRUPTED_FILE_FAILURE, path)); + } catch (IOException ioe) { + logger.info("Unable to read from " + path); + throw new CommandException(String.format(MESSAGE_IMPORT_FLASHCARD_ERROR_READING_FAILURE, path)); + } + } + + private void checkAndAddFlashcardToModel(Flashcard flashcard, Model model) { + if (model.hasFlashcard(flashcard)) { + return; + } + model.addFlashcard(flashcard); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + ImportCommand that = (ImportCommand) object; + return Objects.equals(path, that.path); + } + +} diff --git a/src/main/java/quickcache/logic/commands/ListCommand.java b/src/main/java/quickcache/logic/commands/ListCommand.java new file mode 100644 index 00000000000..059bd8cec3b --- /dev/null +++ b/src/main/java/quickcache/logic/commands/ListCommand.java @@ -0,0 +1,23 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; + +import quickcache.model.Model; + +/** + * Lists all flashcards in QuickCache to the user. + */ +public class ListCommand extends Command { + + public static final String COMMAND_WORD = "list"; + + public static final String MESSAGE_SUCCESS = "Listed all flashcards"; + + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredFlashcardList(Model.PREDICATE_SHOW_ALL_FLASHCARDS); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/quickcache/logic/commands/OpenCommand.java b/src/main/java/quickcache/logic/commands/OpenCommand.java new file mode 100644 index 00000000000..d9673da8cb4 --- /dev/null +++ b/src/main/java/quickcache/logic/commands/OpenCommand.java @@ -0,0 +1,52 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import quickcache.commons.core.Messages; +import quickcache.commons.core.index.Index; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Flashcard; +import quickcache.model.flashcard.Question; + +public class OpenCommand extends Command { + + public static final String COMMAND_WORD = "open"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Opens the flashcard identified by the index number used in the displayed flashcard list.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_OPEN_FLASHCARD_SUCCESS = "Opened Flashcard:\n\n%1$s"; + + private final Index targetIndex; + + public OpenCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredFlashcardList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_FLASHCARD_DISPLAYED_INDEX); + } + + Flashcard flashcardToOpen = lastShownList.get(targetIndex.getZeroBased()); + Question question = flashcardToOpen.getQuestion(); + return new CommandResult(String.format(MESSAGE_OPEN_FLASHCARD_SUCCESS, flashcardToOpen), question, + null, true); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof OpenCommand // instanceof handles nulls + && targetIndex.equals(((OpenCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/quickcache/logic/commands/StatsCommand.java b/src/main/java/quickcache/logic/commands/StatsCommand.java new file mode 100644 index 00000000000..1c643afd65f --- /dev/null +++ b/src/main/java/quickcache/logic/commands/StatsCommand.java @@ -0,0 +1,135 @@ +package quickcache.logic.commands; + +import static java.util.Objects.requireNonNull; +import static quickcache.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import quickcache.commons.core.Messages; +import quickcache.commons.core.index.Index; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Flashcard; +import quickcache.model.flashcard.FlashcardPredicate; +import quickcache.model.flashcard.Question; +import quickcache.model.flashcard.Statistics; +import quickcache.model.flashcard.Tag; + +public class StatsCommand extends Command { + + public static final String COMMAND_WORD = "stats"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Displays the statistics of the flashcard identified by the index number " + + "used in the displayed flashcard list or a set of flashcards identified by their tags.\n" + + "Parameters (either but not both):\n" + + "1. INDEX (must be a positive integer)\n" + + "2. [TAGS]\n" + + "Example: \n" + + "1. " + COMMAND_WORD + " 1\n" + + "2. " + COMMAND_WORD + " " + PREFIX_TAG + "MCQ"; + + public static final String MESSAGE_DISPLAY_STATISTICS_FLASHCARD_SUCCESS = + "Displayed statistics of Flashcard:\n\n%1$s"; + + public static final String MESSAGE_DISPLAY_STATISTICS_FLASHCARDS_BY_TAG_SUCCESS = + "Displayed statistics of Flashcards:\n\n%1$s"; + + private final Index targetIndex; + private final FlashcardPredicate predicate; + private final Set tagsToMatch; + private final boolean isStatsByTag; + + /** + * Instantiates a stats command. + * + * @param targetIndex of the question in the filtered question list to test. + */ + public StatsCommand(Index targetIndex) { + this.targetIndex = targetIndex; + this.predicate = null; + this.tagsToMatch = null; + this.isStatsByTag = false; + } + + /** + * Instantiates a stats command. + * + * @param predicate To filter on model. + * @param tagsToMatch To generate the output message. + */ + public StatsCommand(FlashcardPredicate predicate, Set tagsToMatch) { + this.targetIndex = null; + this.predicate = predicate; + this.tagsToMatch = tagsToMatch; + this.isStatsByTag = true; + } + + private String createStatsWithTagsMessage() { + assert isStatsByTag && tagsToMatch != null; + return tagsToMatch.stream() + .reduce("with tags ", ( + curr, next) -> curr + next.toString() + " ", + String::concat) + .trim(); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + if (isStatsByTag) { + model.updateFilteredFlashcardList(predicate); + List filteredList = model.getFilteredFlashcardList(); + Statistics aggregatedStatistics = getAggregatedStatistics(filteredList); + String statsWithTagsMessage = createStatsWithTagsMessage(); + + // necessary to display all the remaining flashcards in the list + model.updateFilteredFlashcardList(Model.PREDICATE_SHOW_ALL_FLASHCARDS); + + return new CommandResult( + String.format(MESSAGE_DISPLAY_STATISTICS_FLASHCARDS_BY_TAG_SUCCESS, + statsWithTagsMessage), aggregatedStatistics); + } else { + requireNonNull(targetIndex); + List lastShownList = model.getFilteredFlashcardList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_FLASHCARD_DISPLAYED_INDEX); + } + + Flashcard flashcardToDisplayStatistics = lastShownList.get(targetIndex.getZeroBased()); + Question question = flashcardToDisplayStatistics.getQuestion(); + Statistics statistics = flashcardToDisplayStatistics.getStatistics(); + return new CommandResult(String.format(MESSAGE_DISPLAY_STATISTICS_FLASHCARD_SUCCESS, + flashcardToDisplayStatistics), question, statistics); + } + } + + private Statistics getAggregatedStatistics(List filteredList) { + int timesTested = 0; + int timesTestedCorrect = 0; + for (Flashcard flashcard : filteredList) { + timesTested += flashcard.getStatistics().getTimesTested(); + timesTestedCorrect += flashcard.getStatistics().getTimesTestedCorrect(); + } + return new Statistics(timesTested, timesTestedCorrect); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + StatsCommand that = (StatsCommand) object; + return isStatsByTag == that.isStatsByTag + && Objects.equals(targetIndex, that.targetIndex) + && Objects.equals(predicate, that.predicate) + && Objects.equals(tagsToMatch, that.tagsToMatch); + } + +} diff --git a/src/main/java/quickcache/logic/commands/TestCommand.java b/src/main/java/quickcache/logic/commands/TestCommand.java new file mode 100644 index 00000000000..98679aab1af --- /dev/null +++ b/src/main/java/quickcache/logic/commands/TestCommand.java @@ -0,0 +1,193 @@ +package quickcache.logic.commands; + +import static java.util.Objects.nonNull; +import static java.util.Objects.requireNonNull; +import static quickcache.logic.parser.CliSyntax.PREFIX_ANSWER; +import static quickcache.logic.parser.CliSyntax.PREFIX_OPTION; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import quickcache.commons.core.Messages; +import quickcache.commons.core.index.Index; +import quickcache.logic.commands.exceptions.CommandException; +import quickcache.model.Model; +import quickcache.model.flashcard.Answer; +import quickcache.model.flashcard.Flashcard; +import quickcache.model.flashcard.MultipleChoiceQuestion; +import quickcache.model.flashcard.OpenEndedQuestion; +import quickcache.model.flashcard.Option; +import quickcache.model.flashcard.Question; + + +public class TestCommand extends Command { + + public static final String COMMAND_WORD = "test"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Tests the specified question " + + "by the index number used in the displayed question list. " + + "[" + PREFIX_ANSWER + "ANSWER] " + + "[" + PREFIX_OPTION + "OPTION] " + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_ANSWER + "Oxygen " + + PREFIX_OPTION + " 1"; + + + public static final String MESSAGE_FORMAT = "Expected Answer:\n%1$s\n\n" + + "Your Answer:\n%2$s"; + public static final String MESSAGE_NO_OPTION_PROVIDED = "An option must be chosen for " + + "the multiple choice question."; + public static final String MESSAGE_OPTION_INVALID = "Option given must be one of the " + + "options in the multiple choice question"; + public static final String MESSAGE_NO_ANSWER_PROVIDED = "An answer must be chosen for the open ended question."; + public static final String MESSAGE_NO_OPTION_OR_ANSWER_PROVIDED = "An option or answer must be specified."; + private final Index index; + private final TestAnswerDescriptor testAnswerDescriptor; + + /** + * Instantiates a test command. + * + * @param index of the question in the filtered question list to test. + * @param testAnswerDescriptor details to test the question with. + */ + public TestCommand(Index index, TestAnswerDescriptor testAnswerDescriptor) { + requireNonNull(index); + requireNonNull(testAnswerDescriptor); + + this.index = index; + this.testAnswerDescriptor = testAnswerDescriptor; + } + + /** + * Creates a string output of the test result based on whether it is correct. + * + * @param correctAnswer of the question. + * @param userAnswer that is given. + * @return string output of the test result. + */ + private static String getTestResult(Answer correctAnswer, Answer userAnswer) { + return String.format(MESSAGE_FORMAT, correctAnswer, userAnswer); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredFlashcardList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_FLASHCARD_DISPLAYED_INDEX); + } + + Flashcard flashcardToTest = lastShownList.get(index.getZeroBased()); + Question question = flashcardToTest.getQuestion(); + + + if (question instanceof MultipleChoiceQuestion && testAnswerDescriptor.getOption().isEmpty()) { + throw new CommandException(MESSAGE_NO_OPTION_PROVIDED); + } + if (question instanceof OpenEndedQuestion && testAnswerDescriptor.getAnswer().isEmpty()) { + throw new CommandException(MESSAGE_NO_ANSWER_PROVIDED); + } + + Answer answer = null; + + if (question instanceof MultipleChoiceQuestion) { + MultipleChoiceQuestion mcq = (MultipleChoiceQuestion) question; + Option option = testAnswerDescriptor.getOption().get(); + + // Tries to get the answer based on the option's index, throws an error if invalid index + try { + Index index = option.getIndex(); + answer = mcq.getAnswerFromIndex(index); + } catch (IllegalArgumentException | IndexOutOfBoundsException e) { + throw new CommandException(MESSAGE_OPTION_INVALID); + } + + } else if (question instanceof OpenEndedQuestion) { + OpenEndedQuestion openEndedQuestion = (OpenEndedQuestion) question; + answer = testAnswerDescriptor.getAnswer().get(); + } + + requireNonNull(answer); + boolean isCorrect = flashcardToTest.checkAnswer(answer); + + // Initialize an updated flashcard + Flashcard updatedFlashcard; + if (isCorrect) { + updatedFlashcard = flashcardToTest.getFlashcardAfterTestSuccess(); + } else { + updatedFlashcard = flashcardToTest.getFlashcardAfterTestFailure(); + } + + // Updates the flashcardToTest with the new updatedFlashCard (with incremented test count) + assert nonNull(updatedFlashcard); + assert !flashcardToTest.equals(updatedFlashcard); + model.setFlashcard(flashcardToTest, updatedFlashcard); + return new CommandResult(getTestResult( + flashcardToTest.getAnswer(), answer), question, isCorrect, true); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof TestCommand)) { + return false; + } + + // state check + TestCommand e = (TestCommand) other; + return index.equals(e.index) + && testAnswerDescriptor.equals(e.testAnswerDescriptor); + } + + /** + * Stores the details to test the question with. Can be used for both open ended and + * multiple choice questions. + */ + public static class TestAnswerDescriptor { + private Answer answer; + private Option option; + + public TestAnswerDescriptor() { + } + + public Optional getAnswer() { + return Optional.ofNullable(answer); + } + + public void setAnswer(Answer answer) { + this.answer = answer; + } + + public Optional