By: Team CS2103-T14-3      Since: Nov 2019      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

ArchitectureDiagram
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.

The .puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the Using PlantUML guide to learn how to create and edit diagrams.

Main has two classes called Main and MainApp. 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 method where necessary.

Commons represents a collection of classes used by multiple other components. The following class plays an important role at the architecture level:

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

The rest of the App consists of four components.

  • UI: The UI of the App.

  • Logic: The command executor.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

Each of the four components

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component

How the architecture components interact with each other

The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.

ArchitectureSequenceDiagram
Figure 3. Component interactions for delete 1 command

The sections below give more details of each component.

2.2. UI component

UiClassDiagram
Figure 4. Structure of the UI Component

API : Ui.java

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 is specified in MainWindow.fxml

The UI component,

  • Executes user commands using the Logic component.

  • Listens for changes to Model data so that the UI can be updated with the modified data. === Logic component

LogicClassDiagram
Figure 5. Structure of the Logic Component

API : Logic.java

  1. Logic uses the FlashcardListParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a Flashcard).

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeleteSequenceDiagram
Figure 6. Interactions Inside the Logic Component for the delete 1 Command
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.

2.3. Model component

ModelClassDiagram
Figure 7. Structure of the Model Component

API : Model.java

The Model,

  • stores a UserPref object that represents the user’s preferences.

  • stores the Flashcard List data.

  • exposes an unmodifiable ObservableList<Flashcard> 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.

  • also exposes a statistics object to the ui to create the statistic charts .

2.4. Storage component

StorageClassDiagram
Figure 8. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the Flashcard data in json format and read it back.

2.5. Common classes

Classes used by multiple components are in the seedu.flashcard.commons package.

3. Implementation

This section describes some noteworthy details on how certain features are implemented.

3.1. Quiz and Flip feature

In the flashcard system, quiz and flip is a special function that can help the user quiz themselves on the flashcards and see there own improvements. The flip command, which is answering the quizzed flashcard, can only be used when a current flashcard is being quizzed. The following sequence diagram shows how the quiz and flip diagram works.

QuizSequenceDiagram
Figure 9. Component interactions for quiz command on a single flashcard

3.2. Stats feature

After a series of quizzes, each flashcard can automatically record how many correct answers and wrong answers has the user did on this flashcard. The stats command helps the user to see their progress while doing the quizzes. Below is a sequence diagram of how this command works.

StatsSequenceDiagram
Figure 10. Component interactions for stats command

3.3. Quiz Tag feature

Alternatively, users can choose to quiz a series of tags instead of a single card. A list of flashcards will then be added to the list of quizable cards, which also triggers quiz mode, allowing users to use the flip command to answer flashcards consecutively. The following sequence diagram shows how the quiztag command works:

QuizTagSequenceDiagram
Figure 11. Component interactions for any quiztag command

Calling a quiztag command triggers the quiz mode, which is stored as a boolean in the FlashcardListParser. This is done with the consideration that there are different functions that can start the quiz mode (i.e quiz, quiztag), and others that can end the quiz mode (i.e flip, end, exit).

During quiz mode, the flip command can be called consecutively for as long as there are flashcards left in the quiz, as shown below:

FlipSequenceDiagram
Figure 12. Flip command running and interact with the parser to toggle quiz mode

The flip command interacts with the model to check if there are any quizable flashcards. If there are none, the flip command toggles the quiz mode in FlashcardListParser off.

3.4. Undo/Redo feature

3.4.1. Implementation

The undo/redo mechanism is facilitated by VersionedFlashcardList. It extends FlashcardList with an undo/redo history, stored internally as an flashcardListStateList and currentStatePointer. Additionally, it implements the following operations:

  • VersionedFlashcardList#commit() — Saves the current flashcard list state in its history.

  • VersionedFlashcardList#undo() — Restores the previous flashcard list state from its history.

  • VersionedFlashcardList#redo() — Restores a previously undone flashcard list state from its history.

These operations are exposed in the Model interface as Model#commitFlashcardList(), Model#undoFlashcardList() and Model#redoFlashcardList() respectively.

Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.

Step 1. The user launches the application for the first time. The VersionedFlashcardList will be initialized with the initial flashcard list state, and the currentStatePointer pointing to that single flashcard list state.

UndoRedoState0

Step 2. The user executes delete 5 command to delete the 5th Flashcard in the flashcard list. The delete command calls Model#commitFlashcardList(), causing the modified state of the flashcard list after the delete 5 command executes to be saved in the flashcardListStateList, and the currentStatePointer is shifted to the newly inserted flashcard list state.

UndoRedoState1

Step 3. The user executes add q/What is a machine …​ to add a new Flashcard. The add command also calls Model#commitFlashcardList(), causing another modified flashcard list state to be saved into the flashcardListStateList.

UndoRedoState2
If a command fails its execution, it will not call Model#commitFlashcardList(), so the flashcard list state will not be saved into the flashcardListStateList.

Step 4. The user now decides that adding the flashcard was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoFlashcardList(), which will shift the currentStatePointer once to the left, pointing it to the previous flashcard list state, and restores the flashcard list to that state.

UndoRedoState3
If the currentStatePointer is at index 0, pointing to the initial flashcard list state, then there are no previous flashcard list states to restore. The undo command uses Model#canUndoFlashcardList() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.

The following sequence diagram shows how the undo operation works:

UndoSequenceDiagram
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.

The redo command does the opposite — it calls Model#redoFlashcardList(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores the flashcard list to that state.

If the currentStatePointer is at index flashcardListStateList.size() - 1, pointing to the latest flashcard list state, then there are no undone flashcard list states to restore. The redo command uses Model#canRedoFlashcardList() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.

Step 5. The user then decides to execute the command list. Commands that do not modify the flashcard list, such as list, will usually not call Model#commitFlashcardList(), Model#undoFlashcardList() or Model#redoFlashcardList(). Thus, the flashcardListStateList remains unchanged.

UndoRedoState4

The following activity diagram summarizes what happens when a user executes a new command:

CommitActivityDiagram

3.4.2. Design Considerations

Aspect: How undo & redo executes
  • Alternative 1 (current choice): Saves the entire flashcard list.

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage.

  • Alternative 2: Individual command knows how to undo/redo by itself.

    • Pros: Will use less memory (e.g. for delete, just save the flashcard being deleted).

    • Cons: We must ensure that the implementation of each individual command are correct. There will be a lot coding involved and a higher chance of regression bugs.

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (current choice): Use a list to store the history of flashcard list states.

    • Pros: It has a very clear structure and is therefore easy for future developers to update.

    • Cons: It might be difficult to navigate between different elements in the list. However, that’s not really a big issue as we only need to move to neighbouring states each time.

  • Alternative 2: Use HistoryManager for undo/redo

    • Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.

    • Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as HistoryManager now needs to do two different things.

Aspect: Quiz Mode
  • Alternative 1 (current choice): A static boolean is stored in the FlashcardListParser to indicate whether the application is currently in quiz mode. Being in quiz mode allows access to some commands and disables others.

    • Pros: It is easy to toggle Quiz mode on and off from the various commands as it is a static boolean and can be accessed easily.

    • Cons: It violates the Single Responsibility Principle as the parser now stores information vital to the logic of the application, besides parsing arguments.

  • Alternative 2: Store the Quiz mode boolean inside Logic Manager.

    • Pros: It adheres better to software engineering principles as variables affect the logic of the programme should be stored in the logic manager.

    • Cons: As Quiz mode heavily affects the parsing of the commands, the boolean has to be passed to and fro several layers, making it harder for commands to toggle quiz mode on and off.

3.5. Logging

We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 3.6, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

3.6. Configuration

Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json).

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • needs to memorize a large amount of discrete knowledge like vocabulary

  • want to check his/her progress over a period of time

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition: manage short knowledge like vocabulary faster than a typical mouse/GUI driven app

Appendix B: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

new user

see usage instructions

refer to instructions when I forget how to use the App

* * *

user

add a new flashcard

* * *

user

delete a flashcard

remove flashcards that I have already firmly memorized

* * *

user

find a flashcard by keywords in its question or answer

locate details of flashcards without having to go through the entire list

* * *

user

tag the flashcards

group them based on their fields

* * *

user

start a quiz

train myself on the flashcards

* * *

user

see my statistics over time

I know what parts I need to train more, what parts I am weak at

* *

user

edit a flashcard

do adjustment on the cards instead of typing the question and answer all over again

* *

user

import flashcards from other documents

add a lot of questions into the system without typing them one by one

* *

user

set time limit to each flashcard

* *

user

set up a deadline to train on each set of flashcards

*

user with many flashcards in the flashcard list

sort flashcards by name

locate a flashcard easily

*

user

automatically judge my answer to my short answer question

I can know how well I am doing

*

user

automatically decide duplicate flashcard

I will add same flashcard into the system multiple times

Appendix C: Use Cases

(For all use cases below, the System is the FlashcardList and the Actor is the user, unless specified otherwise)

Use case: UC01 - View all the flashcards

Actor: User

MSS

  1. User requests to view all existing flashcards by using correct command line input.

  2. FlashMind shows a list of all existing flashcards.

    Use case ends.

Extensions

  • 1a. The flashcard list is empty.

    Use case ends.

Use case: UC02 - Delete a flashcard

Actor: User

MSS

  1. User views all flashcards (UC01).

  2. User locates the correct index of the flashcard he/she wants.

  3. User request to delete the flashcard with the specific index number.

  4. FlashMind deletes the flashcard.

    Use case ends.

Extensions

  • 2a. The given index is invalid.

    • 2a1. FlashMind shows an error message.

      Use case resumes at step 2.

Use case: UC03 - Tag a flashcard

Actor: User

MSS

  1. User views all existing flashcards (UC01).

  2. User identifies the index of the particular flashcard that he/she wants to tag.

  3. User tags the flashcard with provided tag names.

  4. FlashMind creates new tags with the given tag names and put the flashcard under these tags.

    Use case ends.

Extensions

  • 2a. The given tag already exist, but the target flashcard is not under this tag yet.

    • 2a1. FlashMind puts the given flashcard under the existing tag instead of creating a new tag.

      Use case ends.

  • 2b. The target flashcard is already under the given tag.

    • 2b1. FlashMind shows an error message.

      Use case ends.

  • 2c. The input flashcard index number is invalid.

    • 2c1. FlashMind shows an error message.

      Use case ends.

Use case: UC04 - edit a flashcard

Actor: User

MSS

  1. User views all existing flashcards (UC01).

  2. User identifies the index of the particular flashcard that he/she wants to edit.

  3. User request to edit the question, tag or answer of a flashcard.

  4. FlashMind updates the question, tag or answer on the specific flashcard.

Extensions

  • 2a. The requested question or answer is in wrong format

    • 2a1. FlashMind shows an error message including the constraints of the question and answer.

      Use case ends.

  • 2b. The input flashcard index number is invalid

    • 2b1. FlashMind shows an error message.

      Use case ends.

Use case: UC05 - find all flashcards with particular tags

Actor: User

MSS

  1. User request to list all the flashcard sets with the same tags by inputting these tags.

  2. FlashMind shows a list of all current flashcards with the provided tags.

  • 2a. The tag is empty or does not exist.

    • 2a1. System displays an error message. user case ends.

Use case: UC06 - delete a tag

Actor: User

MSS

  1. User requests to delete a particular tag by inputting the name of that tag.

  2. FlashMind deletes the tag from all flashcards with this tag and delete it from the tag list. Also, all flashcards with that tag are not removed.

Extensions

  • 4a. The tag user wants to delete does not exist.

    • 4a1. FlashMind shows an error message.

      Use case ends.

Use case: UC07 - Start a quiz on a flashcard

Actor: User

Precondition: The tag exists in the database

MSS

  1. User views all existing flashcards (UC01).

  2. User starts a quiz on a particular flashcard by providing its index.

  3. FlashMind displays the question on that flashcard.

  4. User carries out the quiz by providing an answer to that question.

  5. FlashMind displays result.

  6. User confirms the result.

  7. Quiz ends.

Use case ends

Extensions

  • 3a. User does not give an answer

    • 3a1. FlashMind waits for 15 seconds

    • 3a2. User still has no answer

    • Flashcard will be skipped or marked as wrong.

  • *a. At any time, User decides to end the quiz

    • *a1. FlashMind requests to confirm the cancellation.

    • *a2. User confirms the cancellation.

    • use case ends

Use case: UC08 - Start a quiz on a set of flashcards with the same tag

Actor: User

Precondition: The tag exists in the database

MSS

  1. User views all existing flashcards (UC01).

  2. User identifies a particular tag that he/she wants to quiz on.

  3. User starts a quiz on that tag by providing the tag name.

  4. FlashMind shows the question of the first flashcard.

  5. User answers the question by providing a response.

  6. FlashMind displays result.

  7. User confirms the result.

    • steps 2-5 are repeated until all the flashcard in the tag have been quizzed.

  8. Quiz ends.

Use case ends

Extensions

  • 3a. User does not give an answer

    • 3a1. FlashMind waits for 15 seconds.

    • 3a2. User still has no answer

    • Use case resumes from step 4 (flashcard is skipped or marked as wrong)

  • *a. At any time, User decides to quit the quiz

    • *a1. FlashMind requests to confirm the cancellation.

    • *a2. User confirms the cancellation.

    • use case ends

Use case: UC09 - Undo/redo a flashcard list change

Actor: User

Precondition: There is an actual change that happened to the flashcard list.

MSS

  1. User inputs either undo or redo command to get back the previous or previous undone state of flashcard list.

  2. FlashMind displays the undone/redone flashcard card list to the user.

Use case ends

Extensions

  • 1a. There is no undoable/redoable state available

    • 1a1. FlashMind displays error message.

Use case: UC10 - View all the available commands

Actor: User

MSS

  1. User enters help to ask FlashMind for all the commands.

  2. System responds by providing all the available commands.

    Use case ends.

Use case: UC11 - View the statistics of flashcards

Actor: User

MSS

  1. User enters stats to ask FlashMind to show stats of all cards

  2. System displays the statistics of the selected flashcards in a new window

    Use case ends.

Extensions

  • 1a. User enters stats [t/Tag] to ask FlashMind to show stats of cards under specified tags.

    Use case resumes at step 2.

  • 2a. The tag is empty or does not exist.

    • 2a1. System displays an error message.

      use case ends.

Appendix D: 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.

  4. If the stored flashcard list is very long, all commands should still be executed at a fast speed, with minimal sluggishness.

  5. Should be able to minimize loss of stored flashcard information if the app closes due to unforeseen external circumstances.

  6. Command format should be easily understandable and intuitive to make it easier then using a GUI interface

Appendix E: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Flashcard

A digital card that contains a short piece of information like an English word or a geography common knowledge. Normally used by people to facilitate the memorization process.

Appendix F: Instructions for Manual Testing

Given below are instructions to test the app manually.

These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.

F.1. Launch and Shutdown

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file
      Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the app by double-clicking the jar file.
      Expected: The most recent window size and location is retained.

F.2. Deleting a flashcard

  1. Deleting a flashcard while all flashcards (in a tagged set/in the all-flashcard list) are listed

    1. Prerequisites: List all flashcards using the list command. Multiple flashcards in the list.

    2. Test case: delete 1
      Expected: First flashcard with ID 1 is deleted from the list.

    3. Test case: delete 0
      Expected: No flashcard is deleted. Error details shown in the status message.

    4. Other incorrect delete commands to try: delete, delete x (where x is larger than the list size or ID number is negative) Expected: Similar to previous.

F.3. Saving data

  1. Dealing with missing/corrupted data files

    1. Manually make a Json file with invalid fields and see if FlashMind can identify these issues or not.