This portfolio outlines my contributions to the project Anakin.

PROJECT: Anakin


Project Anakin is the brainchild of team T09-2 which comprises myself, Joel Lee, Foo Guo Wei, David Goh and Nguyen Trong Truong Thanh. We completed it in November 2018 as part of a Software Engineering module (CS2103T) in the National University of Singapore.

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.

Ui

The user interacts with Anakin using a command line interface, and has a GUI created with JavaFX. Anakin is written in Java, and has about 10 kLoC.

Summary of contributions

This section acts as a summary of my contributions to project Anakin.

  • Major enhancement: I added the ability to review decks

    • What it does: allows the user to review the flashcards in the deck one by one.

    • Justification: This feature improves the product significantly because a user will want to be able to look through his flashcards stored in our application. It is also important to be able to view the question and answer separately as this is used as a revision tool.

    • Highlights: This enhancement affects existing commands and commands to be added in future. While in the review mode, the user is not allowed to make any changes to his decks and cards, except for classifying his performance for each card. The implementation of this enhancement involves notable UI changes to switch out the screen for editing decks with a different screen specially created for reviewing flashcards.

  • Minor enhancements:

    • Enhanced UI component by introducing a new screen for reviewing flashcards and adding a panel for displaying flashcards in decks.

    • Implemented a editcard command that allows user to update the details of their flashcard which include the question and answer.

    • Successfully integrated the different components of the application (i.e. Model, Logic, Storage and UI) and produced the first working prototype.

  • Code contributed: My GitHub commits, My RepoSense Dashboard

  • Other contributions:

    • Project management:

    • Enhancements to existing features:

      • Updated the GUI color scheme (Pull requests #77, #178)

      • Created tests for UI component (Pull request #137)

      • Refined system tests (Pull request #179)

      • Added more tests as part of a team effort to increase coverage to above 90% (Pull request #250)

    • Documentation:

      • Improved documentation through adding more details and reformatting. (Pull requests #34, #113, #118, #183, #184)

    • Community:

      • PRs reviewed (with non-trivial review comments): (Reviews #30)

      • Resolved issues and bugs: (Pull requests #35, #116, #182, #251)

      • Discovered and reported bugs to peers: (Issues #99, #101, #102, #151, #153, #174)

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.

Review the cards in a deck : review

Starts a review of the deck specified.
Format: review INDEX_OF_DECK

  • INDEX_OF_DECK must be a positive integer from 1 onwards and is based on the currently displayed list.

  • While in review mode, commands that operate on decks and cards are disabled except endreview, flipcard, nextcard, prevcard, classify, help, history, exit.

  • The application’s data will only be stored after executing endreview command.

Flip a card in a review : flipcard

View the other side of the current card during a review.
Format: flipcard

Examples:

  • review 1
    flipcard
    flipcard
    Reviews the first deck on the list. You will see the first question card. Upon first flipcard, you will see the answer on the back of the card. When you execute flipcard again, you will see the question card once more.

Go to the next card in a review : nextcard

Views the subsequent card in the deck.
Format: nextcard

When you are at the last card of the deck, executing nextcard will loop back to the first card.

Go to the previous card in a review : prevcard

Views the previous card in the deck.
Format: prevcard

When you are at the first card of the deck, executing prevcard will loop back to the last card.

Exit review mode : endreview

Exits the review and returns to the editing menu
Format: endreview

Executing undo after reviewing will undo all the changes made in that review session (all classify commands).

Editing a card : editcard

When user is inside a deck, edits an existing card at the specified index. If multiple arguments are given for question or answer, only the last valid argument is accepted for each respective field.
Format: editcard INDEX_OF_CARD [q/QUESTION]-[a/ANSWER]

  • Edits the card at the specified INDEX_OF_CARD inside the deck. The index refers to the index number shown in the list of displayed cards. The index must be a positive integer e.g. 1,2,3.

  • Existing values will be updated to the input values.

  • If any of 2 fields: [q/QUESTION] [a/ANSWER] is left empty, the old value for that field will be retained

  • At least one of the optional fields must be provided.

  • User should be inside a deck to perform this operation.

Examples:

  • editcard 1 a/New Answer
    Edits the answer of the first card in the current card list to be "New Answer". If multiple arguments are given for question or answer, only the last valid argument is accepted for each respective field.

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.

Deck Review Implementation

Current Implementation

The deck review mechanism is facilitated by Anakin from Model, the MainWindow and DeckReviewScreen from UI and the EventsCenter.

It implements the following operations:

  • Anakin#isReviewingDeck() - Checks if user is in review mode.

  • Anakin#startReview() - Starts a review.

  • Anakin#endReview() - Ends a review.

  • Anakin#getIndexOfCurrentCard() - Retrieves the index of the last known reviewed card.

  • Anakin#setIndexOfCurrentCard() - Updates the index of the last known reviewed card.

These operations are exposed in the Model interface as Model#isReviewingDeck(), Model#startReview(), Model#endReview(), Model#getIndexOfCurrentCard() and Model#setIndexOfCurrentCard respectively.

Also, it is supported by the following commands from Logic:

  • review - Starts the review of a selected deck

  • endreview - End the review

  • nextcard - Moves to the subsequent card in the deck

  • prevcard - Moves to the previous card in the deck

  • flipcard - Flips the current card to display either the question or the answer

Furthermore, it posts the following events to trigger changes in UI:

  • StartReviewRequestEvent(Card card)

  • FlipCardRequestEvent()

  • ReviewNextCardEvent(Card nextCard)

  • ReviewPreviousCardEvent(Card prevCard)

  • EndReviewRequestEvent()

Given below is an example usage scenario and how the deck review mechanism behaves at each step.

Step 1. The user launches the application and he already has a deck of cards that he wants to review. He executes review 1 command to review the first deck on the list.

  1. The review command calls Model#getIntoDeck(Deck deck).

  2. It then calls Model#startReview() which updates the isReviewingDeck boolean in Anakin to true.

  3. It also calls Model#getFilteredCardList() and Model#getIndexOfCurrentCard() to retrieve the Card object of the last reviewed card.

  4. Thereafter, it posts a StartReviewRequestEvent(Card card) with the EventsCenter.

  5. MainWindow, on the UI side, subscribes to this event and switches DeckEditScreen with DeckReviewScreen by reordering the nodes in mainAreaPlaceholder, which is a JavaFX StackPane.

The following sequence diagram shows how the review operation works:

ReviewSequenceDiagram

Step 2. The user sees the question displayed on the first card and comes up with his own answer. To verify his answer, he executes the flipcard command.

  1. The flipcard command posts a FlipCardRequestEvent with EventsCenter.

  2. DeckReviewScreen is notified of the event and switches the card with the question with the other card displaying the answer. This is also achieved by reordering the nodes in a StackPane but this time in reviewAreaPlaceholder. As a result, the user is presented with the answer to the question.

Step 3. The user wants to go to the next card and executes nextcard command.

  1. The nextcard command calls Model#getFilteredCardList() and Model#getIndexOfCurrentCard() and increments the index by one.

  2. If the incremented index is equal to the size of the card list, it reassigns the index a value of 0. This is to ensure that calling nextcard on the last card of the deck will loop back to the first card.

  3. Using the Card object found at the new index, the command posts a ReviewNextCardEvent using EventsCenter.

  4. DeckReviewScreen is subscribed to the event and uses the Card object to create question and answer `DeckReviewCard`s and replaces the currently displayed cards with these two new ones.

Step 4. If the user wants to go back to review a previous card, he executes prevcard command. The explanation of the process is similar to Step 3.

Step 5. When the user is done, he executes endreview to quit review mode.

  1. The endreview command posts a EndReviewRequestEvent using EventsCenter.

  2. MainWindow is subscribed to the event and switches the DeckEditScreen back to the front by reordering the nodes in mainAreaPlaceholder and the user is able to edit his decks again.

The following activity diagram summarizes what happens when a user enters deck review mode.

ReviewActivityDiagram

Design Considerations

Aspect: Tracking index of current card
  • Alternative 1 (current choice): Store a currentIndex field in UniqueCardList

    • Pros: Easy to implement and complies with separation of concerns. Can also easily saved in Storage.

    • Cons: Introducing state to UniqueCardList may not be the best solution.

  • Alternative 2: Store currentCardIndex in Anakin

    • Pros: Convenient access to field by exposing method in Model

    • Cons: Field is not required by many operations in Anakin and its use case is specific to deck reviews.

Aspect: Iterating through cards during review
  • Alternative 1 (current choice): Post events for UI to change the currently reviewed card.

    • Pros: Logic of iterating cards is decoupled from UI.

    • Cons: Limited scalability as adding new functionality require adding more events and event handlers.

  • Alternative 2: Implement a ListElementPointer for the list of cards similar to command history.

    • Pros: Able to easily implement more functionality such as keyboard shortcuts for iterating cards.

    • Cons: Still requires events to trigger changes in UI.

UI Implementation

Previous implementation (v1.2)

The UI for Anakin at v1.2 split the main area into three sections:

  • (Left) List of decks

  • (Right) List of cards in selected deck

This was implemented by morphing PersonListPanel and PersonListCard into our use cases for decks and cards and editing MainWindow to render changes in both decks and cards.

Given below is an example usage scenario and how the lists are displayed at each step.

Step 1. The user launches Anakin application and sees a list of sample decks. At this step, the CardListPanel is empty.

Step 2. The user executes cd 1 command to navigate into the first deck. Anakin renders the deck’s cards (at index 1) on the CardListPanel.

Step 3. The user executes cd 2 command to navigate into the second deck. Anakin switches the displayed cards with that of the second deck.

Step 4. The user executes cd .. command to navigate out of the second deck. The CardListPanel is empty again.

Current implementation (v1.3)

The UI for Anakin was revamped in v1.3. Previously in v1.2, the application had a list of decks and list of cards on its main view MainWindow. In v1.3, the panels displaying these lists have been refactored into DeckEditScreen. This is because of the addition of DeckReviewScreen which acts as the user interface when users are reviewing a deck. When the user starts reviewing a deck, MainWindow will swap DeckEditScreen with DeckReviewScreen to show the correct UI. The DeckReviewScreen displays a DeckReviewCard at a time, as the user is going through his flashcards. It also boasts of the ability to flip the card to display questions and answers separately, and iterate to subsequent and previous cards in the deck. See Deck Review Implementation for an example use case.

Design considerations

  • Alternative 1 (current choice): Display deck and card lists side by side

    • Pros: Easy to implement

    • Cons: Somewhat lacking in aesthetics

  • Alternative 2: Display deck and card list in the same panel and switch out accordingly

    • Pros: Looks more impressive in UI-wise

    • Cons: Have to implement a switch event to toggle items inside StackPane

UI component

AnakinUIClassDiagram
Figure 1. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, DeckEditScreen, DeckReviewScreen, StatusBarFooter etc. The DeckEditScreen is in turn made up of DeckListPanel and CardListPanel and the DeckReviewScreen is made up of DeckReviewCard. 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.

  • Binds itself to some data in the Model so that the UI can auto-update when data in the Model changes.

  • Responds to events raised from various parts of the App and updates the UI accordingly.