1. About the Project

My team and I were tasked with morphing a basic commandline interface addressbook application(AB4) for our software engineering project. We decided to morph the application into a Flashcard management application called TopDeck

TopDeck is a user-friendly flashcard management application that aims to help users better memorise any content that they desire. The main functionality of the application include managing a list of decks, managing the cards within each deck and having study sessions. Users can use it to learn a language, remember a math formula or simply recall an answer to a question.

I was in-charge of the card’s management feature within the application and these include creating, reading, updating and deleting (CRUD) a card within a deck as well as searching for cards that the user is interested in. The following sections illustrate these enhancements as well as the relevant sections that I have included in the user and developer guides.

2. Glossary

The following symbols are used throughout the application and represent the following:

NOTE
CAUTION

3. Summary of Contributions

This section shows a summary of my coding, documentation, and other helpful contributions to the team project.

Enhancement added: I added the ability for users to add, delete and edit cards. Along with the usual CRUD operation, I also added a find and clear feature for the cards.

  • Justification: A user should be able to modify a deck to customize the study session that the user will experience. A find feature will help the user to locate the specific card especially when they want to recall the question or answer to the specific question.

  • Highlights: The CRUD operation has to work with the existing commands and data structure in AB4. This was challenging as the Undo and Redo methods in the original application leverages on the immutability of the data structure. Also, our application maintains a state object which the UI is dependent on. As such, there is also a need to ensure both the state of the application and the model is consistent with each other after every command.

  • Credits: The edit command has an auto-complete feature which was implemented by my teammate Wei Heng.

Code contributed:

Other contributions:

Project management:

  • There were a total of 4 milestones, I managed the milestone tracking through out the whole project through the issue tracker on GitHub.

Enhancements to existing feature:

  • Wrote Card System test to increase the coverage from 82% to 87% (Pull request #96)

  • Enhance find command to allow for finding of cards using phrases. (Pull request #60)

  • Enhance UI test for ListPanelHandle so that it can take both Deck and Cards (Examples: #54, #94)

Community:

  • Reviewed Pull-Requests (Examples: #58, #28, #88)

  • Reported bugs (Examples: #34, #136)

  • Updated Class diagrams (Examples: #16, #148)

  • Refactored initial code from AB4 (Pull request #8)

4. Contributions to the User Guide

We had to update the original User Guide with new instructions for the different enhancements implemented. The following is an extract from TopDeck User Guide that I have written.

(Start of extract)

4.1. Cards View

These commands are only available in cards view. In this section, the active deck is the deck used in the open command.

4.1.1. Adding a card to the active deck: add

Format: add q/QUESTION a/ANSWER [t/TAG]

Outcome: Creates a new card with question and answers and adds it to the current deck.

Example: add q/Hello a/World t/TopDeckSample

Below is an example of what the user should see upon the execution of the command:

Before:

add card 1

After:

add card 2

4.1.2. Editing a card in the active deck: edit

Format: edit INDEX q/QUESTION a/ANSWER [t/TAG]

Outcome: Edits the text of the card at INDEX.

Example: edit 1 q/Edit Hello a/World t/Editted

Auto-Complete: Instead of typing the whole command, TopDeck also provides an auto-complete feature for the edit command. Users need only type edit INDEX and TopDeck will fill up the commandline for the user to edit accordingly.

4.1.3. Finding a card in the active deck by name: find

Format: find KEYWORD [KEYWORD]…​

Search for phrases: TopDeck provides the user the ability to search for specific question by searching for a whole phrase instead of only individual words. This is done by putting " around KEYWORD. The find command searches all KEYWORD between 2 " and so there should not be any " character in KEYWORD. Searching using phrases only searches the question.

Outcome: Lists all cards within the current deck containing KEYWORD in its text.

find will only search for full-matching words. For e.g. Animals will not be found if animal is used to search for it.
The entire phrase inside " will be matched word for word. For example, find "Is there a question" will display the questions with the entire phrase Is there a question and the question Is there a question? will not be matched due to the extra ?

Example:

  • find Singapore

Below is the result of executing this command:

find card 1

(End of extract)

5. Contributions to the Developer Guide

The following section is an extract of my additions to TopDeck Developer Guide.

(Start of extract)

5.1. Card management

5.1.1. Current implementation

Card management is currently facilitated by Model which implements the following operations:

  • hasCard(Card card, Deck deck)

  • addCard(Card card, Deck deck)

  • removeCard(Card target, Deck deck)

  • editCard(Card newCard, Deck deck)

The CRUD operations are exposed in the Model interface as Model#addCard(Card card, Deck deck), Model#deleteCard(Card target, Deck deck) and Model#setCard(Card target, Card newCard, Deck deck). For each operation, there are 2 objects that need to be updated namely, VersionedTopDeck and CardsView. Each CRUD operation called by `ModelManager`can be broken down into the following steps:

card seq
Figure 4.3.1 ModelManager#addCard(Card card, Deck deck) Activity Diagram

Here is a code snippet for VersionedTopDeck#addCard(Card newCard, Deck deck) which shows the sequence of functions carried out and returns the newly edited deck to ModelManager:

public Deck addCard(Card card, Deck activeDeck) throws DuplicateCardException, DeckNotFoundException {
        requireAllNonNull(card, activeDeck);
        if (!decks.contains(activeDeck)) {
            throw new DeckNotFoundException();
        }
        if (activeDeck.hasCard(card)) {
            throw new DuplicateCardException();
        }
        Deck editedDeck = new Deck(activeDeck);
        editedDeck.addCard(card);
        decks.setDeck(activeDeck, editedDeck);
        .
        .
        .
        return editedDeck;
}
All other CRUD operations works similarly. Instead of VersionedTopDeck.addCard(Card card, Deck activeDeck), VersionedTopDeck.deleteCard(Card target, Deck activeDeck) or VersionedTopDeck.setCard(Card target, Card newCard, Deck activeDeck) is called.

Given below is an example usage scenario of how the add operation works and how it interacts with Undo/Redo:

Step 1. The user starts up the application and is in the DecksView. The user then executes the open 1 command to open the first deck(D1 in the figure). This should change the ViewState in the ModelManager from DeckView to CardsView and causes CardsView.activeDeck to point to the first deck as per figure 4.3.2. For more information, refer to the Deck feature.

card fig 1
Figure 4.3.2 Scenario 1

Step 2. The user executes add q/question a/answer to add the new card into the current deck. The add command is parsed and calls Model#addCard(Card card, Deck deck). VersionedTopDeck(Card newCard, Deck deck) is then called. D3 which is a copy of D1 is created and the new card is added to D3. VersionedTopDeck is then updated as per figure 4.3.3 by calling UniqueDeckList.setDeck(Deck target, Deck editedDeck).

card fig 2
Figure 4.3.3 Scenario 2

Step 3. Next, the CardsView is updated creating a new CardsView that points to D3 as in figure 4.3.4

card fig 3
Figure 4.3.4 Scenario 3

Step 4. Once that is done, the ModelManager.filteredItems list and the UI is being updated to reflect the change.

Below is a sequence diagram to illustrate the sequence of activities upon calling Model#addCard(Card card, Deck deck):

card fig 9
Figure 4.3.10 Sequence Diagram

5.1.2. Design considerations

Aspect: Data structure of cards
  • Alternative 1(current choice): Have a list of cards within each deck

    • Pros: Allows for decks features such as import and export. Also, any search operation is done within the deck only.

    • Cons: There is a need to implement an extra Deck data structure and makes the model more complicated.

  • Alternative 2(current choice): Have a global list of cards with tags.

    • Pros: Updating of UI will be easier as there is one global list only.

    • Cons: In order to study the cards, the application has to search through the global list to find the cards with the tags that we want to study. Organisation of cards will also be messy as the only form of organisation for cards is through tagging.

  • Reason for choice 1: Choice one was chosen as it would allow the user an extra layer of organisation(Deck and Tag) when managing cards.

Aspect: How CRUD operation should work
  • Alternative 1 (current choice): Recreate the CardViews after each operation

    • Pros: Leverages on the current implementation of VersionTopDeck making it easier to implement.

    • Cons: There is a memory and operation overhead as a new CardsView is constantly being created. Also, there is a need to refresh the UI at every update as the UI needs to render the new CardsView.

  • Alternative 2: Alter the card list in CardsView and the model upon each operation

    • Pros: Only has to update the active Deck in CardsView and the model

    • Cons: As CardsView.activeDeck can only reference to one deck only, the current Undo/Redo feature will have to be re-implemented to store the previous commands and the object changed.

  • Reason for choice 1: Choice one was chosen in order to retain the Undo/Redo function and to leverage on the original architecture instead of changing it.

(End of extract)