Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
-
Appendix: Requirements
- Product scope
- User stories
-
Use cases
- Use case: UC1 - Add a deck
- Use case: UC2 - Delete a deck
- Use case: UC3 - Edit a deck name
- Use case: UC4 - Select a deck
- Use case: UC5 - Find deck(s) with keyword(s)
- Use case: UC6 - Show all decks
- Use case: UC7 - Add a card
- Use case: UC8 - Delete a card
- Use case: UC9 - Edit a card
- Use case: UC10 - Find card(s) by keyword(s)
- Use case: UC11 - Show all cards
- Use case: UC12 - Review a deck
- Non-Functional Requirements
- Glossary
- Appendix: Instructions for manual testing
- Appendix: Effort
- Appendix: Planned Enhancement
Acknowledgements
- Our application is based on the AB3 project created by the SE-EDU initiative
- Our application makes use of JavaFX as the UI framework.
- Our application’s white and blue color scheme takes inspiration from the color scheme of Apple’s iMessage.
- Our application’s three modes design:
MAIN_UNSELECTED_MODE,MAIN_SELECTED_MODE,REVIEW_MODEwas inspired by a similar design of the past project FlashNotes (UG, DG), although our implementation is entirely new.
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture

The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
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 methods where necessary.
Commons represents a collection of classes used by multiple other components.
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.
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 deleteCard 1.

Each of the four main components (also shown in the diagram above),
- defines its API in an
interfacewith the same name as the Component. - implements its functionality using a concrete
{Component Name}Managerclass (which follows the corresponding APIinterfacementioned in the previous point.
For example, the Logic component defines its API in the Logic.java interface and implements its functionality using the LogicManager.java class which follows the Logic interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.

The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java

The UI consists of a MainWindow that can be summarised into 4 parts, Card, Deck, ReviewStats and Utility components.Card displays all card related information, Deck components displays all deck related information, ReviewStats displays the stats recorded during a Review session, and Utility are UI components that display other important non PowerCards related information. Components with suffix Panel act as containers for element classes that act as individual objects created by Model.
Some components are mutually exclusive. During a review session, only the ReviewStats components will be displayed and Deck components hidden. During the review, only one of FlippedReviewElement or UnflippedReviewElement will be displayed at a time.
All these, including the MainWindow, inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI. Due to the large number of components, we have left out the UiPart section as it is redundant to link them all to it.
The UI component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml
- executes user commands using the
Logiccomponent. - listens for changes to
Modeldata so that the UI can be updated with the modified data. - keeps a reference to the
Logiccomponent, because theUIrelies on theLogicto execute commands. - depends on some classes in the
Modelcomponent, as it displaysCardobject residing in theModel.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic component:

How the Logic component works:
- When
Logicis called upon to execute a command, it checks the current mode of the application (MAIN_UNSELECTED,MAIN_SELECTED,REVIEW) to determine which method withinMasterDeckParserto call next. - It then calls the appropriate parsing method within the
MasterDeckParserclass to parse the user command. - This results in a
Commandobject (more precisely, an object of one of its subclasses e.g.,AddCardCommand) which is executed by theLogicManager. - The command can communicate with the
Modelwhen it is executed (e.g. to add a card). - The result of the command execution is encapsulated as a
CommandResultobject which is returned back fromLogic.
The Sequence Diagram below illustrates the interactions within the Logic component for the execute("deleteCard 1") API call.

DeleteCardCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in Logic (omitted from the class diagram above) that are used for parsing a user command:

How the parsing works:
- When called upon to parse a user command, the
MasterDeckParserclass parse the command differently based on the current mode (MAIN_UNSELECTED,MAIN_SELECTED,REVIEW) of the application and creates anXYZCommandParser(XYZis a placeholder for the specific command name e.g.,AddCardCommandParser) which uses the other classes shown above to parse the user command and create aXYZCommandobject (e.g.,AddCardCommand) which theMasterDeckParserreturns back as aCommandobject. - All
XYZCommandParserclasses (e.g.,AddCardCommandParser,DeleteCardCommandParser, …) inherit from theParserinterface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java

The Model component,
- stores the MasterDeck data i.e., all
Cardobjects (which are contained in aUniqueCardListobject) and allDeckobjects (which are contained in aUniqueDeckListobject). - stores the currently ‘selected’
Cardobjects (e.g., results of selecting a deck) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Card>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 currently ‘selected’
Deckobjects (e.g., results of a deck search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Deck>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 a
UserPrefobject that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPrefobjects. - stores an optional
Reviewobject, which handles the cards being reviewed by the user. Refer below for more details. - does not depend on any of the other three components (as the
Modelrepresents data entities of the domain, they should make sense on their own without depending on other components)
Each Card object,
- stores one
Question, oneAnswer, oneDeckwhich theCardobject references from theDecklist, and one TagNameTag(cards initialized without tags will have an untagged tag). - belongs to the
Deckit references.
Review

The Review
- stores a
Deckcurrently being reviewed. - stores a
UniqueCardListinstance which stores all theCardinstances belonging to theDeckbeing reviewed. - stores the ‘current’
Cardobject (the current card being displayed in the review) in a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Card>that can be ‘observed’.- The UI can be bound to this list so that the UI automatically updates when the
Cardin the list changes. - The list is always filtered to contain one
Cardat any time.
- The UI can be bound to this list so that the UI automatically updates when the
Storage component
API : Storage.java

The Storage component,
- can save both MasterDeck data and user preference data in json format, and read them back into corresponding objects.
- inherits from both
MasterDeckStorageandUserPrefStorage, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Modelcomponent (because theStoragecomponent’s job is to save/retrieve objects that belong to theModel)
Common classes
Classes used by multiple components are in the seedu.powercards.commons package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Implementation of MasterDeck
The MasterDeck class stores all the Deck and Card data the users will interact with.
Below are the current implementation we chose for MasterDeck and the possible alternative designs that we will explore in the future.
Current Implementation

MasterDeck stores 2 independent lists, a UniqueCardList storing all existing unique cards and a UniqueDeckList storing all existing unique decks.
Each Card instance references an existing instance of Deck. This reference denotes that the card belongs to a specific deck.
Why we chose this design:
- Ease of implementation: The deck behaves similarly to a tag whose purpose is to group the cards together. This allows us to take reference from the source code of the
Tagclass from the AddressBook3 (AB3). - Single Responsibility Principle: The
UniqueDeckListclass’s sole responsibility is to store and modify the user-created decks. If we store aUniqueCardListinside each deck (similar to the alternative design below), theUniqueDeckListhas to be responsible for managing the cards inside each deck as well. This can potentially violate Single Responsibility Principle (SRP).
Limitation:
- Worse time complexity: Some commands (e.g.,
selectDeck) require the whole card list to be filtered to show only the cards in a specific deck. This incurs a worse runtime complexity, as performance degrades when the size of the card list grows.
Alternative Designs
A more intuitive design for MasterDeck is given below.

- The
MasterDeckhas aUniqueDeckListwhich stores unique instances of decks. - Each deck in turn stores a reference to a
UniqueCardList. - Each
UniqueCardListstores a list of unique instances of cards inside a specific deck.
Pros:
- This design follows Object-Oriented Programming (OOP) more closely, as a deck is supposed to contain a list of cards in the real world.
- Time complexity is improved for some commands (e.g.,
selectDeckretrieves cards from a deck much faster, as it does not require filtering every single existing card like our current implementation).
Cons:
- Requires a complete overhaul of the code base and test cases, which may not be practical considering our limited development time.
While the alternative design seems more appropriate than our current design, we deem it less feasible to implement due to our project’s time constraint. Furthermore, the performance difference is negligible as our average user does not have enough cards to cause noticeable performance degradation. Nevertheless, we intend to prioritize the implementation of the alternative design in future iterations, as time and resources permit.
Command Validity Based on Application Mode
The activity diagram below illustrates what happens when a user enters a command.

Our application has three modes: MAIN_UNSELECTED_MODE, MAIN_SELECTED_MODE, and REVIEW_MODE, each with its own set of exclusive commands.
To enforce this, the LogicManager class checks the current mode of the user and enables/disables certain commands as necessary.
-
When the user is in
MAIN_UNSELECTED_MODE:- This mode primarily handles deck-related commands, such as
AddDeckCommandandFindDecksCommand. - No deck is selected in this mode, so card-related and review-related commands are disabled.
- This mode primarily handles deck-related commands, such as
-
When the user is in
MAIN_SELECTED_MODE:- This mode primarily handles card-related commands, such as
AddCardCommandandFindCardsCommand. - A deck is selected in this mode, so deck-related commands are disabled.
- Review-related commands are also disabled, as there is no ongoing review.
- This mode primarily handles card-related commands, such as
-
When the user is in
REVIEW_MODE:- This mode primarily handles review-related commands, such as
FlipCardCommandandNextCardCommand. - A review is ongoing in this mode, so deck-related and card-related commands are disabled.
- This mode primarily handles review-related commands, such as
Implementation of MAIN_UNSELECTED_MODE Features
MAIN_UNSELECT_MODE is the mode of the application when the users have not selected a deck, and they are not reviewing any decks.
Most commands in the MAIN_UNSELECTED_MODE behaves similarly as the example of addDeck command below:
addDeck Feature
Given below is an example usage scenario and how the addDeck() mechanism behaves at each step.
Step 1. The user executes addDeck Math command to add a new deck. The addDeck command calls Model#addDeck(), which executes adding a new deck feature.
Step 2. A new deck is now added on the list and able to execute further functionalities.
Note:
- In case of a duplicate deck name, an exception will be thrown and the newly created deck will not be saved in the
MasterDeck. - However, note that deck names are case-sensitive. For example, user cannot create two “Math” decks, but are allowed to create a “Math” deck and a “math” deck.
The following activity diagram summarizes what happens when a user executes addDeck command:

The following sequence diagram shows how the addDeck operation works:

Implementation of MAIN_SELECTED_MODE Features
‘MAIN_SELECTED_MODE’ is the mode of the application when the users have selected a deck, and they are not reviewing any decks.
Commands in the MAIN_SELECTED_MODE behave similarly as the example of deleteCard below:
deleteCard Feature
The deleteCard INDEX feature allows users to delete specific card from their selected deck.
Given below is an example usage scenario and how the deleteCard() mechanism behaves at each step.
Step 1. The user has a deck selected and keys in deleteCard INDEX to delete card at the specified index. If the index is invalid, an error will be thrown.
Step 2. The card is now deleted from the deck.
The following activity diagram summarizes the action taken when deleteCard is executed:

Implementation of REVIEW_MODE Features
A user can enter into the REVIEW_MODE to test their knowledge on a deck of cards and optionally filter that deck by the tags of the cards.
The following activity diagram is a summary of the typical review workflow a user might carry out:

REVIEW_MODE Implementation Details
A Review object is stored within the Model and represents the current review.
- If the current review object is
null, it indicates that there is currently no ongoing review, thus the application is in theMAIN_MODE. - To construct a
Reviewobject, theModelwill pass in:- a list of cards to be reviewed (as filtered by
CardInDeckPredicateandCardHasTagPredicate), - the
Deckto be reviewed and - an integer representing the review limit set by user (-1 if no limit set).
- a list of cards to be reviewed (as filtered by
Within the Review object, the list of cards to be reviewed are stored in a UniqueCardList.
- Note that this list of cards are not the same card objects as those in the
MasterDeckand hence any changes to be made on a card during review will need to be made on the equivalent cards in both theMasterDeckand the current review’sUniqueCardList. - The
UniqueCardListis used to construct theObservableListandFilteredListof cards which is passed upwards to the UI to display the current card under review.
Each time a Review object is constructed, a list of integers representing a shuffled order of indices of the cards is created.
- A pointer representing the current card index is used to iterate across this list of shuffled indices to get the current
Cardunder review from theUniqueCardList. - The pointer is incremented when the user moves on to the next card and decremented when the user moves back to the previous card
Within the Review object, there is an ObservableList of a Pair of strings representing the following statistics of the current review: deck name, current card number, current tag count for each difficulty and the navigation guide.
- The statistics are displayed on the left panel during the review mode.
- In a
Pairof strings, the first string represents the title of the statistic while the second contains information about that respective statistic. (e.g. String 1: “Deck Name”, String 2: “Chemistry”) - These statistics are constantly updated whenever a command executed (e.g. tag current card with new difficulty) changes any of the above statistics of the review.
The following is a sequence diagram shows a review is started:

Notice that the UI calls the methods getReviewStatsList() and getReviewCardList() in Logic to return an ObservableList of the review statistics and current card respectively.
Any changes made to these ObservableLists during the review will be listened to and updated visually on the UI.
nextCard Feature
Review#goToNextCard() is the operation that allows the user to move to the next card during a review.
This operation is exposed in the Model interface as Model#goToNextCard().
Given below is an example usage scenario and how the goToNextCard() mechanism behaves at each step.
Step 1. The user starts a review. A Review object is created within the Model class. The current mode of the application is changed to REVIEW_MODE.
Step 2. The user reviews the first card by testing their knowledge on the question, flipping the card to see the answer, then tagging the appropriate difficulty of the card.
Step 3. The user moves on to the next card by executing ] in the command line interface. ] is the command word for the NextCardCommand.
The following activity diagram summarizes what happens when a user executes NextCard command:

Tag Cards During The Review Feature
Users are allowed to tag the cards in the review session with 3 different difficulty tags (e.g., Easy, Medium and Hard). The tags will be saved and displayed on each card even after they end the review.
There are three commands that allow a card to be tagged during a review. They are TagEasyCommand, TagMediumCommand and TagHardCommand.
Below is the sequence diagram that shows how TagEasyCommand behaves when it is executed. The remaining two commands behave similarly.

Take note:
- The
Reviewholds a separateUniqueCardListstoring all the cards in the review. These cards are independent of the cards stored in theUniqueCardListinsideMasterDeck. - Hence, tagging the card in one list will not modify the same card in the other list.
- Consequently, both cards must be tagged independently in
MasterDeckandReview. - Tagging the card in
Reviewis sufficient for changes to appear in UI.
Implementation of UI
The UI consists of the DeckPanel on the left and the CardPanel on the right, along with CommandBox and ResultDisplayon the bottom. CommandBox and ResultDisplay are in fixed positions and do not get shifted around or removed in any use case.
DeckPanel and CardPanel display modifiable DeckElement and CardElement objects that are stored as Javafx ObservableList<> elements. When these objects are added, deleted, or edited by the user, the changes are reflected immediately in the UI.
Initially, when the user launches Powercards, DeckPanel will display all DeckElement objects and CardPanel displays all CardElement objects. They can be modified through commands such as findDecks,findCards, editCard, etc.
When the user starts a review, the left DeckPanel is replaced with a ReviewStatsPanel to display the relevant information generated during the review. The CardElement objects on the right CardPanel are replaced with a single CardElement object from the selected deck to review.
The flip command (p) will toggle between the corresponding FlippedReviewElement and UnflippedReviewElement of the single displayed CardElement.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- Needs to study a group of terms and definitions efficiently
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition: study various topics using cards on the computer
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 |
Epic |
user | manage cards | |
* * * |
user | create a new card with a question and answer pair | |
* * |
user | search for cards using keywords in the questions | |
* * |
user | rewrite the question or the answer in the card | |
Epic |
user | group cards into decks of the same topic | |
* * * |
user | set the name of a deck | |
* * * |
user | list all decks I have created | |
* * * |
user | list all the cards in a deck | |
* * * |
user | add cards in a deck | |
* * * |
user | remove cards in a deck | |
* * |
user | rename a deck | |
* * |
user | delete a deck | |
* * |
user | add the description of each deck | I can check later what this deck is about. |
Epic |
user | review decks of cards | |
* * * |
user | review a single deck of cards | I can test my knowledge of the topic |
* * * |
user | mark a card to be correct / wrong during review | |
* * |
user | see how many cards I have left to review in one deck | |
Epic |
user | keep track of how effective my learning has been | |
* * |
user | see which are the cards I struggle with / succeed at | |
* |
user | see which topics (decks) I am stronger / weaker in | |
* |
user | revise cards that I got wrong for | I can see what I’m weak at |
* * |
user | reset the statistics | |
Epic |
user | share and receive decks from my friends | |
* * * |
user | import decks from other users. | |
* * * |
user | export decks for other users. | |
Epic |
user | undo and redo changes I make | |
* |
user | retrieve a deck or card should I accidentally delete it | |
* |
user | redo changes that I had undone. | |
Epic |
user | adjust the frequency of certain cards appearing based on my input | |
* * |
user | tag cards that are hard | they will appear more frequently |
* * |
user | tag cards that are easy | they will appear less frequently |
Use cases
For all use cases below, the System is the Powercards application and the Actor is the user, unless specified otherwise.
Use case: UC1 - Add a deck
MSS:
- User requests to create a new deck with a specified name.
-
System creates a new deck with the given name.
Use case ends.
Use case: UC2 - Delete a deck
MSS:
- User requests to delete an existing deck with a specified name.
-
System deletes the existing deck with the given name.
Use case ends.
Use case: UC3 - Edit a deck name
MSS:
- User requests to edit an existing deck to have a new name.
-
System edits the existing deck to have the new name.
Use case ends.
Use case: UC4 - Select a deck
MSS:
- User selects a deck manage cards within.
-
System enters the chosen deck and shows cards in that deck.
Use case ends.
Use case: UC5 - Find deck(s) with keyword(s)
MSS:
- User requests to find decks with names containing keyword(s).
-
System shows deck(s) containing any of the given keyword(s).
Use case ends.
Use case: UC6 - Show all decks
MSS:
- User requests to see all decks after running
findDeckscommand. -
System shows all decks.
Use case ends.
Use case: UC7 - Add a card
MSS:
- User selects a deck (UC2) to add card to.
- User enters the question and answer details for the card.
-
System adds the card to the chosen deck.
Steps 3-4 are repeated for as many times as required until the User finishes adding more cards to the deck.
Use case ends.
Use case: UC8 - Delete a card
MSS:
- User selects a deck (UC2) to delete card from.
- User requests to delete a specific card in the deck.
- System deletes the card.
Use case ends.
Use case: UC9 - Edit a card
MSS:
- User selects a deck (UC2) to edit a card within.
- User enters the card field(s) they wish to edit - question, answer or tag details.
-
System updates the card with the new given fields.
Steps 3-4 are repeated for as many times as required until the User finishes editing more cards to the deck.
Use case ends.
Use case: UC10 - Find card(s) by keyword(s)
MSS:
- User requests to find cards with questions containing keyword(s).
-
System shows card(s) containing any of the given keyword(s).
Use case ends.
Use case: UC11 - Show all cards
MSS:
- User requests to see all cards in selected deck after running
findCardscommand. -
System shows all cards in selected deck.
Use case ends.
Use case: UC12 - Review a deck
MSS:
- User enters review mode for a particular deck.
- Application shows the question of the first card under review.
- User attempts to answer the question in the card.
- User flips the card to reveal the answer.
- User self-grades question as easy/medium/difficult.
-
User proceeds on to the next card.
Repeat step 2-6 until all cards in deck have been exhausted.
Use case ends.
Extensions:
- *a. User decides to end the review early.
- *a1. User requests to end the review session.
- *a2. PowerCards ends the session and brings the user back to the Main mode before the review started.
Use case ends.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11or above installed. - Should be able to hold up to 1000 cards without a noticeable sluggishness in performance for typical usage.
- A card should load when prompted without any noticeable lag
- Every command should provide a response within 2 seconds
- The PowerCards program is not expected to determine the correctness of the user’s response
- A card should be easily added/deleted within 3 commands after opening the program
- The data stored by PowerCards should be forward compatible such that old data can still be loaded in newer versions of the program
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Deck: A group of flashcards (cards) of a specific topic
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
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.
-
Testing Commands for MAIN_UNSELECTED_MODE
Selecting a deck
-
Selecting a deck on the deck list
-
Prerequisites: User is in the Main Mode and a deck is not selected. MasterDeck is not empty.
-
Test case:
selectDeck 1
Expected: First deck on the list is selected and cards in the deck are displayed. -
Test case:
selectDeck 0
Expected: No deck is selected. Error details shown in the status message. -
Other incorrect
selectDeckcommands to try:selectDeck,selectDeck x,...(where x is larger than the list size)
Expected: Similar to previous.
-
Adding a deck
-
Adding a new deck of unique name to the MasterDeck
-
Prerequisites : User is in the Main Mode and a deck is not selected.
-
Test case:
addDeck Math
Expected: A new deckMathis created and displayed on the list of decks. If there is already a deck calledMath(case-sensitive) in the MasterDeck, it throws an error message and does not add the deck into the list. -
Test case:
addDeck
Expected: No new deck is added to MasterDeck. Error details shown in the status message states that deck name cannot be blank.
-
Editing a deck
-
Editing the name of an existing deck
-
Prerequisites: User is in the Main Mode and a deck is not selected. MasterDeck is not empty.
-
Test case:
editDeck 1 Chemistry
Expected: Edits the name of the deck at the index of 1 on the deck list to beChemistry. If there is already a deck calledChemistry(case-sensitive) in the MasterDeck, it throws an error message and does not edit the deck. -
Test case:
editDeck 0 Chemistry
Expected: No deck name is edited. Error details shown in the status message. -
Other incorrect
editDeckcommands to try:editDeck,editDeck x,...(where x is larger than the list size)
Expected: Similar to previous.
-
Deleting a deck
-
Deleting a deck on MasterDeck
-
Prerequisites: User is in the Main Mode and a deck is not selected. MasterDeck is not empty.
-
Test case:
deleteDeck 1
Expected: First deck is deleted from the list. Details of the deleted deck shown in the status message. -
Test case:
deleteDeck 0
Expected: No deck is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
deleteDeck,deleteDeck x,...(where x is larger than the number of decks)
Expected: Similar to previous.
-
Finding a deck
-
Finding a deck in MasterDeck
-
Prerequisites: User is in the Main Mode and a deck is not selected.
-
Test case:
findDecks science
Expected: Decks with names that includescienceare shown (case-insensitive). -
Test case:
findDecks science programming
Expected: Decks with names that includescienceorprogrammingare shown (case-insenstive). -
Test case:
findDecks
Expected: Does not show any specific decks. Error details shown in the status message.
-
Showing all decks
-
Showing all decks in MasterDeck
-
Prerequisites: User is in the Main Mode and a deck is not selected.
-
Test case:
showDecks
Expected: All existing decks in MasterDeck are shown.
-
Testing Commands for MAIN_SELECTED_MODE
Unselecting a Deck
- Unselecting a deck when a deck is selected
-
Prerequisites: User is in the Main Mode and a deck is selected.
-
Test case:
unselectDeck
Expected: Current deck is unselected.
-
Adding a card
-
Adding a card to the selected deck
-
Prerequisites: User is in the Main Mode and a deck is selected.
-
Test case:
addCard q\What is gravity? a\A force of attraction between objects due to their mass t\Easy
Expected: Adds a card to the deck with questionWhat is gravity?, answerA force of attraction between objects due to their mass, and tagEasy. Details of added card shown in the status message. -
Test case:
addCard q\What is gravity?
Expected: No card added to the deck. Error details shown in the status message. -
Test case:
addCard q\What is gravity? a\A force of attraction between objects due to their mass t\Doable
Expected: No card added to the deck. Error details shown in the status message. -
Other incorrect
addCardcommands to try:addCard q\ a\A force of attraction between objects due to their mass,...(where either question or answer is blank or missing in the command)
-
Deleting a card
-
Deleting a card at the given index in the selected deck
-
Prerequisites: User is in the Main Mode and a deck is selected. The deck is not empty.
-
Test case:
deleteCard 1
Expected: First card is deleted from the deck. Details of the deleted card shown in the status message. -
Test case:
deleteCard 0
Expected: No card is deleted. Error details shown in the status message. -
Other incorrect
deleteCardcommands to try:deleteCard,deleteCard x,...(where x is larger than the number of cards)
Expected: Similar to previous.
-
Editing a card
-
Editing a card at the given index in the selected deck
-
Prerequisites: User is in the Main Mode and a deck is selected. The deck is not empty.
-
Test case:
editCard 1 q\What is photosynthesis?
Expected: Edits the question of the first card in the deck. Details of the edited card shown in the status message. -
Test case:
editCard 0 q\What is photosynthesis?
Expected: No card is edited. Error details shown in the status message. -
Other incorrect
editCardcommands to try:editCard,editCard x,...(where x is larger than the number of cards)
-
Finding a card
-
Finding cards in the selected deck with keywords
-
Prerequisites: User is in the Main Mode and a deck is selected.
-
Test case:
findCards recursion
Expected: Cards with questions that includerecursionare shown (case-insensitive) -
Test case:
findCards recursion loop
Expected: Cards with questions that includerecursionandloopare shown (case-insensitive) -
Test case:
findCards
Expected: No card is shown. Error details shown in the status message.
-
Showing all cards in the deck
-
Showing all cards in the selected deck
-
Prerequisites: User is in the Main Mode and a deck is selected.
-
Test case:
showCards
Expected: Cards in the deck are shown.
-
Testing Commands for REVIEW_MODE
Ending a Review
-
Ending the current review
-
Prerequisites: User is in Review Mode.
-
Test case:
endReview
Expected: User returns to Main Mode with a deck selected/unselected depending on what the state of the application was before entering Review Mode.
-
Flipping a Card
-
Flipping the current card in review
-
Prerequisites: User is in Review Mode.
-
Test case:
p(Pis also a valid command)
Expected: The card either reveals or hide the answer.
-
Going to previous card
- Go to previous card in review
-
Prerequisites: User is in Review Mode.
-
Test case:
[
Expected: Right panel displays the previous card. If the current card is the first card in the review deck (i.e. no previous card exists), error details shown in the status message.
-
Going to next card
- Go to next card in review
-
Prerequisites: User is in Review Mode.
-
Test case:
]
Expected: Right panel displays the next card. If the current card is the last card in the review deck (i.e. no next card exists), error details shown in the status message.
-
Tagging a card as easy
-
Tag a card as easy during review
-
Prerequisites: User is in Review Mode.
-
Test case:
l(Lis also a valid command)
Expected: Current card is tagged as easy.
-
Tagging a card as medium
-
Tag a card as medium during review
-
Prerequisites: User is in Review Mode.
-
Test case:
;
Expected: Current card is tagged as medium.
-
Tagging a card as hard
-
Tag a card as hard during review
-
Prerequisites: User is in Review Mode.
-
Test case:
'
Expected: Current card is tagged as hard.
-
Other Testing Commands
Starting review
-
Starting review on a deck
-
Prerequisites: User is in the Main Mode. MasterDeck is not empty.
-
Test case:
review 1
Expected: Starts a review on the deck at the index of 1 on the deck list. If there is no cards in that deck, it throws an error message and does not start a review. -
Test case:
review 0
Expected: Review Mode is not started. Error details shown in the status message. -
Other incorrect
reviewcommands to try:review,review x,...(where x is larger than the number of decks)
Expected: Similar to previous.
-
Setting the limit of cards
-
Setting the limit of cards per review
-
Prerequisites: User is in the Main Mode. MasterDeck is not empty.
-
Test case:
setLimit 10
Expected: Sets the limit per review of 10 cards. -
Test case:
setLimit none
Expected: Resets the limit per review. -
Test case:
setLimit 0
Expected: Does not set the limit per review. Error details shown in the status message. -
Other incorrect
setLimitcommands to try:setLimit,setLimit x,...(where x is larger than 2147483647)
Expected: Similar to previous.
-
Opening help window
-
Opening the help window to display the UG link
- Test case:
help
Expected: A pop-up window is containing a link to UG with a copy button is shown.
- Test case:
Exiting the program
-
Exiting the program
- Test case:
exit
Expected: Exits the program. Window is closed.
- Test case:
Appendix: Effort
Challenges
User-friendly UI
The original AB3 program’s list view of persons is not practical for a flashcard application where users need to manage/review decks and cards. In addition, our PowerCards application requires two interfaces for the user: one for managing cards and decks and another for review sessions. To address these issues, we implemented a dual panel layout that allows users to view useful information side by side, helping them keep track of their progress and execute commands efficiently. In main mode (deck selected or unselected), the left panel is dedicated to decks while the right panel is dedicated to cards, enabling users to manage both easily. During review mode, the left panel displays review statistics while the right panel shows the current card being reviewed. Regarding the color scheme, we felt that AB3’s dark theme was uninspiring, so we designed and implemented our own light theme. This new theme gives the app a warm, welcoming feel that enhances the user’s experience.
Extensive testing
Our application has a total of 26 unique commands, as compared to 8 unique commands in AB3. With the increased number of commands, along with the increased number of classes to support these commands, means that code coverage is likely to decrease and more testing had to be done.
-
MAIN_SELECTED_MODEhas a total of 11 accessible commands. -
MAIN_UNSELECTED_MODEhas a total of 11 accessible commands. -
REVIEW_MODEhas a total of 9 accessible commands.
As such, we saw this as a valuable opportunity to conduct extensive testing of our application. We achieved this by writing unit and integration tests for our commands, parsers, and model objects. Through this process, we were able to maintain a coverage level of ~70%, only slightly less than the original ~72% coverage in AB3. Additionally, we increased the number of test cases from 248 in AB3 to 356 in PowerCards.
Achievements
- Successfully built a simple and efficient CLI flashcard application.
- Improved a lot from AB3 with a number of new features and a better UI.
- Drew clear and correct different styles of diagram for DG.
- Made a concrete OOP structure through discussions.
Appendix: Planned Enhancement
In order to counter known feature flaws from testing, the following are enhancements to be implemented in the future.
1. Making the command box scrollable
- Currently, the command box is not scrollable - when the user types into the command box, the content does not wrap.
- Users are likely to type long questions and answers hence it would be more convenient if the command box was scrollable.
- We plan to make content in the command box wrap and the command box itself scrollable.
Current: Non-Scrollable Command Box

Planned Enhancement: Scrollable Command Box

2. Review by untagged cards
- Currently, a user can only review all cards or cards that are specifically tagged with a difficulty.
- However, a user may want to review only untagged cards (which they have yet to review).
- Hence, the
reviewcommand should support a flag-uwhere untagged cards will be reviewed.
3. Enable removing of tags
- Currently, if a user intends to remove a tag from a card, they need to delete the card and create a new card without a tag.
- Hence, it would be more convenient if the user is able to untag a card directly from the edit command.
- Example:
editCard 2 t\would untag card with displayed index 2. - Additionally, a user may want to clear all tags of a deck before sharing with others.
- Hence, it would be more convenient if there is a
clearTagscommand to untag all cards in a deck - Example:
clearTags
4. Setting minimum width for components
- Currently, the size of the GUI panels can be shrunk by the user to a large extent as seen in figure 4 below such that the app is messy and essentially unusable.
- Hence, we intend to fix it by setting a minimum width for each component.
Current: Unusable GUI when shrunk by a large extent
Planned Enhancement: GUI with minimum width
5. Support finding keywords in deck name or card question even if there is punctuation or symbol appended
- Currently, the
findDecksandfindCardscommands are not able to find keywords in a deck or card if the word has no whitespace separating it from a punctuation. For example,findCards loopdoes not return a card with questionwhat is a loop?. - The find commands should support this feature as the punctuation does not change the existence of the keyword.
- Hence, we intend to support this feature in the future.

