PROJECT: FlashCard Pro

Overview

FlashCard Pro is an application designed for students who prefer to use a desktop app for managing flashcards. It is optimised for users who are comfortable with Command Line Interface-based interaction.

FlashCard Pro has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.

Summary of contributions

Major enhancement: added the ability for user to view their statistics.

  • What it does:

    • Allows the user to see their past login sessions, total duration spent in the app, and their test sessions involving each deck.

    • More detailed statistics are also provided, allowing the user to drill down into a granular view of their activity, e.g. login sessions by week.

    • The user can also see their statistics by deck, which is useful if they want to gauge how much time they’re spending reviewing each subject. The average score for test sessions conducted on the deck is also provided, giving the user feedback on their performance.

  • Justification:

    • This feature improves the product by allowing the user to reflect on their activity in the app, and whether the time spent was productive.

    • Users can also see their improvement over time and feel encouraged by it.

  • Highlights:

    • This enhancement required some degree of analysis of how the application handles various commands, in particular the startup and shutdown of the application, in order to time the duration of each login session.

    • Additions to the Storage component and learning to use Haliq’s JSON storage features were required to store and load the SessionList objects.

    • My team’s decision to make State non-static influenced me to decouple UserStats and DeckStats from State. This required some degree of refactoring quite close to the deadline of the project.

    • To get aggregate data from LocalDateTime and Duration objects, I implemented a number of utilities in the DateTimeUtil class (and some others). I also implemented SessionListUtil and StatsDisplayUtil for handling the calculation of average scores and the display of TableView objects. The process of writing and testing these utilities was quite enjoyable and increased my confidence in working with Java APIs.

stats window

The Statistics window contains key statistics like the user’s number of login sessions, duration of login sessions, number of decks, number of cards, and average score for test sessions. It also displays the user’s login sessions in a table format, which can be sorted by clicking on the column headers. Similarly, the user’s decks are summarised in a table. Double-clicking on a table row will open the corresponding deck statistics window.

deck stats window

The Deck Statistics window shows the user’s statistics pertaining to the deck, and all of their test sessions involving the deck in a table format.

Major enhancement: contributions to the GUI of the app.

  • What I’ve done:

    • I was initially responsible for building and maintaining GUI of the app. The GUI I had envisioned was much simpler and had a custom layout — conceptualised in Figma, then built from scratch. It did not use the MVC pattern.

    • However, it was for the better that our team eventually decided to move on to an MVC-based GUI. This allowed us to focus on building the happy path of the app, before working on integrating the GUI and CLI, then making various cosmetic improvements. This new version of the GUI was authored by Timothy (hence, it is no longer my main feature), but I have made a number of improvements since.

    • Justification:

      • Although the application was and would be functional without many of these enhancements I have made, I believe they help to increase the usability of the application. For example, the box containing the MCQ options the user has inputted was previously too small. I have changed it to expand and show all MCQ options by default.

      • To see some more examples of my work, refer to the table below.

      • Cosmetic changes help make our app more appealing to the user and appear more polished overall.

    • Planned future enhancements:

      • For scrollable content, set the default scrollbar position to the top, rather than the bottom, when dealing with scrollable content. This was something that troubled me for a while, but I did not manage to fix in the end.

      • Wrap the cards in a deck within a scrollable pane, so that the whole layout will fit in view.

    • Highlights:

      • From my first baby steps in working with GUIs during the individual project, I can safely say that I have learnt a great deal since. In particular, I am now more familiar with the JavaFX library.

      • I can now build a JavaFX GUI (albeit a simpler one) programmatically, without using SceneBuilder, as I have done in the earlier stages of the project.

      • I can also author new components via SceneBuilder (such as StatisticsWindow) and make significant changes to existing components (such as MainWindow and the various displays). By referring to the API, I was able to overcome a number of challenges to achieve my desired behaviour (e.g. components being laid out with appropriate padding, preserving the size and scale of components when the window is resized).

      • I have also designed a different layout for my statistics windows, consisting of big numbers with labels, which is more creative and visually appealing than my initial design, which displayed the information in a bland way.

old stats window

My old design for the statistics window, which has since been substantially improved, as my comfort level with JavaFX has increased. See above for the new statistics window.

initial design

My initial design work on Figma.

The following table provides a summary of some of my GUI enhancements:

Description Old screenshot Updated screenshot

Improve appearance of code editor windows

old flashcoder java

new flashcoder java

Allow MCQ options in the "add card" and "edit card" displays to expand, instead of using a scroll pane.

old mcq

new mcq

Same as above, but for Java card test cases. Also added prompt text to help user with inputting test cases.

old java card

new java card

Set a constrained minimum size for the application window, to maintain visibility when the window is resized by the user.

old resize The window can be resized beyond reasonable limits.

new empty deck The window maintains its minimum size.

Increase the size of the question and answer text areas in the "add card" and "edit card" displays, allowing for user-friendly scrolling and multi-line input.

old long question add card

new long question add card

Modify the display of the card in a test, so that long questions and MCQ options display as expected.

old review long question old review mcq

new review long question new review mcq

Change the display of cards in a deck to become scrollable, flexible-width, and display long questions correctly.

old deck display

new deck display

Improve the appearance of the result popup that appears upon completing a test. Also, add the app icon to all popup windows.

old score popup

new score popup

  • Code contributed: [Functional code] [Test code for utilities] [Test code for other statistics classes]

  • Other contributions:

    • Team tasks:

      • Updated the app’s icon, including for all popup windows.

      • Also updated the title of JS and Java editors and playgrounds to include "FlashCard Pro:" as a prefix.

    • Project management:

      • Wrote issues upon discovering bugs and assigned them to respective team members.

      • Went through the issues from PE dry run and assigned them to respective team members.

    • Documentation:

      • I authored the Introduction section of the User Guide, as I was quite involved in the initial conceptualisation of the project. See Contributions to the User Guide below.

      • Subsequently, I made non-trivial improvements to the clarity of the writing throughout the User Guide. In particular, I abstracted out the What is a flashcard? and Interacting with flashcards sections from the Introduction.

      • I also helped to clean up various sections of the User Guide, especially in the first draft, to make sure they adhered to a consistent format.

      • I documented my own features (Statistics) in the Developer Guide. See Contributions to the Developer Guide below.

    • Community:

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

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.

Introduction

FlashCard Pro is an application designed for students who prefer to use a desktop app for managing flashcards. It is also useful for teachers who would like to provide resources, in the form of custom flashcard decks, to support their students’ learning.

FlashCard Pro is optimised for users who are comfortable with Command Line Interface-based interaction, allowing them to work more efficiently than with traditional Graphical User Interface (GUI)-based flashcard apps, while still being able to use their flashcards in a familiar GUI format.

What is a flashcard?

Flashcards are containers for information. Each card has a “front” and a “back”. One recommended use case is such: the user stores a question on the “front” of the card, and the answer on the “back”.

Interacting with flashcards

After sets of flashcards (known as “decks”) have been created, the user can interact with the flashcards in various ways. For example, they may test themselves on the content of the decks via timed and untimed tests. For ordinary cards with a front and back, the user can gauge their own understanding of the material by pressing either the "I got it right!" or "I got it wrong :(" buttons on the back of the flashcard.

Other types of flashcards support more advanced interactions. Cards with multiple choices for their answers will prompt the user to select an answer, and the app will automatically determine if the answer is correct.

At the end of each test, FlashCard Pro will provide the user with a score. Comprehensive statistics on the user’s test sessions and login sessions are recorded, which can be accessed via the Statistics menu in FlashCard Pro. The user may use these statistics to assess the frequency of their usage and their performance over time. Statistics are also provided on each card in a deck, so that the user can identify specific cards they may have problems with [coming in v2.0].

As with physical flashcards, the flashcards in FlashCard Pro can be shuffled, used in reverse, mixed between decks, etc [coming in v2.0]. Unlike physical flashcards, flashcards in FlashCard Pro are dynamic, offering a range of possibilities from traditional memorisation-type uses, to support for learning programming.

With FlashCard Pro’s Java and JavaScript cards, teachers can define basic coding problems for their students. Based on the test cases provided by the teachers, FlashCard Pro will evaluate the output of the student’s solution, allowing students to gauge their own coding knowledge, and teachers to evaluate their students’ progress. Test decks can be passed easily from student to teacher, as they are stored in convenient, lightweight JSON files which can be imported or exported natively in FlashCard Pro.

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.

Saving and viewing user statistics

  • The Statistics feature revolves around the storage and interpretation of the user’s sessions, be it login sessions or test sessions.

  • Therefore, the Session class is the main building block of all Statistics-related classes. They are stored in SessionList objects.

  • Due to design considerations, the UserStats and DeckStats objects are intended to be singletons, created upon application startup and modified, but never duplicated or deleted.

    • Thus, they are accessible via the static methods getUserStats() and getDeckStats() accessible via the StatsHolder class.

    • This method of implementation is similar to what my teammates have used to store State.

    • Initially, the UserStats and DeckStats objects were intended to be stored within State as well. However, the addition of undo/redo functionality complicated matters. Thus, the statistics objects have been decoupled from State.

The structure of Statistics-related classes is depicted in the class diagram below.

class diagram

Or, simplified:

class diagram simplified

The following sequence diagram depicts the starting, ending and saving of the user’s Session when they open and close the app.

sequence diagram

Challenges in implementation

  • Because of the custom StorageManager class used to load and save JSON objects, the implementation of loading and saving statistics is somewhat tightly coupled with StorageManager.

    • It is insufficient to simply override the toJson() method to ensure that the statistics objects would be stored correctly. Instead, the underlying structure of the statistics objects must be known and exposed during the implementation of e.g. the loadDeckStats() and saveDeckStats() methods in StorageManager.

    • Perhaps in v2.0, refactoring of StorageManager could allow for a higher level of abstraction of storage-related methods and reduced coupling between StorageManager and the unrelated Statistics classes.

  • As our application is quite significantly different than AB3, we used an MSS-focused approach to development: i.e. we focused on making sure that the user’s "happy path" could be completed via the GUI, before linking up the app’s behaviour with the CLI commands. This resulted in insufficient clarity and tight coupling of the Responses class with other classes.

    • The logic of parsing CLI input, handling incorrect commands, determining if the application is in an appropriate State etc., along with the actual handling of the command, is all bundled within Responses at present.

    • In v2.0, we could focus on removing duplicated code between the CLI and GUI implementations.

    • In v2.0, we could also work towards abstracting out the app’s desired response to a command in Command classes, allowing for a Parser to handle CLI calls and a Dispatcher to handle all Command s, whether they originate from the CLI or GUI.

    • By abstracting out the handling of each command into separate classes, each team member can check the logic of how each Command interacts with their component with ease and avoid duplicated code. e.g. A startTestSessionCommand could initialise the ExamRunner, update Statistics, and so on.

    • Because of the current less-than-ideal implementation of the app’s behaviour, in order to support creating/renaming/deleting decks along with undo/redo, code pertaining to DeckStats needed to be inserted at many disparate places in the code, e.g. within a button action in the EditDeckDisplay controller and in Responses.

Proposed extension: Statistics for individual cards in a deck

  • Statistics for specific cards in a deck could be stored within the Session object representing the user’s test session on a deck.

    • In this way, summary statistics e.g. how many times the card was reviewed in the past week or whether the user attempted the card correctly on average, can be generated with ease.

    • There is no need to store duplicated data about when each card is accessed.

  • One challenge for the implementation of card-specific statistics is the tight coupling of Responses with other classes, as mentioned above.

    • Because individual cards are prone to change, e.g. when the user edits the front or back of the card, not to mention the decks themselves can also be renamed or deleted, it is important that the implementation of DeckStats is fully cleaned up before work on CardStats can begin.