PROJECT: Flashy


logo

Overview

Flashy is an application to help users organise their flashcards to help them memorise better.

Summary of contributions

  • Major enhancement: Enhanced flashcards to be polymorphic.

    • What it does: Allows users to add and edit MCQ or fill-in-the-blanks flashcards (on top of normal ones).

    • Justification: This feature improves the product significantly because users learn differently (some need prompts) and the ability to add different kinds of flashcards would allow them to add those that suit their learning style.

    • Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands, and care has to be taken so as to not affect the existing features.

  • Minor enhancement: Added a delete flashcard feature so that flashcards can be deleted when users no longer have a use for them.

  • Code contributed: [Functional Code] [Test Code]

  • Other contributions:

    • Project management:

      • Added issues and milestones

    • Project enhancement:

      • Performed a refactor from the original addressbook to the current Flashy application.

    • Enhancements to existing features:

      • Changed typical cards to aid tests for existing features (Pull requests #66, #38)

    • Documentation:

      • Did cosmetic tweaks to existing contents of the Developer Guide (Pull Requests #76, #200)

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.

Adding a flashcard: addc

You can add flashcards to Flashy. In Flashy, we support the feature of adding three different types of flashcards: normal, MCQ or fill blanks.
To add a normal flashcard, use addc f/FRONT b/BACK [t/TAGS]…​
To add a fill blanks card, the input is the same as that for a normal card, the only difference is the presence of blanks _ in the f/FRONT parameter.
To add a MCQ flashcard, use addc f/FRONT o/OPTION …​ b/BACK [t/TAGS] …​

For a MCQ flashcard, ensure that the parameter for b/ falls between 1 the number of options inclusive.
Note that a blank is denoted by a single underscore _.
For a fill blanks flashcard, ensure that the parameter for b/ should have the same number of answers (separated by ,) as there are blanks.

Examples:

  • addc f/What is the greatest flashcard application? b/Flashy t/Trivia
    Adds a normal flashcard with the front and back of the first card being What is the greatest flashcard application? and Flashy respectively, as well as tagging it as Trivia.

  • addc f/A square is a polygon with _ side meeting at _ angles. b/equal, right
    Adds a fill-blanks card with the front and back of the card being A square is a polygon with _ side meeting at _ angles. and equal, right respectively.

  • addc f/Which continent is Singapore in? o/Asia o/Africa o/Australia o/South America b/1
    Adds a MCQ-type flashcard with the front being Which continent is Singapore in?, options includes Asia, Africa, Australia and South America and back being 1.

A flashcard can have any number of tags (including 0).

Editing a flashcard : editc

You can edit an existing flashcard currently stored in Flashy. This comes in handy if you make a mistake when adding a card.
Format: editc INDEX [f/FRONT] [o/OPTION] .. [b/BACK] [+t/TAG]… [-t/TAG]…

  • Edits the flashcard at the specified INDEX. The index refers to the index number shown in the last card listing. The index must be a positive integer 1, 2, 3, …​

  • Existing values will be updated to the input values.

  • This only applies to parameters which you have supplied. If, for example, no parameters for f/ are supplied, the front of the card would not be edited.

A particular type of flashcard (normal, MCQ or fill blanks) can only be edited to the same type of flashcard (e.g. you cannot edit a normal flashcard to a MCQ flashcard).
When removing a tag from a flashcard, ensure that the tag exists and the flashcard is associated with that tag.
Ensure that the constraints on flashcard is not violated when editing. For constraints, refer to the Caution warning under Section 5.2.2.

Examples:

  • editc 1 f/What is the greatest flashcard application? b/Flashy +t/Trivia
    Edits the front and back of the 1st flashcard to be What is the greatest flashcard application? and Flashy respectively, and also add a Trivia tag to it.

  • editc 2 b/Lee Hsien Loong -t/Trivia
    Edits the back of the 2nd flashcard to be Lee Hsien Loong, and remove its tag Trivia.

  • editc 1 o/Asia o/Australia o/Africa
    Edits the options of the 1st flashcard to be Asia, Australia and Africa. (Only if that flashcard is a MCQ flashcard).

Deleting a flashcard : deletec

You can delete cards which you no use for, this helps to declutter your card bank.
Format: deletec INDEX

  • Deletes the card at the specified INDEX.

  • The index refers to the index number shown in the most recent listing.

  • The index must be a positive integer 1, 2, 3, …​

If a tag no longer has associated flashcards, the tag will also be removed. Don’t be alarmed if some of your tags are also removed in the process!

Examples:

deletec 2
Deletes the 2nd flashcard in the list.

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.

Polymorphic flashcards

Current Implementation

Allowing different types of cards is essential to Flashy. This enables the user to add and edit a normal, MCQ or fill-in-the-blanks flashcard so that the user can learn more efficiently, and use whichever that suits his learning style.
New classes McqCard and FillBlanks were created to implement this enhancement, and they inherit the Card class, as shown in Figure 11.

ModelClassDiagramBW
Figure 1. Structure of the Model Component featuring the inheritance of McqCard and FillBlanksCard from the Card class
CardInheritanceBW
Figure 2. Class diagram featuring attributes and methods of Card, McqCard and FillBlanksCard.

Aspect: Implementation of polymorphic flashcards

  • Alternative 1 (current choice): Have a class each for MCQ and fill blanks type flashcards and let them inherit the Card class.
    MCQ flashcards have the constraint that the back of the card should be an integer between 1 and the number of options available.
    For fill blanks flashcards, the constraint is that the number of answers should be the same as the number of blanks.

    • Pros: In terms of usability, having constraints allows users to input the right arguments for different cards.

    • Cons: Additional classes have to be implemented.

  • Alternative 2: Just use a single Card class for all cards, so no constaints are set.

    • Pros: No additional classes have to be implemented. Let the user add flashcards with any arguments.

    • Cons: No constraints for the flashcards.

Adding and editing of polymorphic flashcards

Current implementation

The addc command is used to add all types of flashcards.

Design Considerations

Aspect: Implementation of add command for MCQ and fill blanks type flashcards.
  • Alternative 1 (current choice): Use addc for the adding of MCQ and fill blanks type flashcards.

    • Pros: There would be less commands to keep track of and combining the command reduces repeated codes since there are similarities between adding of normal and other type cards.
      One example of similarity is shown in the code snippet for seedu.flashy.logic.commands.AddCardCommand: executeUndoableCommand() below.

    • Cons: The add card command has to be changed which can result in undesired consequences if mistakes were made. Care has to be taken when implementing the add card feature for MCQ and fill blanks flashcards as both have constraints which cannot be violated.
      Thus the constraints have to be checked before allowing the flashcard is added, as shown in the code snippet for seedu.flashy.logic.commands.AddCardCommandParser: parse()

    public CommandResult executeUndoableCommand() throws CommandException {
            requireNonNull(model);

            try {
                model.addCard(cardToAdd);
            }
            // ... Catch exception ...

            if (tagsToAdd.isPresent()) {
                Set<Tag> tags = tagsToAdd.get();
                try {
                    model.addTags(cardToAdd, tags);
                }
                // ... Catch exception ...
            }

            // ... Return result ...

        }
    public AddCardCommand parse(String args) {
        // ...

        try {
            // ... Parse arguments ...

            if (options.isEmpty()) {
                if (FillBlanksCard.containsBlanks(front)) {
                    card = ParserUtil.parseFillBlanksCard(front, back);
                } else {
                    card = new Card(front, back);
                }
            } else {
                for (String option: options) {
                    ParserUtil.parseMcqOption(option);
                }
                card = ParserUtil.parseMcqCard(front, back, options);
                card.setType(McqCard.TYPE);
            }

            return new AddCardCommand(card, tags);
        } catch (IllegalValueException ive) {
            throw new ParseException(ive.getMessage(), ive);
        }
    }
  • Alternative 2: Implement a different addm and addf command for adding of MCQ and fill blanks type flashcard respectively.

    • Pros: No changes needs to be made to the addc command. Even if addm or addf fails, addc command can still work.

    • Cons: Less commands for developers to keep track of. It is also less efficient to have similar codes for different commands.
      If there is a change in implementation, developers would have to change code for three separate commands, which is troublesome.

Storage of flashcards

Current Implementation

The current implementation saves the flashcard data in XML format and reads it back when the card bank is loaded. A single XmlAdaptedCard class is used to convert the attributes of flashcards into XML Elements and XmlSerializableCardBank stores a list of XmlAdaptedCard.

Design Considerations

Aspect: Implementation of XmlAdaptedCard class
  • Alternative 1 (current choice): Implement a single XmlAdaptedCard class to convert all types of flashcards into XML format.

    • Pros: Flashcards would be stored in the order in which they were added.

    • Cons: XmlAdaptedCard has to be tweaked to take in the options attribute from the McqCard class, and the toModelType() method has to check for the constraints of the MCQ and fill blanks flashcard as shown in the code snippets below:
      From src.main.java.seedu.flashy.storage.XmlAdaptedCard

    public class XmlAdaptedCard {

        // ... Other attributes ...

        @XmlElement(required = true)
        private List<String> option = new ArrayList<>();

        // ... Constructors and methods ...
    }

    // ...

    public Card toModelType() throws IllegalValueException {
        // ... Check id, front, back constraints ...

        if (this.type.equals(FillBlanksCard.TYPE)) {
            if (!FillBlanksCard.isValidFillBlanksCard(this.front, this.back)) {
                // ... Catch exception ...
            }
            // ... Return card ...;
        }
        if (this.type.equals(McqCard.TYPE)) {
            if (!McqCard.isValidMcqCard(this.back, this.option)) {
                // ... Catch exception ...
            }
            // ... Return card ...
        }
        // ... Return card ...
     }
  • Alternative 2: Implementing a separate XmlAdaptedMcqCard and XmlAdaptedFillBlanksCard to convert MCQ and fill blanks flashcards into XML format respectively.
    Initially, XmlAdaptedMcqCard was implemented to inherit XmlAdaptedCard. In XmlSerializableCardBank, there would be a separate list for XmlAdaptedMcqCard, as shown in the code snippet below (which was implemented initially but later removed from source code):

    public class XmlSerializableCardBank {
        // ... Other attributes ...

        @XmlElement
        private List<XmlAdaptedCard> cards;

        // New list for XmlAdaptedMcqCards
        @XmlElement
        private List<XmlAdaptedMcqCard> mcqCards;

        /**
         * Conversion
         */
        public XmlSerializableCardBank(ReadOnlyCardBank src) {
            // ...
            for (Card card: src.getCardList()) {
                if (card.getType().equals(McqCard.TYPE)) {
                    mcqCards.add(new XmlAdaptedMcqCard(...));
                } else {
                    cards.add(new XmlAdaptedCard(...));
                }
            }
        }
        // ...
    }
  • Pros: No need to tweak XmlAdaptedCard and both classes would be separate, so mistakes in XmlAdaptedMcqCard would not affect that in XmlAdaptedCard. There’s no need to check for McqCard constraints.

  • Cons: XmlAdaptedCard and XmlAdaptedMcqCard would be stored in separate lists in XML format. When the card bank is loaded, both lists would be read separately and the order in which the cards were added would not be captured.

Use case: Add a flashcard

MSS

  1. User adds a flashcard with an associated tag

  2. CardBank adds the new flashcard

    Use case ends.

Extensions

  • 1a. The given parameters are invalid.

    Use case ends.