PROJECT: 3VIA


Overview

The purpose of this portfolio is to document my role and contributions to project 3VIA. 3VIA is a desktop flash card application designed for self-driven learners to reinforce their knowledge. The main form of interaction with the application is via the keyboard. 3 notable features are learning, testing and reviewing. This is a team-based project. My main task was to implement a mass import feature. Additionally, my assigned role was to review the code quality written by each member which is done by reviewing each member’s pull request on Github.

Summary of contributions

  • Major enhancement: added the ability to import multiple cards.

    • What it does: allows the user to add multiple cards into 3VIA at one go.

    • Justification: This feature incentivizes non-existing users to use 3VIA more as the users can import their existing digital notes quickly.

    • Highlight: This enhancement allows grouping of multiple pairs of questions and answers under a set of topics. Thereby reducing the need to repeatedly tag each question and answer pair with the same set of topics.

  • Code contributed: [Functional code]

  • Other contributions:

    • Project management:

      • Conceptualized future releases.

      • Assigned roles and responsibilities to team members.

    • Enhancements to existing features:

      • Ported list and select functions from original AddressBook to 3VIA.

    • Documentation:

      • Updated storage class diagram for 3VIA.

    • Community:

      • Reviewed PRs of team members to improve code quality.

      • Reported bugs and suggestions for team members. (examples: 1, 2, 3)

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.

Cram More Knowledge!: import

Quickly import multiple flash cards from existing notes or documents into 3VIA.

Format: import FILEPATH

Example:

  • import C:\Users\username\Desktop\file.txt
    Imports the contents from the file.txt text file from the specified file location on Windows.

  • import file.txt
    Imports the contents from the file.txt text file relative to the location of the 3VIA application.

The file path refers to either the absolute file path or the relative file path of the import file.

Creating your import file:

Open your existing notes or create a new one. You may use any text editing programs such as Microsoft Word, Google Docs, etc. Below are 2 rules regarding the import file type and format that must be adhered too.

  1. Import file type:

    • The file must be in UTF-8 format.

    • The file must be a plain text file (i.e. file.txt).

  1. Import file format:

import file format pic
Formating explaination
Keys Purpose

SPACE + t + /

A space and "t/" prefix separates each topic

TAB

A tab space separates a question and an answer

A new line separates each card

Duplicate questions in the import text file will result in an import failure. Duplicated answers with different questions are allowed.

Importing your file:

Now that your file is ready, head over to 3VIA and lets begin the import.

  1. Enter the import command followed by the absolute/ relative file path of the import file you previously created in the command box as seen below.

    import step 1 pic
  1. Hit enter/ return to confirm. 3VIA will now display a list of cards that has been imported.

    import step 2 pic
You can edit or delete any of the recently imported cards and/or even undo the import if you are not satisfied with the cards imported.

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.

Mass Import Feature

Current implementation

The import mechanism allows the user to add multiple cards quickly into 3VIA. This is done by parsing an external file in a specified format and file type but with minimal syntax.

The import mechanism is facilitated mainly by ImportFile and TriviaBundle. Additionally, the import mechanism implements the following operations:

  • ImportFile#parseFileToCard() — Parses a plain text file into a unique list of cards.

  • TriviaBundle#haveAnyCard() — Checks if the cards to add contain any duplicated cards already in TriviaBundle.

  • TriviaBundle#addMultipleCards() — Adds multiple cards into the TriviaBundle at once.

The 2 TriviaBundle operations are exposed in the Model interface as Model#haveAnyCard() and Model#addMultipleCards() respectively.

The following activity diagram summarizes what happens when a user executes the import command.

ImportCommandActivityDiagram

Given below is an example usage scenario and how the import mechanism behaves.

Step 1. The user enters the import command to import a file from an absolute or relative file path. An ImportCommand object is initialised.

Step 2. When the ImportCommand executes, the desired import file is first verified to be valid by calling ImportFile#isFileValid(). The following checks are done:

  • #isValidFile() — the import file’s path points to a file and the file is non-empty.

  • #isValidFileType() the import file is of a supported file type (i.e. plain/text file format).

  • #isValidFileFormat() the import file is readable and the text in the import file is in the specified format.

Step 3. Once verified, the import file is parsed to form a unique list of cards that is stored in UniqueCardList.

An empty UniqueCardList is also considered as an import failure as no cards were parsed from the given text file. A CommandException will be thrown, and the user is informed that no cards (question and answer pair) were found in the text file.

Step 4. TriviaBundle#haveAnyCard() checks every card in the UniqueCardList against the existing list of cards in TriviaBundle for duplicates. If duplicates are found, the import fails and a DuplicateCardException is raised.

Step 5. The UniqueCardList is then added into TriviaBundle via TriviaBundle#addMultipleCards(). The number of cards and the cards imported are displayed to the user for verification.

The sequence diagram below describes the import of multiple cards. Each card is added repeatedly by invoking TriviaBundle#add() until all cards in the UniqueCardList are added.

ImportMultipleCardsSequenceDiagram

Design Considerations

Aspect: Pre-import preview
  • Alternative 1: (current implementation) Single step to import cards from a text file.

    • Pros:

      • A single command can be executed quickly for an import.

      • Post import edits can be done using existing commands such as edit, delete, etc.

    • Con:

      • A single formatting error in the text file will result in an import failure.

  • Alternative 2: 'Stages' the import file by first previewing the imported cards to the user. Edits to the import file can be done directly to the text file within the application during this phase. The actual import is then done upon confirmation.

    • Implementation details:

      • Given below is a class diagram describing the structure for the alternative import implementation.

        AlternativeImportClassDiagram
      • The Format class verifies the formatting of the ImportFile, marks and displays the errors of the text file within the application for editing.

        The FileParser is dependent on Format to determine whether each line in the text file is a topic or a question and an answer pair. The FileParser parses the ImportFile into a UniqueCardList to be added.

        The ObservableFile interface allows the UI component to update the preview of the cards each time the file is edited without a direct dependency to it.

    • Pro:

      • Allows the user to identify errors in formatting and correct them directly in the application.

    • Con:

      • An additional step (command) is required to successfully import the cards into the application.

Aspect: How import executes
  • Alternative 1 (current choice): Store all cards to be added in TriviaBundle before writing to file on the hard disk.

    • Pro: Less IO intensive as only one write to file is needed.

    • Con: May have heap memory issue if large amount of cards are stored temporarily.

  • Alternative 2: Writes a card to a xml file after each card is added.

    • Pro: Easy to implement.

    • Con: May have performance issue when large amount of cards are added.

Aspect: How the import file is parsed
  • Alternative 1 (current choice): Tokenize strings according to defined characters between question and answer, and between cards.

    • Pro: Allows the user to undo/ redo an import as the execution of the import only executes VersionedTriviaBundle#commit() once.

    • Con: May have memory performance issue as multiple cards are stored temporarily in the TriviaBundle.

  • Alternative 2 (current choice): Tokenize strings based on the AddCommand input format.

    • Pro: Easy to implement as it allows reuse of the AddCommand functions.

    • Con: Unable to undo/ redo import of cards as the execution of the import command executes VersionedTriviaBundle#commit() multiple times. A successful undo/ redo of the import of all cards would require multiple executions of the undo/ redo command.

[Proposed] Delete Multiple Coming in v2.0

Current Implementation

The delete mechanism is facilitated by TriviaBundleParser, DeleteCommandParser, ParserUtil, DeleteCommand and Index.

Currently, DeleteCommandParser invokes ParserUtil#parseIndex() which parses a oneBasedIndex input into an Index. The DeleteCommand executes the deletion of a card using the zeroBasedIndex as specified in Index.

Proposed Enhancement

To delete a range of cards from 1 to 5, delete 1-5 will be executed. The proposed deletion of multiple cards will utilise the following operations:

  • ParserUtil#parseIndex() — takes in a one based index.

  • ParserUtil#parseMultipleIndex() — takes in a range of one based indexes in a specified format.

Both of the above methods will return a set of Index.

Given below is an example implementation of how delete 1-5 will behave at each step.

Step 1. DeleteCommandParser will determine if the given input deletes a single card or multiple cards. This can be done by determining if the input contains a -.

Step 2. In this example, ParserUtil#parseMultipleIndex() will execute and return a set of Index.

Step 3. The set of Index is used to initialise DeleteCommand.

Step 4. When DeleteCommand#execute() is invoked. A zero based index is obtained from each Index in the set. Each zero based index is then used to delete the cards, similar to the current implementation of delete.

Design Consideration

Aspect: Separate or single delete command
  • Alternative 1 (current choice): Single delete command.

    • Pro: Reduces the number of commands for the user to remember.

    • Con: Users may be unaware of this functionality being available as the name of the command does not describe deleting multiple cards.

  • Alternative 2: Separate delete command for deleting multiple cards.

    • Pro: The command will describe the action of deleting multiple cards clearly (i.e. deleteMultiple 1-5).

    • Con: There will be more commands for the user to remember.