By: Team CS2103-T14-3
Since: Nov 2019
Licence: MIT
1. Setting up
Refer to the guide here.
2. Design
2.1. Architecture
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.
|
-
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.
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.
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
.
delete 1
commandThe sections below give more details of each component.
2.2. 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
API :
Logic.java
-
Logic
uses theFlashcardListParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding a Flashcard). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
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.
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
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
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.
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.
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:
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:
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.
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.
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
.
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.
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:
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.
The following activity diagram summarizes what happens when a user executes a new command:
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 usingLogsCenter.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
-
User requests to view all existing flashcards by using correct command line input.
-
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
-
User views all flashcards (UC01).
-
User locates the correct index of the flashcard he/she wants.
-
User request to delete the flashcard with the specific index number.
-
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
-
User views all existing flashcards (UC01).
-
User identifies the index of the particular flashcard that he/she wants to tag.
-
User tags the flashcard with provided tag names.
-
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
-
User views all existing flashcards (UC01).
-
User identifies the index of the particular flashcard that he/she wants to edit.
-
User request to edit the question, tag or answer of a flashcard.
-
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
-
User request to list all the flashcard sets with the same tags by inputting these tags.
-
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
-
User requests to delete a particular tag by inputting the name of that tag.
-
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
-
User views all existing flashcards (UC01).
-
User starts a quiz on a particular flashcard by providing its index.
-
FlashMind displays the question on that flashcard.
-
User carries out the quiz by providing an answer to that question.
-
FlashMind displays result.
-
User confirms the result.
-
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
-
User views all existing flashcards (UC01).
-
User identifies a particular tag that he/she wants to quiz on.
-
User starts a quiz on that tag by providing the tag name.
-
FlashMind shows the question of the first flashcard.
-
User answers the question by providing a response.
-
FlashMind displays result.
-
User confirms the result.
-
steps 2-5 are repeated until all the flashcard in the tag have been quizzed.
-
-
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
-
User inputs either undo or redo command to get back the previous or previous undone state of flashcard list.
-
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
-
User enters
help
to ask FlashMind for all the commands. -
System responds by providing all the available commands.
Use case ends.
Use case: UC11 - View the statistics of flashcards
Actor: User
MSS
-
User enters
stats
to ask FlashMind to show stats of all cards -
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
-
Should work on any mainstream OS as long as it has Java
11
or above installed. -
Should be able to hold up to 1000 flashcards without a noticeable sluggishness in performance for typical usage.
-
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.
-
If the stored flashcard list is very long, all commands should still be executed at a fast speed, with minimal sluggishness.
-
Should be able to minimize loss of stored flashcard information if the app closes due to unforeseen external circumstances.
-
Command format should be easily understandable and intuitive to make it easier then using a GUI interface
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
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
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
-
Deleting a flashcard while all flashcards (in a tagged set/in the all-flashcard list) are listed
-
Prerequisites: List all flashcards using the
list
command. Multiple flashcards in the list. -
Test case:
delete 1
Expected: First flashcard with ID 1 is deleted from the list. -
Test case:
delete 0
Expected: No flashcard is deleted. Error details shown in the status message. -
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
-
Dealing with missing/corrupted data files
-
Manually make a Json file with invalid fields and see if FlashMind can identify these issues or not.
-