1. About the Project

For our Software Engineering module CS2103T, our four-person team was tasked to modify or enhance the addressbook program into our software of choice. We morphed it into TopDeck, a general purpose flash card application, which allows users store flash cards in decks, and study these flash cards later.

My role was to implement study sessions. The following sections will describe my contributions in greater detail, as well as the sections I’ve added to the user and developer guides with regards to these enhancements.

2. Summary of Contributions

This section shows a summary of the coding, documentation, and other helpful contributions I have done to contribute to the team project.

Enhancement added: I added Study View to study a deck of flash cards.

  • What it does: The study session allows users to study a deck of cards. This is done by presenting users with random questions from cards in a deck. Once the users have recalled their answers, they can choose to reveal the answers to the questions. Cards do not repeat until the whole deck has been viewed.

  • Justification: In order for a flash card application to aid users in memory tasks, there has to be a mode where the users can test their knowledge of the cards. This mode allows users to randomise viewing of questions and then choose when to see the answers.

  • Highlights:

    • The feature was challenging to implement because it entailed constantly changing states.

    • The ability to generate flash cards are found in a separate class, making it easy for smarter study algorithms to be implemented in future.

    • Architectural considerations were made to ensure that the display would have minimal interactions with the internal state of the program.

    • Distinctive display themes were designed to make it intuitive for people to know whether they are looking at a question or answer.

Code Contributed: Please view https://github.com/cs2103-ay1819s2-w11-1/main to see the code that I have contributed.

Other contributions:

  • Project management:

    • There were a total of 4 releases, from version 1.1 to 1.4. I managed releases versions 1.2 to 1.3 (2 releases), together with the mid-versions (mid 1.2 and mid 1.3) on GitHub. This includes compiling the requirements needed at each stage, ensuring that all issues are resolved before each release, as well as building and releasing the binary.

    • I proposed a few meetings in order for our team to designate tasks before the release.

  • Enhancements to existing features:

    • I added the ability to switch between Cards/Deck view to Study view and vice versa

    • I resolved checkStyle issues

    • I enhanced the UI of our application and made the interface responsive to scaling

  • Documentation:

    • I made minor changes to the introduction to make it more comprehensible for non-technical users.

    • I alphabetised and split our Command Summary based on relevant categories.

  • Community:

    • I reviewed pull requests, #77 and #62 (undoing of card commands) and #29 (view state)

    • I assigned issues and enhancements that our team could work towards fixing or implementing.

    • I helped my friends add annotated diagrams for some parts of their documentation.

    • I gave our team tips on the IntelliJ workflow regarding code reformatting and viewing files in Project Structure.

  • Tools:

    • I made the project RepoSense Compatible

3. Contributions to User Guide

Below is an extract from my User Guide

<start of extract>

3.1. Study View

Study view can be accessed using any of these commands:

  • study INDEX from decks view

  • study from cards view

In order to facilitate your study session, Study view presents Flash Cards in two phases, namely Question Phase and Answer Phase.

3.1.1. Question Phase

Study view starts off in Question Phase, which displays the question in this user interface:

question
Figure 1. Study view’s Question Phase

As seen above, the question to be answered is displayed in a dark blue flash card.

Currently, questions are chosen this way: TopDeck shuffles the deck and displays cards one at a time until the entire deck has been viewed. Topdeck repeats this endlessly until you choose to end your study session.

You may attempt the question by typing your answer into the Command Box, which now doubles as an Answer Box. Once you’re ready to see the answer, hit Enter. Your attempt will be recorded and TopDeck will enter Answer Phase.

3.1.2. Answer Phase

During this phase, you will see the answer to the earlier question in the following user interface:

answer
Figure 2. Study view’s Answer Phase

As seen from the figure, the correct answer is displayed on a white flash card. Your attempt is shown on top next to the card for your own comparison.

Additionally, a prompt asks you to rate the difficulty of that flash card. You should input your rating into the Command Box which now doubles as a Rating Box.

Once you’ve typed in your rating, hit Enter. Your rating will be recorded and this value will contribute to average difficulty statistic seen in cards view. Immediately after that, TopDeck will reenter Question Phase.

During both phases, the following commands are available to end your study session:

3.1.3. Returning to decks view: back

Format: back

Outcome: Returns to decks view.

3.1.4. Opening the deck in cards view: open

Format: open

Outcome: Opens the deck in cards view.

4. Contributions to Developer Guide

<start of extract>

4.1. Study view

4.1.1. Stateful implementation

The purpose of a study session is to let users test their knowledge of flash cards. This is done by randomly generating a card to be shown to users, presenting them with questions followed by answers in an alternating manner.

In order to facilitate the alternation between two states, the StudyView class holds two main variables:

  • currentCard - the card which is currently being shown to the user.

  • currentStudyState - an enum which can be either be QUESTION or ANSWER

These two variables are continuously being altered to change the view every time the user interacts with the program.

User Commands

The user can execute two types of commands to toggle value of currentStudyState. These are ShowAnswerCommand and GenerateQuestionCommand.

Unlike other commands, the type of command executed is inferred on the basis of currentStudyState instead of the command word. Upon command execution, currentStudyState is evaluated and is toggled to the opposite state. This behaviour is summarised below.

cyc
Figure 3. Alternation of states summary

Besides toggling state, both commands also call other functions to fully support StudyView functionality as detailed below.

4.1.2. ShowAnswerCommand

This command is executed when users types in anything to the CommandBox during question state.

This string typed is the user’s attempt for the question shown. ShowAnswerCommand has to store this string internally for later display. This is done by setting userAnswer variable in StudyView class.

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

show
Figure 4. How ShowAnswerCommand works

Step 1. User attempts the question by typing in any command. If in question state and the command is not a preset command, a ShowAnswerCommand object containing userAnswer is returned.

Step 2. When command is executed, the user’s answer is stored internally in userAnswer variable of StudyView through the setUserAnswer() function.

Step 3. currentStudyState in StudyView is toggled to ANSWER.

Step 4. UI automatically changes to show answer as shown UI section.

4.1.3. GenerateQuestionCommand

This command is executed when users types into the CommandBox during answer state.

The string typed is his rating for the flash card shown. Thus, GenerateQuestionCommand needs to modify average difficulty rating inside Card object. Besides that, it needs to modify currentCard to show a new card as well.

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

gen
Figure 5. How GenerateQuestionCommand works

Step 1. User enters a rating. If in answer state, and command is not a preset command, and rating is between 1-5, a GenerateQuestionCommand object containing int rating is returned.

Step 2. When command is executed, addRating() is called to modify the difficulty of the currentCard. This calls addDifficulty() in Difficulty class which is a property of Card class. Implementation detailes are found in Difficulty Section.

Step 3. generateCard() in StudyView is called. StudyView calls its DeckShuffler to generate a card as detailed in DeckShuffler section. Card returned by DeckShuffler is passed back to StudyView and studyView uses this to reset its own currentCard through setCurrentCard() function.

Step 4. currentStudyState in StudyView is toggled to QUESTION.

Step 5. UI automatically changes to show question as shown in UI section.

Summary of Changes

The summary of variable changes to StudyState after running these commands is detailed below.

cycle

4.1.4. UI implementation

StudyView makes use of ReadOnlyProperty wrapper to store variables which the UI has to display. This wrapper is chosen as it implements the Observable interface.

The UI listens out for three things: the studyState, userAnswer, and textShown.

ui
Figure 6. UI Observer-Listener relationship diagram

The following details the changes to these observable variables.

observableProperty variable How this variable is modified Changes in UI

currentStudyState

Explained in Study User Commands

sCard.pseudoClass (flash card background color), sQuestion.pseudoClass (colour of flash card text), status.visibility (whether or not to userAnswer and difficulty rating prompt is seen. These must be seen only during answer state)

textShown

Calling setCurrentCard() and setCurrentStudyState() modifies textShown assign it a value which is either Question or Answer of currentCard.

sQuestion.text (text written on flash card)

userAnswer

Explained in Show Answer Command

userLabel.text (label which displays user’s answer to question displayed earlier)

4.1.5. DeckShuffler brief overview

In order to generate a random Card object reference, DeckShuffler holds 3 variables:

  • activeDeck - deck that it needs to choose cards from

  • shuffledDeck - list of cards in activeDeck that has been shuffled by Collections.shuffle()

  • it - a Card iterator that loops through cards in shuffledDeck.

When generateCard() is called, iterator calls next and returns Card referenced. If none, shuffledDeck is shuffled again and iterator is set to shuffledDeck.begin().

4.1.6. Difficulty class overview

The Difficulty object, a property of Card, has two variables:

  • totalRating

  • numberOfAttempts

When addDifficulty(int rating) is called, rating is added to totalRating and noOfAttempts is incremented by 1. Other views can obtain average by obtaining quotient of the two variables above.

4.1.7. Design considerations

Aspect: How to store states
  • Alternative 1 (current choice): Using enums

    • Pros: Easy to implement. Makes sense as QuestionState and AnswerState do not have intrinsic properties, besides the UI looks associated with each state.

    • Cons: Unused variables in StudyView, such as userAnswer variable.

  • Alternative 2: polymorphism using QuestionState and AnswerState classess

    • Pros: Less unused variables. More organised.

    • Cons: Requires larger structural changes.

I chose the first implementation as the problem of unused variables is minimal. I do not foresee major changes to the way QUESTION and ANSWER works in future. There are not many possible reasons to store extra variables associated only with either state.

Aspect: How to implement UI modifications
  • Alternative 1 (current choice): Observable Properties

    • Pros: UI changes automatically. Concerns are separated as no additional command is needed to manually update UI during internal state change.

    • Cons: Less control over UI changes.

  • Alternative 2: Manual Modification of UI

    • Pros: Greater control over items to send to UI

    • Cons: StudyView will have to concern itself with UI arrangements

I chose the first implementation as UI changes happen all the time but the UI is highly similar in both states. Thus, a few Observable variables should suffice to achieve the desired variation between states. <end of extract>