PROJECT: Anakin


Overview

Anakin is a desktop flashcard management application created by team T09-2 to solve the inherent problems associated with physical flashcards. It aims to facilitate quick and intuitive management of virtual flashcards as well as the sharing of flashcard decks. Additionally, it features the ability to rate the difficulty of individual flashcards and a scheduling algorithm that prompts reviews of cards based on their difficulty rating.

Team T09-2 consisted of myself, Joel Lee, Tay Yu Jia, Foo Guo Wei, and David Goh.

Summary of contributions

  • Code contributed: Reposense

  • Major enhancement: Re-design model component

    • What can the new model do:

      • Allows Anakin to have a list of decks, each deck contains a card list with questions and answers.

      • Allows UI to observe both the deck list and card list so that it can update its deck panel and card panel when these lists are modified (executing commands).

      • Allows Logic component to execute its set of commands by providing a detailed Model interface, which can support the logic of those operations.

    • Justification: A new Model is needed to manipulates the state of the application and determines the interaction between objects like deck and card.

    • Highlights: Re-designing the Model component requires in-depth understanding of all components in order to have a comprehensive application design.

  • Other enhancements:

    • Implement sort command

      • What can it do:

        • Sort the current deck list in lexicographical order.

        • Sort the current card list in lexicographical order if user is inside a deck.

      • Justification: This allows user to manage their data better and to find deck or card easily.

    • Implement find command

      • What can it do:

        • Search for decks by name if user is under the home directory.

        • Search for cards by question if user is inside a deck.

        • Search for partial word (keyword need not be exactly the same as the deck’s name or card’s question)

      • Justification: This allows user to locate the deck or card that contains specific keywords quickly.

    • Add messages to undo and redo commands

      • What is the new messages: The undo and redo messages will show which command has just been undo, or redo.

      • Justification: This provides user more transparent view of the commands being executed.

  • Team contributions:

    • Project management: Managed release v1.4 on GitHub - v1.4

    • Wrote tests for model component (Pull requests #130)

    • Enhancement to existing features:

      • Wrote additional classes for test util (Pull requests #122)

      • Wrote additional tests for existing features to increase coverage from 79.5% to 84% (Pull request #192)

    • Documentation:

      • Updated developer guide (Pull request #91, #195, #199)

      • Updated user guide (Pull request #164, #195)

    • Community:

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Search for a deck or card : find

Search decks by names or cards by questions.

  • If user is currently in a deck, find all cards which contain the specific keywords.

  • If user is not in a deck, find decks.

Format: find KEYWORD [MORE_KEYWORDS]…​

  • The search is case insensitive. e.g hans will match Hans

  • The order of the keywords does not matter. e.g. Hans Bo will match Bo Hans

  • Only the name of the deck or the question of the card is searched.

  • Decks or cards matching at least one keyword will be returned (i.e. OR search). e.g. Hans Bo will return Hans Gruber, Bo Yang

  • If user inputs 1 keyword, partial word will be matched. e.g 'Han' will match `Hans'

  • If user inputs multiple keywords, only full words will be matched e.g. 'Han Solo' will match 'Han non-solo' but will not match 'Hans Soooolo'

Examples:

  • find Algo
    Returns algo and Easy Algo

  • User is not inside any decks:

    • find Bio Chem Physics
      Returns any decks containing Bio, Chem, or Physics in their name.

    • find insert
      Returns insert, inserted, inserting or any decks of which name contains these words.

  • User is inside a deck: find John Snow
    Returns any cards containing John or Snow in their questions.

Sort : sort

Sort the current list in lexicographical order.

  • If user is currently inside a deck, sort all cards according to their questions.

  • If user is not in a deck, sort all decks according to the their names.

Format: sort

Adding a deck: newdeck

Adds a new deck with the given name to Anakin
Format: newdeck n/NAME

  • This deck will contains an empty list of cards.

  • This operation is disabled when user is currently inside a deck.

  • If multiple arguments are given (i.e. newdeck n/My First Deck n/My Second Deck only the last valid argument is accepted for each respective field.

  • User should be under Anakin’s deck list to perform this operation (not inside any decks).

Examples:

  • newdeck n/My First Deck

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Model component

AnakinModelClassDiagram

Structure of the Model Component

The Model,

  • stores Anakin’s data and manipulates the state of the application.

  • provides a Model interface for Logic component to execute its set of commands.

  • manages the interaction and relationship between different objects (Anakin, Card, Deck, …​)

  • exposes an unmodifiable ObservableList<Deck> and ObservableList<Card> that can be 'observed' e.g. the UI is bound to these lists so that the UI automatically updates when the data in the lists change.

  • does not depend on any of the other three components.

Card-level operations

Current implementation

Card-level operations are supported in Anakin class:

  • Anakin#addCard(Card card) - Add a card to the current deck.

  • Anakin#deleteCard(Card card) - Delete a card from the current deck.

  • Anakin#updateCard( Card target, Card editedCard) - Update the information of a card inside the current deck.

These operations are exposed in the Model interface as: Model#addCard(Card card), Model#deleteCard(Card card), Model#updateCard(Card target, Card editedCard) respectively.

Given below is an example usage scenario and how these operations are executed in Model.

The user executes newcard q/Hello? a/World to add a new card with question "Hello?" and answer "World" to the current deck.

  1. The newcard command calls Model#addCard(Card card), or ModelManager#addCard.

  2. ModelManager, which implements Model interface, will call Anakin#addCard method.

  3. Anakin#addCard will throw DeckNotFoundException if the user is not inside a deck. Otherwise, it will call method UniqueCardList#add(Card toAdd).

  4. UniqueCardList#add will throw DuplicateCardException if the card already exist in the list. Otherwise, it will add the card to its internal ObservableList<Card>.

The following sequence diagram shows how the newcard operation works:

NewCardSequenceDiagram

Design consideration

  • Alternative 1 (current choice): Implement the logic of card-level operations in Anakin class.

    • Pros: Easy to implement and debug as all logic related with executing commands are implemented in Anakin.

    • Cons: Deck class is not informed, or notified when its UniqueCardList is modified. This might result in unexpected behaviors if a card-level command is executed and the person in charge of Deck class assumes that the UniqueCardList is unmodified.

  • Alternative 2: Implement the logic of card-level operations in Deck class.

    • Pros: The responsibility of each class is clear, only a Deck can modify its list of cards.

    • Cons: The logic for executing deck-level and card-level commands are implemented at different places. We must ensure that the implementation of each command is correct.

Handle invalid commands

Current implementation

  • Deck-level operations (newdeck, editdeck, deldeck, exportdeck, importdeck) are disabled when user is inside a deck.

  • These commands will be blocked in Logic component by checking the state of the application through Model interface.

Design consideration

  • Alternative 1 (current choice): Implement the logic of command-checking in Logic component

    • Pros:

      • Reduce possible bugs caused by having each methods check the state of the application before execution.

      • Model component does not have to handle invalid commands.

      • Exceptions are thrown and handled inside Logic components instead of being passed from Model to Logic.

    • Cons: Increase coupling between Logic and Model component.

  • Alternative 2: Handle all commands logic in Model component

    • Pros: Lower degree of dependency between Logic and Model (aka low coupling), thus make the process of maintenance, integration and testing easier.

    • Cons: Model component has to check for invalid commands according to its state for all commands.

Keep cards panel updated by UI

Problem with the old design

The UI (MainWindow) constructs the displayed cards panel by obtaining an ObservableList of cards from Model, this list is assigned when UI starts, and will never be re-assigned.

The UI "observes" the list and updates when it is modified.

This approach works well for the deck list because Anakin contains only 1 list of decks. However, the card list can not be updated in the same manner because Model component will change its card list’s reference when user enters another deck.

In this case, the card list in UI will not be updated because the card list of which UI has reference to is actually not changed, but it is the wrong card list.

Design considerations

  • Alternative 1 (current choice): Have a displayedCards list in Model and keep it updated with the current list of cards

    • Explanation: The UI needs only 1 reference to this displayedCards list, each time user enters another deck, displayedCards list is cleared and the new deck’s list of cards is copy to the displayedCards list

    • Pros: The structure of Model and UI component needs not be changed

    • Cons: Need to keep a copy of the current card list, copying the whole list of cards for each cd operation might affect performance

  • Alternative 2: Model component raises an event when its current card list’s reference is changed

    • Explanation: When user cd (enters) a new deck, Model will raise an event (CardListChangedEvent), which is subscribed by UI, then UI can re-assign its list of cards and update the cards panel accordingly

    • Pros: Better performance

    • Cons: Need to re-design Model and UI components