Skip to content

Latest commit

 

History

History
2012 lines (1422 loc) · 86.2 KB

DeveloperGuide.adoc

File metadata and controls

2012 lines (1422 loc) · 86.2 KB

Fastis-Meetup Manager - Developer Guide

By: Team W15-B3 Since: February 2018 Licence: MIT

1. Introduction

FASTIS
Fastis is a desktop application which functions as an address book that aims to help students who are studying at National University of Singapore (NUS) manage their group projects effectively. The application enables students to keep track of group members’ timetables, information, meetups agendas, to-dos, and schedule suitable meetup time.

This Developer Guide is meant to provides the necessary information for developers who are interested in contributing to this application. New developers should begin with Section 2, “Setting up”. Experienced developers might want begin instead with the Section 3, “Design” section to learn more about how Fastis is structured.

Understanding the implementation of the features in Fastis will be crucial to be able to modify any feature for further improvements.

2. Setting up

This section provides information on setting up the project in order to work on Fastis.

2.1. Prerequisites

The following programs have to be installed on the computer system before setting up.

  1. JDK 1.8.0_60 or later

    ℹ️
    Having any Java 8 version is not enough.
    This app will not work with earlier versions of Java 8.
  2. IntelliJ IDE

    ℹ️
    IntelliJ by default has Gradle and JavaFx plugins installed.
    Do not disable them. If you have disabled them, go to File > Settings > Plugins to re-enable them.

2.2. Setting up the project in your computer

  1. Fork this repo, and clone the fork to your computer

  2. Open IntelliJ (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first)

  3. Set up the correct JDK version for Gradle

    1. Click Configure > Project Defaults > Project Structure

    2. Click New…​ and find the directory of the JDK

  4. Click Import Project

  5. Locate the build.gradle file and select it. Click OK

  6. Click Open as Project

  7. Click OK to accept the default settings

  8. Open a console and run the command gradlew processResources (Mac/Linux: ./gradlew processResources). It should finish with the BUILD SUCCESSFUL message.
    This will generate all resources required by the application and tests.

2.3. Verifying the setup

The following steps should be done to verify that the setup of Fastis is correct:

  1. Run the seedu.address.MainApp and try a few commands

  2. Run the tests to ensure they all pass.

2.4. Configurations to do before writing code

The following configurations should be done to ensure that Fastis future development follows good coding standards and practices.

2.4.1. Configuring the coding style

This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify,

  1. Go to File > Settings…​ (Windows/Linux), or IntelliJ IDEA > Preferences…​ (macOS)

  2. Select Editor > Code Style > Java

  3. Click on the Imports tab to set the order

    • For Class count to use import with '*' and Names count to use static import with '*': Set to 999 to prevent IntelliJ from contracting the import statements

    • For Import Layout: Ensure that the import order is import static all other imports, import java.*, import javax.*, import org.*, import com.*, import all other imports. Add a <blank line> between each import

Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.

2.4.2. Updating documentation to match your fork

After forking the repo, links in the documentation will still point to the CS2103JAN2018-W15-B3/main repo. If you plan to develop this as a separate product (i.e. instead of contributing to the CS2103JAN2018-W15-B3/main) , you should replace the URL in the variable repoURL in DeveloperGuide.adoc and UserGuide.adoc with the URL of your fork.

2.4.3. Setting up CI

You should set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.

After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).

ℹ️
Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork.

Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).

ℹ️
Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based)

2.4.4. Getting started with coding

When you are ready to start coding, get some sense of the overall design by reading Section 3.1, “Architecture”.

3. Design

This section describes how Fastis is built and how its different components interact and work with each other.

3.1. Architecture

The Architecture Diagram given below (Figure 1, “Architecture Diagram.”) explains the high-level design of Fastis. Given below is a quick overview of each component.

Architecture
Figure 1. Architecture Diagram.
💡
The .pptx files used to create diagrams in this document can be found in the diagrams folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose Save as picture.

The Main component has only one class called MainApp. It is responsible for:

  • Initializing the components in the correct sequence, and connects them up with each other during application launch.

  • Shutting down the components and invokes cleanup method where necessary during shut down.

The Commons component represents a collection of classes used by multiple other components. Two of those classes play important roles at the architecture level.

  • EventsCenter : This class (written using Google’s Event Bus library) is used by components to communicate with other components using events (i.e. a form of Event Driven design)

  • LogsCenter : This class is used by many classes to write log messages to the App’s log file.

The Database component handles the downloading of module information via the NUSmods API, as well as holding and retrieving the information. Because it is only accessed and never changed, the database component resides on its own outside of the Model component.

The rest of the App consists of these components:

UI: The UI of the App. Logic: The command executor. Model: The holder of the data of the App in-memory. Storage: The location on the hard disk where date is read from and written to.

Each of the above four components

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the Logic component (see Figure 2, “Class Diagram of the Logic Component.”) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component.

Events-Driven nature of the design

Figure 3, “Component interactions for delete 1 command (part 1).” shows how the components interact for the scenario where the user issues the command delete 1.

SDforDeletePerson
Figure 3. Component interactions for delete 1 command (part 1).
ℹ️
Note how the Model simply raises a AddressBookChangedEvent when the Address Book data are changed, instead of asking the Storage to save the updates to the hard disk.

Figure 4, “Component interactions for delete 1 command (part 2).” shows how the EventsCenter reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.

SDforDeletePersonEventHandling
Figure 4. Component interactions for delete 1 command (part 2).
ℹ️
Note how the event is propagated through the EventsCenter to the Storage and UI without Model having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct coupling between components.

The sections below give more details of each component.

3.2. UI component

The UI component handles the inputs from and the outputs to the User Interface. It consists of a MainWindow that is made up of parts e.g. CommandBox, ResultDisplay, PersonListPanel, StatusBarFooter, BrowserPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class. Refer to Figure 5, “Structure of the UI Component.”.

UiClassDiagramV1.5
Figure 5. Structure of the UI Component.

API : Ui.java

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 change.

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

3.3. Logic component

The Logic component handles the commands from user and passes the command results to the User Interface. Refer to Figure 6 and Figure 7 for class diagrams on how the Logic component is structured.

LogicClassDiagram
Figure 6. Structure of the Logic Component.
LogicCommandClassDiagram
Figure 7. Structure of Commands in the Logic Component. This diagram shows finer details concerning XYZCommand and Command in Figure 6, “Structure of the Logic Component.”.

API : Logic.java

Given below is the workflow of the Logic Component when the user inputs a command:

  1. The Logic uses the AddressBookParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a person) and/or raise events.

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

Figure 8 shows the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeletePersonSdForLogic
Figure 8. Interactions Inside the Logic Component for the delete 1 Command.

3.4. Model component

The model component stores and operates on the data held by Fastis as shown in Figure9.

ModelClassDiagram
Figure 9. Structure of the Model Component.

API : Model.java

The Model component:

  • stores a UserPref object that represents the user’s preferences.

  • stores the Address Book data.

  • exposes an unmodifiable ObservableList<Person> that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.

The model component does not depend on any of the other three components, meaning that it does not rely on any functions outside of itself to operate.

3.5. Storage component

The storage component saves processed data from Fastis on to the running machine’s hard-disk and reads from the stored data as shown in Figure 10.

StorageClassDiagram
Figure 10. Structure of the Storage Component.

API : Storage.java

The Storage component:

  • saves UserPref objects in json format and reading it back on next startup.

  • saves the Address Book data in xml format and read it back on next startup.

3.6. Database component

The Database component is in charge of connections to the web.

The Database component:

  • downloads module information from the NUSmods API.

  • retrieves modules given a NUSmods timetable link.

ℹ️
NUSmods timetable links are the sharable short URL from a NUSmods page. E.g. http://modsn.us/MYwiD

The sturucture of the Database component is shown in Figure 11

DatabaseClassDiagram
Figure 11. Structure of the Database Component.

3.7. Common classes

Classes that are used by multiple components, such as BaseEvent and JsonUtil, are defined in the seedu.addressbook.commons package.

4. Implementation

This section describes some noteworthy details on how certain features are implemented.

4.1. Undo/Redo feature

The Undo feature allows users to restore the state before the latest command while the Redo feature reverses the Undo command.

4.1.1. Current implementation

The undo/redo mechanism is facilitated by an UndoRedoStack, which resides inside LogicManager. It supports undoing and redoing of commands that modifies the state of the address book (e.g. add, edit). Such commands will inherit from UndoableCommand.

UndoRedoStack only deals with UndoableCommands. Commands that cannot be undone will inherit from Command instead. Figure 12 shows the inheritance of commands:

LogicCommandClassDiagram
Figure 12. Execution of delete command.

As you can see from Figure 12, UndoableCommand adds an extra layer between the abstract Command class and concrete commands that can be undone, such as the DeleteCommand. Note that extra tasks need to be done when executing a command in an undoable way, such as saving the state of the address book before execution. UndoableCommand contains the high-level algorithm for those extra tasks while the child classes implements the details of how to execute the specific command. Note that this technique of putting the high-level algorithm in the parent class and lower-level steps of the algorithm in child classes is also known as the template pattern.

Commands that are not undoable are implemented this way:

public class ListCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... list logic ...
    }
}

With the extra layer, the commands that are undoable are implemented this way:

public abstract class UndoableCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... undo logic ...

        executeUndoableCommand();
    }
}

public class DeleteCommand extends UndoableCommand {
    @Override
    public CommandResult executeUndoableCommand() {
        // ... delete logic ...
    }
}

Suppose that the user has just launched the application. The UndoRedoStack will be empty at the beginning.

The user executes a new UndoableCommand, delete 5, to delete the 5th person in the address book. The current state of the address book is saved before the delete 5 command executes. The delete 5 command will then be pushed onto the undoStack (the current state is saved together with the command). Refer to Figure 13 for an illustration.

UndoRedoStartingStackDiagram
Figure 13. Push of delete command into undoStack.

As the user continues to use the program, more commands are added into the undoStack (Figure 14). For example, the user may execute add n/David …​ to add a new person.

UndoRedoNewCommand1StackDiagram
Figure 14. Execution of Adding David.
ℹ️
If a command fails its execution, it will not be pushed to the UndoRedoStack at all.

The user now decides that adding the person was a mistake, and decides to undo that action using undo.

We will pop the most recent command out of the undoStack and push it back to the redoStack. We will restore the address book to the state before the add command executed (Figure 15).

UndoRedoExecuteUndoStackDiagram
Figure 15. State before the add command restored.
ℹ️
If the undoStack is empty, then there are no other commands left to be undone, and an Exception will be thrown when popping the undoStack.

Figure 16, “Sequence diagram for Undo/Redo.” shows how the undo operation works:

UndoRedoSequenceDiagram
Figure 16. Sequence diagram for Undo/Redo.

The redo does the exact opposite (pops from redoStack, pushes to undoStack, and restores the address book to the state after the command is executed).

ℹ️
If the redoStack is empty, then there are no other commands left to be redone, and an Exception will be thrown when popping the redoStack.

The user now decides to execute a new command, clear. As before, clear will be pushed into the undoStack (Figure 17). This time the redoStack is no longer empty. It will be purged as it no longer make sense to redo the add n/David command (this is the behavior that most modern desktop applications follow).

UndoRedoNewCommand2StackDiagram
Figure 17. Execution of clear command.

Commands that are not undoable are not added into the undoStack. For example, list, which inherits from Command rather than UndoableCommand, will not be added after execution (as shown in Figure 18):

UndoRedoNewCommand3StackDiagram
Figure 18. Execution of list command, which will not be added to undoStack after execution.

Figure 19, “Activity diagram of undo/redo.” summarize what happens inside the UndoRedoStack when a user executes a new command:

UndoRedoActivityDiagram
Figure 19. Activity diagram of undo/redo.

4.1.2. Design Considerations

The following considerations were taken into account during the design of this feature.

Aspect: Implementation of UndoableCommand
  • Alternative 1 (current choice): Add a new abstract method executeUndoableCommand()

    • Pros: This implementation preserves undo/redo functionality as it is now part of the default behaviour. Classes that deal with Command do not have to know that executeUndoableCommand() exist.

    • Cons: This implementation makes it hard for new developers to understand the template pattern.

  • Alternative 2: Just override execute()

    • Pros: This implementation does not involve the template pattern, and is easier for new developers to understand.

    • Cons: This implementation makes it so that classes that inherit from UndoableCommand must remember to call super.execute(), or lose the ability to undo/redo.

Aspect: How undo & redo executes
  • Alternative 1 (current choice): Saves the entire address book.

    • Pros: This implementation is easy to implement.

    • Cons: This implementation may have performance issues in terms of memory usage.

  • Alternative 2: Individual command knows how to undo/redo by itself.

    • Pros: This implementation uses less memory (e.g. for delete, just save the person being deleted).

    • Cons: This implementation reduces leeway for error and forces developers to ensure that the implementation of each individual command are correct.

Aspect: Type of commands that can be undone/redone
  • Alternative 1 (current choice): Only include commands that modifies the AddressBook.

    • Pros: This implementation only reverts changes that are hard to change back (the view can easily be re-modified as no data are * lost).

    • Cons: This implementation might confuse users as to whether the command also works when the list is modified (undoing filtering for example).

  • Alternative 2: Include all commands.

    • Pros: This implementation might be more intuitive for the user.

    • Cons: This implementation makes it harder for users who only want to revert changes to AddressBook. Additional Info: See our discussion here.

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (current choice): Use separate stack for undo and redo

    • Pros: This implementation is easy to understand for new Computer Science undergraduates to understand, who are likely new developers.

    • Cons: This implementation duplicates Logic. For example, when a new command is executed, both HistoryManager and `UndoRedoStack`must be update.

  • Alternative 2: Use HistoryManager for undo/redo

    • Pros: This implementation just reuses what is already in the codebase.

    • Cons: This implementation violates Single Responsibility Principle and Separation of Concerns as HistoryManager now needs to undo commands on top of keeping track of them.

4.2. Module database feature

The database feature enables Fastis to store and quickly find lesson schedules.

4.2.1. Current implementation

Fastis uses the available NUSmods API to retrieve module information from the API server.

The sequence diagram (Figure 20) for the instantiation of DatabaseManager is shown below.

DatabaseComponentSequenceDiagram
Figure 20. Sequence diagram for the instantianion of DatabaseManager.

On startup, the network component makes a connection to the API server and checks the lastmodified field of the JSON file on the server. If the lastmodified date is more recent that the JSON file held in storage, the network component will download and overwrite the existing file on disk.

The Storage component then converts the JSON file into a hashMap of modules to be held in the Database component.

4.2.2. Design Considerations

Aspect: Storage of Module information
  • Alternative 1 (current choice): Store a complete dataset of all modules

    • Pros: This implementation allows Fastis to access information even when used offline.

    • Cons: This implementation requires more memory space.

  • Alternative 2: Store nothing, retrieve only module information of single module each time.

    • Pros: This implementation does not require any storage space.

    • Cons: This implementation requires Fastis to constantly download information from the web, making the app reliant on good internet connection.

4.3. Calendar feature

Fastis uses a stand-alone Calendar class, adapted from javafx-calendar by SirGoose3432. It is used to view the user’s upcoming events, e.g. interviews, meetings, etc.

4.3.1. Current implementation

The calendar feature is facilitated by Calendar and CalendarDate classes, both of which reside inside Ui component. Their sole purpose is to draw out the calendar in the application when given a list of Event objects.

The calendar is drawn/redrawn whenever a CalendarChangedEvent is raised. The flow of operation thereafter is shown is Figure 21 below.

CalendarSequenceDiagram
Figure 21. Sequence diagram for CalendarChangedEvent

Calendar utilizes the Event class to determine which slots in the schedule are occupied. Hence, a list of events is passed to every calendar upon construction and saved as a private variable.

The details of these event, e.g. time, location, are saved locally in .xml file format. It is also retrieved upon start up by the Storage component and saved within the Model for the whole process.

The implementation of Calendar is as follows:

public Calendar(ObservableList<Event> eventList) {
    super(FXML);
    // ... Assigning class fields ...
    initCalendar();
    registerAsAnEventHandler(this);
}

private void initCalendar() {
    // ... Create the calendar 7x6 GridPane ...
    // ... Construct 42 CalendarDate objects ...
    fillCalendar(currentYearMonth);
    showEvents();
    // ... show CalendarView ...
}

private void fillCalendar(YearMonth yearMonth) {
    // ... Fill the calendar with the correct dates according to yearMonth ...
}

private void showEvents() {
    // ... Show all events that are in the current yearMonth in the eventList ...
}

The current time is retrieved upon startup, and the calendar base on that point in time to display the appropriate time frame.

4.3.2. Design Considerations

Aspect: Implementation of the Calendar
  • Alternative 1 (current choice): Implement a stand-alone Calendar class

    • Pros: This implementation makes data manipulation and appearance customizing easy.

    • Cons: This implementation might lack functionalities available in external libraries.

  • Alternative 2: Import external libraries/API

    • Choices:

    • Pros: This implementation would be likely be optimized and have more functionalities.

    • Cons: This implementation restricts developers to what the libraries offer, and require a firm understanding of these external APIs.

Aspect: Storing of the eventList
  • Alternative 1 (current choice): Stores the eventList within the Calendar object.

    • Pros: This implementation makes it easy to show events and their details, even after the constructor returns.

    • Cons: This implementation takes up some memory even if there are no commands for showing these events.

  • Alternative 2: Only passes the eventList as a parameter to the constructor and not storing it as a field within the Calendar object.

    • Pros: This implementation uses less memory and makes code less cluttered.

    • Cons: This implementation makes it hard to show events and their details outside of the constructor.

4.4. Timetable feature

Fastis uses a stand-alone Timetable class, based largely on the Calendar class. It is used to view the user’s own NUSMods timetable as well as that of other people in his address book.

4.4.1. Current implementation

The timetable is the weekly equivalent to the monthly Calendar. This feature is similarly facilitated by the analogous Timetable and TimetableSlot classes, both of which reside inside Ui component. Their sole purpose is to draw out the timetable in the application when given a list of WeeklyEvent objects.

The calendar is drawn/redrawn whenever a TimetableChangedEvent is raised. This is done either by a precedent PersonPanelSelectionChangedEvent or a ScheduleGroupCommand. The flow of operation thereafter is shown Figure 22 below.

TimetableSequenceDiagram
Figure 22. Sequence diagram for TimetableChangedEvent

The implementation of Timetable is as follows:

public Timetable(ObservableList<WeeklyEvent> eventList) {
    super(FXML);
    // ... Assigning class fields ...
    initTimetable();
    registerAsAnEventHandler(this);
}

private void initTimetable() {
    // ... Create the calendar 6x11 GridPane ...
    // ... Construct 66 TimetableSlot objects ...
    clearTimetable();
    showSlots();
    // ... show TimetableView ...
}

private void clearTimetable() {
    // ... Draw all slots as blank ...
    // ... Draw the timeline on the left ...
}

private void showSlots() {
    // ... Show all slots that are in the in the eventList ...
    // ... Make sure no 2 modules with different name would have the same color ...
}

4.4.2. Design Considerations

Aspect: Implementation of the Timetable and Storing of the eventList

As the weekly equivalent of Calendar, Timetable has the same aspect to consider. See Implementation of the Calendar.

Aspect: Supporting modules on weekends and/or after 6pm
  • Alternative 1 (current choice): Don’t support showing those modules

    • Pros: This implementation makes the GUI less cluttered and more readable

    • Cons: This implementation cannot cater to users with modules outside these times. Users cannot schedule events on weekends.

  • Alternative 2: Support showing those modules

    • Pros: This implementation caters to users with those modules, and support scheduling for the weekends.

    • Cons: This implementation makes the GUI look cluttered, as the GUI already has other main components.

4.5. Showing the timetable

This feature allows users to see a person’s timetable by selecting him/her.

4.5.1. Current implementation

When a person is selected, either by the select command or by mouse click via the GUI, a PersonPanelSelectionChangedEvent is raised. The flow of operation thereafter is shown Figure 23 below.

nusModsSequenceDiagram
Figure 23. Sequence digaram for PersonPanelSelectionChangedEvent.

Upon receiving the event, the UI component takes the Person within the PersonPanelSelectionChangedEvent and calls the parseEvents() method of DataBaseManager, passing the TimetableLink of the Person as an argument.

The result of the parseEvents() is an ArrayList of WeeklyEvents. This result is used to form a TimeTableChangedEvent, which ultimately tells the UI component to display the result.

The implementation of parseEvents() is as follows:

public static ArrayList<WeeklyEvent> parseEvents(TimeTableLink link) {
        ArrayList<WeeklyEvent> eventList = new ArrayList<>();

        if (!isCurrentSem(link)) {
           // ... display and log warning messages ...
        }

        String query = getQuery(link);

       // ... parse query into WeeklyEvents ...

        return eventList;
    }

The parseEvents() method firsts checks if the TimetableLink points to a schedule that is in the same semester as Fatis' database. It then calls the getQuery helper method, which a URLconnection to the shortened URL in TimetableLink and returns the query part of the full-length URL.

The method then takes the query and parses them into modules and lessons, which are used to form WeeklyEvents.

4.5.2. Design Considerations

Aspect: Storage of a person’s schedule
  • Alternative 1 (current choice): Store only the link to a NUSmods page for each person

    • Pros: This implementation requires very little space. The schedule of a person can easily be changed by editing the TimetableLink.

    • Cons: This implementation requires Fastis to make a connection to the web each time a person is selected.

  • Alternative 2: Store the schedule of each person in the AddressBook

    • Pros: This implementation will require much more space, and there will be a dilemma between whether to store it as WeeklyEvent, or Module and schedule

    • Cons: This implementation requires Fastis to make a connection to the web only when a person is added or edited.

4.6. Schedule meetings feature

Fastis supports showing all the common free time slots for all members in based on their timetable.

4.6.1. Current implementation

Fastis utilizes a few components to schedule the meetings, namely the Group class and WeeklyEvent class in Model, Timetable in UI, and parseEvents() in Database. The command to show the scheduled meetings is ScheduleGroupCommand, which resides in Logic component.

When a ScheduleGroupCommand is executed, it first gets all group members from Model. For each member, it parses the TimetableLink to get all of his/her modules, and add them to an occupied list. From that list, the command generates all free time slots in another list called free, and post that event to be handled by the UI component later.

The flow of operation is shown in Figure 24 below.

ScheduleGroupSequenceDiagram
Figure 24. Sequence diagram for ScheduleGroupCommand().

The implementation of ScheduleGroupCommand is as follows:

public ScheduleGroupCommand(Group group) {
    requireNonNull(group);
    // ... Assigning class fields ...
    EventsCenter.getInstance().registerHandler(this);
}

public CommandResult execute() throws CommandException {
    // ... Get the group's member from Model ...
    fillTimeSlots(group);
    generateFreeTimeSlots();
    // ... Post new TimetableChangedEvent ...
    // ... Return new CommandResult ...
}

private void fillTimeSlots(Group group) {
    for (Person member : group.getPersonList()) {
        // ... Parse the TimetableLink into moduleList
        // ... Add all modules in moduleList to occupied list
    }
}

private void generateFreeTimeSlots() {
    // ... Generate free time slots logic
}

4.6.2. Design Considerations

Aspect: Scheduling algorithm
  • Alternative 1 (current choice): Show all free time slots

    • Pros: This implementation is intuitive for users, and easy to read.

    • Cons: This implementation slow, as there are a few extra steps to process.

  • Alternative 2: Show all occupied time slots

    • Pros: This implementation is very fast.

    • Cons: This implementation could make GUI cluttered as there are normally more occupied slots than free slots. Also, it might not be intuitive for users.

4.7. List Tag Members feature

Fastis lists all persons in Fastis that have tags similar to input.

4.7.1. Current implementation

Fastis uses ListTagMembersCommand, which resides under Logic to facilitate the listing of members under the same tag. Figure 25 shows the sequence diagram of the listTagMembers command

listTagMemberSequenceDiagram
Figure 25. Sequence diagram of listTagMembers command.

When user types in command line listTagMembers or lTM , Fastis will use the keyword provided to search for the tag and list out all members with the same tag.

4.7.2. Design Considerations

  • Alternative 1 (current choice): Add a new command listTagMembersCommand() to list out the members with same tag.

    • Pros: This implementation makes it is easy to change the methods called by command.

    • Cons: This implementation requires users and developers to remember more commands.

  • Alternative 2: Change existing find command to include finding person with same tags.

    • Pros: This implementation can reduce number of commands required to be remembered.

    • Cons: This implementation can affect the functionality of existing commands.

4.8. Add Group feature

Fastis has a group feature that can:

  • add a group with information that was stated by user input.

  • delete a group with information that was stated by user input.

  • add a person into the group with information that was stated by user input.

  • delete a person from the group with information that was stated by user input.

  • list all the members in the group with information that was stated by user input.

4.8.1. Current implementation

The group mechanism is facilitated by UniqueGroupList, which resides inside Model component. Address book stores all groups in UniqueGroupList. The groups in the group list are facilitated by Group class. Each Group object have a Information object, representing the information of the group. Group,Information and UniqueGroupList class reside inside Model component. Figure 26 is the class diagram showing the relationship between Group, Information and UniqueGroupList:

GroupClassDiagram
Figure 26. Group Class Diagram.

Figure 27 is a object diagram of Group Class.

GroupObjectDiagram
Figure 27. Object Diagram of Group.

Suppose that the user has just launched the application . The UniqueGroupList in the address book will include few groups that are declared in SampleDataUtil.

A Group consists of the following:

  • Information: Represents the information of the group.

  • PersonList: Represents the list of persons in a group.

The add group feature adds a group with information named by user in input into Fastis.

The add group mechanism is facilitated by AddGroupCommand, which resides inside Logic component. It supports adding Group object to the address book. AddGroupCommand inherits from UndoableCommand.

Hence, AddGroupCommand can be undone using UndoRedoStack. With the extra layer, the AddGroupCommand that is undoable is implemented this way:

public abstract class UndoableCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... undo logic ...

        executeUndoableCommand();
    }
}

public class AddGroupCommand extends UndoableCommand {
    @Override
    public CommandResult executeUndoableCommand() {
        // ... AddGroup logic ...
    }
}

Figure 28 shows the interaction of AddGroup Command class.

width:"600"
Figure 28. Class Diagram of add group Command.

The user executes a new AddGroupCommand with Information, to add a new group to the address book. The new group is added to the UniqueGroupList and the current state of the address book is saved.

The AddGroupCommand is facilitated by AddGroupCommandParser to parse AddGroupCommand. Figure 29 shows the flow of parsing of AddGroupCommand object.

AddGroupParserSequenceDiagram
Figure 29. Sequence Diagram for AddGroupParser.

Figure 30 diagram shows how the add group operation works:

AddGroupSequenceDiagram
Figure 30. AddGroup Sequence Diagram.

4.8.2. Design Considerations

Aspect: Implementation of AddGroupCommand
  • Alternative 1 (current choice): Add a new command method AddGroupCommand()

    • Pros: This implementation makes it easy for developers to modify method to suit what they want

    • Cons: This implementation requires users and developers to remember more commands.

  • Alternative 2: Add a new abstract method executeAddGroupCommand()

    • Pros: This implementation preserves addGroup functionality as it is now part of the default behaviour. Classes that deal with AddGroupCommand do not have to know that executeAddGroupCommand() exist.

    • Cons: This implementation makes it hard for new developers to understand the template pattern.

4.9. Add Member To Group feature

Fastis adds a person from the existing contact list to an existing group.

4.9.1. Current implementation

The add member to group mechanism is facilitated by AddMemberToGroupCommand, which resides inside Logic component. It supports adding a member to Group objects to the address book. AddMemberToGroupCommand inherits from UndoableCommand.

Hence, AddMemberToGroupCommand can be undone using UndoRedoStack. With the extra layer, the AddGroupCommand that is undoable is implemented this way:

public abstract class UndoableCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... undo logic ...

        executeUndoableCommand();
    }
}

public class AddMemberToGroupCommand extends UndoableCommand {
    @Override
    public CommandResult executeUndoableCommand() {
        // ... AddMemberToGroup logic ...
    }
}

The list of members in the group list are facilitated by Group class. Each Group object have a UniquePersonList object, representing the list of persons in the group. Address book stores all members added to the group using XmlAdaptedPersons as person object storage as shown in the following sequence diagram where the storage saves to file in XmlAdaptedGroups. Fastis will then handle addressBookChangedEvent and update command result.

Figure 31 shows the interaction of AddMemberToGroup Command class.

width:"600"
Figure 31. Class Diagram of AddMemberToGroup Command.

The AddMemberToGroupCommand is facilitated by AddMemberToGroupCommandParser to parse AddMemberToGroupCommand. Figure 32 shows the flow of parsing of AddMemberToGroupCommand object.

aGMParserSequenceDiagram
Figure 32. Sequence diagram for AddMemberToGroupCommandParser.

Figure 33 diagram shows how the addMembersToGroup operates.

aGMSequenceDiagram
Figure 33. AddMemberToGroup sequence diagram.

4.9.2. Design Considerations

Aspect: Implementation of AddMemberToGroupCommand
  • Alternative 1 (current choice): Add a new command method AddMemberToGroupCommand().

    • Pros: This implementation makes it easy for developers to modify method to suit what they want.

    • Cons: This implementation requires users and developers to remember more commands.

  • Alternative 2 : Add a new interface EditGroupMemberCommand() to handle adding members to group.

    • Pros: This implementation does not require a new command to be created.

    • Cons: This implementation is less flexible.

4.10. Delete Member From Group feature

Fastis deletes a person from the existing contact list to an existing group.

4.10.1. Current implementation

The delete member from groups mechanism is facilitated by DeleteMemberFromGroupCommand, which resides inside Logic component. It supports deleting a member to Group objects to the address book. DeleteMemberFromGroupCommand from UndoableCommand.

Hence, DeleteMemberFromGroupCommand can be undone using UndoRedoStack. With the extra layer, the AddGroupCommand that is undoable is implemented this way:

public abstract class UndoableCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... undo logic ...

        executeUndoableCommand();
    }
}

public class DeleteMemberFromGroupCommand extends UndoableCommand {
    @Override
    public CommandResult executeUndoableCommand() {
        // ... DeleteMemberFromGroup logic ...
    }
}

The list of members in the group list are facilitated by Group class. Each Group object have a UniquePersonList object, representing the list of persons in the group. Address book stores all members added to the group using XmlAdaptedPersons as person object storage. The DeleteMemberFromGroupCommand will retrieve the input, which is the index of the person of the last updated person list, and deletes that person from the list if the person exists in the UniquePersonList in the specified group. Fastis will then handle addressBookChangedEvent and update command result.

Figure 34 shows the interaction of DeleteMemberFromGroup Command class.

width:"600"
Figure 34. Class Diagram of DeleteMemberFromGroup Command.

The DeleteMemberFromGroupCommand is facilitated by DeleteMemberFromGroupCommandParser to parse DeleteMemberFromGroupCommand. Figure 35 shows the flow of parsing of DeleteMemberFromGroupCommand object.

dGMParserSequenceDiagram
Figure 35. Sequence diagram for DeleteMemberFromGroupCommandParser.

Figure 36 diagram shows how the deleteMembersFromGroup operates.

dGMSequenceDiagram
Figure 36. Sequence diagram for DeleteMemberFromGroupCommand.

4.10.2. Design Considerations

Aspect: Implementation of DeleteMemberToGroupCommand
  • Alternative 1 (current choice): Add a new command method DeleteMemberFromGroupCommand()

    • Pros: This implementation is easy for developers to modify method to suit what they want.

    • Cons: This implementation requires users and developers to remember more commands.

  • Alternative 2 : Add a new interface EditGroupMemberCommand().

    • Pros: This implementation does not require a new command to be created.

    • Cons: This implementation is less flexible.

4.11. List Group Members Feature

Fastis lists all persons under the group keyed by user.

4.11.1. Current implementation

Fastis uses ListGroupMembersCommand ,which resides under Logic to facilitate the listing of members under the same group.

When user types in command line listGroupMembers or lGM , Fastis will use the keyword provided to search for the group and list out all members under the specified group in the PersonListPanel.

The ListGroupMembersCommand is facilitated by ListGroupMembersCommandParser to parse ListGroupMembersCommand. Figure 37 shows the flow of parsing of ListGroupMembersCommand object.

ParserlGMSequenceDiagram
Figure 37. Sequence diagram for ListGroupMemberCommandParser.

Figure 38 diagram shows how ListGroupMembersCommand operates.

lGMSequenceDiagram
Figure 38. Sequence diagram for ListGroupMembers.

4.11.2. Design Considerations

Aspect: Implementation of ListGroupMembersCommand
  • Alternative 1 (current choice): Use a command to list out the members with same group.

    • Pros: This implementation makes the methods called by command easily modifiable.

    • Cons: This implementation requires users and developers to remember more commands.

  • Alternative 2: Add a new abstract method ListGroupMembersCommand()

    • Pros: This implementation makes it easy to edit ListGroupMembersCommand() easily to suit our needs

    • Cons: This implementation makes it hard for new developers to understand the template pattern.

4.12. Delete Group feature

Fastis deletes a group named by the user from input.

4.12.1. Current implementation

The delete groups mechanism is facilitated by DeleteGroupCommand, which resides inside Logic component. It supports deleting Group objects to the address book. DeleteGroupCommand inherits from UndoableCommand.

Hence, DeleteGroupCommand can be undone using UndoRedoStack. With the extra layer, the DeleteGroupCommand that is undoable is implemented this way:

public abstract class UndoableCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... undo logic ...

        executeUndoableCommand();
    }
}

public class DeleteGroupCommand extends UndoableCommand {
    @Override
    public CommandResult executeUndoableCommand() {
        // ... DeleteGroup logic ...
    }
}

The user executes a new DeleteGroupCommand with Information, to delete a existing group with the same information to the address book. The group is deleted from the UniqueGroupList and the current state of the address book is saved. Fastis will then handle addressBookChangedEvent and update command result.

Figure 39 shows the interaction of DeleteGroup Command class.

width:"600"
Figure 39. Class Diagram of DeleteGroup Command.

The DeleteGroupCommand is facilitated by DeleteGroupCommandParser to parse DeleteGroupCommand. Figure 40 shows the flow of parsing of DeleteGroupCommand object.

dGParserSequenceDiagram
Figure 40. Sequence diagram for DeleteGroupCommandParser.

Figure 41 shows how the deleteGroup operation works:

dGSequenceDiagram
Figure 41. Sequence diagram for DeleteGroupCommand.

4.12.2. Design Considerations

Aspect: Implementation of DeleteGroupCommand
  • Alternative 1 (current choice): Add a new command method deleteGroupCommand()

    • Pros: This implementation makes it easy for developers to modify method to suit what they want

    • Cons: This implementation requires users and developers to remember more commands.

  • Alternative 2: Add a new abstract method executeDeleteGroupCommand()

    • Pros: This implementation preserves deleteGroup functionality as it is now part of the default behaviour. Classes that deal with DeleteGroupCommand do not have to know that executeDeleteGroupCommand() exist.

    • Cons: This implemetation makes it hard for new developers to understand the template pattern.

4.13. Tag Color feature

Fastis supports changing the color of the tags given to people in the address book. There are up to 17 colors to choose from.

4.13.1. Current implementation

Changing a tag’s color is facilitated by ChangeTagColorCommand, which resides inside Logic component. It supports modifying the color field within Tag objects.

The flow of operation is shown the Figure 42 below.

ChangeTagColorSequenceDiagram
Figure 42. Sequence Diagram for ChangeTagColor.`

ChangeTagColorCommand inherit from UndoableCommand, therefore it can be undone and redone using UndoRedoStack.

The implementation of ScheduleGroupCommand is as follows:

public abstract class UndoableCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... undo logic ...

        executeUndoableCommand();
    }
}

public class ChangeTagColorCommand extends UndoableCommand {
    @Override
    protected void preprocessUndoableCommand() throws CommandException {
        // .. Get the tag's name and color from Model
    }

    @Override
    public CommandResult executeUndoableCommand() {
        // ... Update tag in Model ...
        // ... Update Person list in Model ...
        // ... Return new CommandResult ...
    }
}

4.13.2. Design Considerations

Aspect: Colouring the tags
  • Alternative 1 (current choice): Allow different tags with the same color

    • Pros: This implementation allows users to have more freedom.

    • Cons: This implementation might result in aesthetically unpleasing GUI.

  • Alternative 2: Disallow different tags with the same color

    • Pros: This implementation is more intuitive.

    • Cons: This implementation makes the code longer.

4.14. Add ToDo feature

Adds a to-do.

4.14.1. Current implementation

The add to-dos mechanism is facilitated by AddToDoCommand, which resides inside Logic component. It supports adding ToDo objects to the address book. AddToDoCommand inherits from UndoableCommand.

Hence, AddToDoCommand can be undone using UndoRedoStack. With the extra layer, the AddToDoCommand that is undoable is implemented this way:

public abstract class UndoableCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... undo logic ...

        executeUndoableCommand();
    }
}

public class AddToDoCommand extends UndoableCommand {
    @Override
    public CommandResult executeUndoableCommand() {
        // ... add to-do logic ...
    }
}

The to-dos in the to-do list are facilitated by ToDo class. Each ToDo object have a Content object and a Status object, representing the content and status of the to-do. Address book stores all to-dos in UniqueToDoList. ToDo,Content and UniqueToDoList class reside inside AddressBook. Figure 43 is the class diagram showing the relationship between ToDo,Content, Status, UniqueToDoList and AddressBook:

AddressBookUniqueToDoListToDoClassDiagram
Figure 43. Class Diagram for UniqueToDoList.

On a smaller scale, Figure 44 is a class diagram showing the relationship between ToDo,Content and Status:

ToDoStatusContentClassDiagram
Figure 44. Class Diagram for To-Do.

Suppose that the user has just launched the application. The UniqueToDoList in the address book will be empty if no to-dos have been added previously.

The user executes a new AddToDoCommand with Content, to add a new to-do to the address book. The Status of the to-do is "undone" by default. The new to-do with content and status is added to the UniqueToDoList and the current state of the address book is saved. Figure 45 shows how the addToDo operation works:

AddToDoSequenceDiagram
Figure 45. Sequence Diagram for addToDo.

4.14.2. Design Considerations

Aspect: Implementation of AddToDoCommand
  • Alternative 1 (current choice): Restrict the constructor of ToDo to be ToDo(Content content, Status status)`

    • Pros: This implementation allows ToDo class to be easier to maintain and debug.

    • Cons: This implementation requires extensive refactor of existing tests.

4.15. Check/UnCheck ToDo feature

Checks or unchecks a To-do

4.15.1. Current implementation

The check/uncheck to-dos mechanism is facilitated by CheckToDoCommand and UnCheckToDoCommand, which resides inside Logic component. It supports modifying Status objects within ToDo objects. CheckToDoCommand and UnCheckToDoCommand inherit from UndoableCommand.

Hence, CheckToDoCommand and UnCheckToDoCommand can be undone using UndoRedoStack.

Similar to Content object, each ToDo object have a Status object, representing the status of the to-do. The status of a to-do can be either done or undone.

When user check/uncheck an existing to-do of specific Index, a new ToDo is created, with the existing ToDo’s `Content and appropriate new Status.

The existing to-do is replaced by the new to-do in the UniqueToDoList and the current state of the address book is saved. Figure 46 shows how the checkToDo operation works:

CheckToDoSequenceDiagram
Figure 46. Sequence Diagram for checkToDo.

Figure 47 shows how the unCheckToDo operation works:

UnCheckToDoSequenceDiagram
Figure 47. Sequence Diagram for unCheckToDo.

4.15.2. Design Considerations

Aspect: Implementation of CheckToDoCommand and UnCheckToDoCommand
  • Alternative 1 (current choice): Add a new method setStatus(Status newStatus) in ToDo

    • Pros: This implementation do not require a new ToDo object to be created to replace the existing to-do.

    • Cons: This implementation does not follow the Single Responsibility Principle.

4.16. Edit ToDo feature

Edits a To-do.

4.16.1. Current implementation

The edit to-dos mechanism is facilitated by EditToDoCommand, which resides inside Logic component. It supports modifying Content objects within ToDo objects. EditToDoCommand inherit from UndoableCommand.

Hence, EditToDoCommand can be undone using UndoRedoStack.

When user edit an existing to-do of specific Index, a new ToDo is created, with the new Content and a new Status of "undone" value.

The existing to-do is replaced by the new to-do in the UniqueToDoList and the current state of the address book is saved. Figure 48 shows how the editToDo operation works:

EditToDoSequenceDiagram
Figure 48. Sequence Diagram for EditToDo.

4.16.2. Design Considerations

Aspect: Implementation of EditToDoCommand
  • Alternative 1 (current choice): Add a new method setContentAndStatus(Content content, Status newStatus) in ToDo

    • Pros: This implementation do not require a new ToDo object to be created to replace the existing to-do.

    • Cons: This implementation does not follow the Single Responsibility Principle.

4.17. Delete ToDo feature

Deletes a To-Do.

4.17.1. Current implementation

The delete to-dos mechanism is facilitated by DeleteToDoCommand, which resides inside Logic component. It supports deleting ToDo objects. DeleteToDoCommand inherit from UndoableCommand.

Hence, DeleteToDoCommand can be undone using UndoRedoStack.

When user delete an existing to-do of specific Index, the UniqueToDoList within AddressBook is updated and stored in the StorageManager.

Figure 49 shows how the deleteToDo operation works:

DeleteToDoSequenceDiagram
Figure 49. Sequence Diagram for DeleteToDo.

4.18. Logging

Fastis uses the java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations:

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 4.19, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Listed below are the different logging levels:

  • SEVERE : Critical problems detected which may possibly cause the termination of the application

  • WARNING : Non-Critical problems that allows the application to continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

4.19. Configuration

Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file (default: config.json).

5. Documentation

This section provides necessary information for developers to edit and publish related documentations, such as User Guide and Developer Guide, for Fastis.

Fastis uses asciidoc for documentation.

ℹ️
Asciidoc is chosen over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting.

5.1. Editing documentation

See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits. Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.

5.2. Publishing documentation

See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.

5.3. Converting documentation to PDF format

The project uses Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.

Here are the steps to convert the project documentation files to PDF format.

  1. Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the docs/ directory to HTML format.

  2. Go to your generated HTML files in the build/docs folder, right click on them and select Open withGoogle Chrome.

  3. Within Chrome, click on the Print option in Chrome’s menu.

  4. Set the destination to Save as PDF, then click Save to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.

chrome save as pdf
Figure 50. Saving documentation as PDF files in Chrome

6. Testing

This section documents how to run the tests on Fastis.

6.1. Running tests

There are three ways to run tests.

Method 1: Using Gradle in headless mode (recommended)

Thanks to the TestFX library we use, our GUI tests can be run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means the developer can do other things on the Computer while the tests are running.

To run tests in headless mode, open a console and run the command gradlew clean headless allTests (Mac/Linux: ./gradlew clean headless allTests)

💡
The above-mentioned method is the most reliable. The other two listed below might fail some GUI tests due to platform/resolution-specific idiosyncrasies.

Method 2: Using Gradle

Using Gradle without the headless mode will cause GUI tests to show up on screen. The test functions will simulate mouse movement and keyboard keystrokes, and tests might fail if you move your mouse or type anything on the keyboard. Thus during the GUI tests it is recommended that you leave your machine alone.

To run the tests, open a console and run the command gradlew clean allTests (Mac/Linux: ./gradlew clean allTests)

ℹ️
See UsingGradle.adoc for more info on how to run tests using Gradle.

Method 3: Using IntelliJ JUnit test runner

Using this method, GUI tests will also show up on screen, and will require you to stop mouse and keyboard activity in order to run successfully.

This method requires you to have the project open on IntelliJ:

  • To run all tests, right-click on the src/test/java folder and choose Run 'All Tests'

  • To run a subset of tests, you can right-click on a test package, test class, or a test and choose Run 'ABC'

6.2. Types of tests

Fastis has two types of tests:

  1. GUI Tests - These are tests involving the GUI. They include,

    1. System Tests that test the entire App by simulating user actions on the GUI. These are in the systemtests package.

    2. Unit tests that test the individual components. These are in seedu.address.ui package.

  2. Non-GUI Tests - These are tests not involving the GUI. They include,

    1. Unit tests targeting the lowest level methods/classes.
      e.g. seedu.address.commons.StringUtilTest

    2. Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
      e.g. seedu.address.storage.StorageManagerTest

    3. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
      e.g. seedu.address.logic.LogicManagerTest

6.3. Troubleshooting testing

Problem: HelpWindowTest fails with a NullPointerException.

  • Reason: One of its dependencies, UserGuide.html in src/main/resources/docs is missing.

  • Solution: Execute Gradle task processResources.

7. Dev Ops

7.1. Build automation

See UsingGradle.adoc to learn how to use Gradle for build automation.

7.2. Continuous integration

We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.

7.3. Coverage reporting

We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.

7.4. Documentation previews

When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged. See UsingNetlify.adoc for more details.

7.5. Making a release

Here are the steps to create a new release.

  1. Update the version number in MainApp.java.

  2. Generate a JAR file using Gradle.

  3. Tag the repo with the version number. e.g. v0.1

  4. Create a new release using GitHub and upload the JAR file you created.

7.6. Managing dependencies

A project often depends on third-party libraries. For example, Address Book depends on the Jackson library for XML parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives.
a. Include those libraries in the repo (this bloats the repo size)
b. Require developers to download those libraries manually (this creates extra work for developers)

Appendix A: Product Scope

Target user profile: NUS students with group projects that:

  • Have a number of events to keep track of. For example:

    • Group meetings,

    • Career Fair,

    • Interviews,

    • Consultations,

      etc.

  • Prefer desktop apps over other types.

  • Can type fast.

  • Prefer typing over mouse input.

  • Are reasonably comfortable using CLI apps.

Value proposition: Help students manage the humongous amount of events that they might have.

Feature contribution:

  • Personal To-do list (MAJOR):

    • User can add to-dos, notes, upcoming tasks and organize them in a to-do list.

    • To-do list serves to remind the user of important tasks, events in group projects.

  • Meetup Time Generator (MAJOR):

    • Generator parses information from persons' NUSMods timetables and generate a suitable project meetup time.

    • Meetup Time Generator allows user to quickly decide meetup time without manually checking timetables.

  • Meetup Calendar (MAJOR):

    • User can add meetups with specific start, end time and display meetups on the calendar.

    • Meetup Calendar allows user to visualise and remember upcoming group events/meetups.

  • Organize persons in groups (MAJOR):

    • User can store specific persons in project groups.

    • User can have a group list and display persons in each group.

    • Groups allows user to manage persons based on the project groups they belongs to.

  • Detail field for a person (Minor):

    • Details for a person are additional information such as remark, hobbies, comments, etc.

    • Detail allows user to add information that does not fall under categories such as phone, email, etc.

    • Detail allows storing person information to become more flexible.

  • Timetable link field for a person (Minor):

    • Timetable link for person is an NUSMods website link.

    • Timetable link displays the actual link of NUSMods website shown when a person is selected.

    • Timetable link allows the user to manage NUSMods link of a person.

  • Customizable tags' color (Minor):

    • User can set color of specific tags.

    • Customizable tags' color allows user to better personalise the application.

  • Dark color theme for application bar and background (Minor):

    • Application bar and background are changed to dark grey color.

    • Dark color theme makes the application comfortable to use in different light conditions.

Appendix B: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

Student with group project

Add person with project group tag

I know which person belongs to which project groups

* * *

Student that is finished with a group project

Delete the group tag of a finished group project

I will not see the group in the application anymore

* * *

Student who forget teammates’ information

Find a person by name

I can find out more details of the person such as location, contact number

* * *

Student who made a mistake in recording a group tag

Edit a person’s group tag

I can change the group tag accordingly

* * *

Student who recorded the wrong personal information

Edit a person

I can correct the details of the person

* * *

Student who wants to know which teammates are in the project group

Print out the list of teammates under the same group tag

I know which teammates I am meeting

* * *

Student with arranged meet-ups

Add meet-ups with title, time, venue to the calendar

Have the summary of upcoming meet-ups in a quick glance

* * *

Student using CLI

Press up button to copy the previous command

I do not need to retype duplicate commands

* * *

Student that is involved with multiple groups

search events by its title

I can get details of a particular meet-up

* * *

Student who wants to arrange meet-ups

Search meet-ups by its title

I can get details such as time and place of a particular meet-up

* * *

Student adding teammates’ information

Add the link to teammates’ timetable

I can see teammates’ timetables to arrange meet-ups

* * *

Student working with new teammates

Add their contact information

I can contact them if the need arises

* * *

user

add info of the members involved in events

So that I know who I would need to talk to

* * *

Student first time using the application

See the usage instructions

Learn how to use the application

* * *

Student who have unused contacts

Delete a teammate from the application

I can free up storage for my application

* * *

Busy student with busy schedule

Have a reminder of the upcoming project meeting

I can be reminded of impending project with the details of group members printed on it

* * *

Student who created a group

Show teammates from a group

I can see the information of the teammates from the group

* * *

Student who has multiple group projects

Retrieve a list of all my groups

I can see all my groups at once

* * *

Student who is finished with a project

Delete everyone in a group in one go

I do not have to delete contacts one by one

* * *

Student who is too lazy to type

Use a shorter version of a command

Use the app faster

* *

Student who wants to know the location of teammates

Find the location of teammates’ address via google maps

Decide on a appropriate meeting location for all teammates considering their home address

* *

Student that does not leave applications open

See an overview of the week’s meetup right away when the application opens

Do not have to type in any commands when I first open the application

* *

Student who would like different colours tag for different projects

Have customizable coloured tags for different groups

Easily differentiate the groups via colour tags

* *

User with accessibility problems

Increase the font size of the application

I can read and see more easily

*

Student who is too lazy to eyeball through the timetables

Have an appropriate meet-up time generated for a group

I do not have to manually come up with time for meetup

*

Student who uses NUSMods

Use my NUSMods link to add my schedule into Fastis

I don’t have to manually input my timetable

*

Students who likes other colours on the interface

Change color scheme

Personalise the app

*

Student who wants to call an absent teammate

Open teammates’ Whatsapp page within the application e

I can alert teammates of the meeting

*

Student who do not how to reach the destination of the meet-up

Have the venue of the meet-up shown on google map

I can know the direction to the meetup

*

user

find the road that travels the shortest distance to the location of event

So that I can rely on the, map while driving

*

user

link an event with another

So that events that are related can be linked together so that i know which events are related

*

user

play music from address book

So that I can listen to music i want

*

user

play videos from youtube

So that I can watch videos i want

Appendix C: Use Cases

(For all use cases below, the System is the Fastis and the Actor is the user, unless specified otherwise)

Use case: Add an event

MSS

  1. User requests to add an event by entering information.

  2. Fastis adds the event to the calendar.

    Use case ends.

Extensions

  • 2a. Meet up clashes with an existing event.

    • 2a1. Fastis still adds the event, but it’s not shown in the calendar.

      Use case ends.

Use case: Add a person into a group

MSS

  1. User requests to list all persons.

  2. Fastis shows all persons, listed with an index.

  3. User requests to add a person, specified by an index, to a group, specified by name.

  4. Fastis adds the specified person to the specified group.

    Use case ends.

Extensions

  • 2a. Index given is invalid.

    • 2a1. Fastis notifies user that the index given was invalid.

      Use case ends.

  • 3a. There is no such group in Fastis.

    • 3a1. Fastis notifies the user that no group was found.

      Use case ends.

Use case: List all persons

MSS

  1. User requests to list all persons in Fastis.

  2. Fastis lists all persons.

    Use case ends.

Extensions

  • 2a. The persons list is empty.

    • 2a1. Fastis shows an empty list.

      Use case ends.

Use case: Delete a person from a group

MSS

  1. User requests to list all persons.

  2. Fastis shows all persons, listed with an index.

  3. User requests to delete a person, specified by an index, from a group, specified by name.

  4. Fastis deletes the specified person from the specified group, and notifies the user.

    Use case ends.

Extensions

  • 2a. There is no such group in Fastis.

    • 2a1. Fastis notifies the user that no group was found.

      Use case ends.

  • 3a. The specified person is not in that group.

    • 3a1. Fastis notifies the user that there is no such person in the group specified.

      Use case ends.

Use case: Show a person’s timetable

MSS

  1. User selects a person, either by select command or by clicking on the person in the person list panel.

  2. Fastis shows the timetable for the person.

    Use case ends.

Extensions

  • 2a. The specified person has no timetable

    • 2a1. Fastis shows an empty timetable

      Use case ends.

Use case: Print out all groupmates in the same group

MSS

  1. User requests to list the groupmates for a group, specified by name.

  2. Fastis lists all members in that group in the person list panel.

    Use case ends.

Extensions

  • 2a. There is no such group in Fastis.

    • 2a1. Fastis notifies the user that no group was found.

      Use case ends.

  • 3a. There are no people in that group.

    • 3a1. Fastis shows an empty list.

      Use case ends.

Use case: Help

MSS

  1. User requests to see the help panel.

  2. Fastis shows the help panel in a separate window.

    Use case ends.

Use case: Copy Previous Command

MSS

  1. User enters keystroke to navigate to previously entered command.

  2. Fastis copies the previous command into the input field.

    Use case ends.

Use case: Change Tag Color

MSS

  1. User enters a command to change a specific tag color.

  2. Fastis changes the color accordingly and displays it.

    Use case ends.

Extensions

  • 2a. The tag specified doesn’t exist within the address book.

    • 2a1. Fastis notifies the user.

      Use case ends.

  • 3a. The color specified is not supported by Fastis.

    • 3a1. Fastis notifies the user.

      Use case ends.

Appendix D: Non Functional Requirements

  1. Fastis should work on any mainstream OS as long as it has Java 1.8.0_60 or higher installed.

  2. Fastis should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.

  3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.

  4. Fastis should be usable without the need of a mouse.

  5. Fastis should be usable solely via a command line interface.

  6. Fastis should respond within 2 seconds.

  7. Fastis should have an easy to follow user guide.

  8. Fastis should open the help page when user enters an invalid entry.

  9. Fastis should be possible to fixed and debugged in the event of malfunction.

{More to be added}

Appendix E: Glossary

Abstraction

In Object-oriented Programming, abstraction is the mechanism by which users are provided with only the functionality, and not the implementation details. So, abstraction provides users with information on what an object does, rather than how it does it.

GUI

Acronym for Graphical User Interface. It is an interface (through which humans to interact with computers) that uses windows, icons and menus and which can be manipulated by a mouse and a keyboard.
GUI is used predominantly in Windows and iOS applications, including Fastis.

CLI

Acronym for Command Line Interface. It is a purely text-based interface for software. User respond to visual prompts by typing single commands into the interface and receive results as text as well. An example of CLI would be MS-DOS.

To-do

An objective that must be met by the user. May or may not have deadlines.

Event

A set of scheduled activity that user needs to attend at a specific time
E.g. Interviews, parties, CCAs, talks, coding challenges, assignments, etc.

Mainstream OS

Windows, Linux, Unix, OS-X

Member

A person in the address book.

Private contact detail

A contact detail that is not meant to be shared with others

User Interface

The means by which the user and a computer system interact, in particular the use of input devices and software.

Appendix F: Product Survey

Product Name

Author: …​

Pros:

  • …​

  • …​

Cons:

  • …​

  • …​

Appendix G: Instructions for Manual Testing

Given below are instructions to test the app manually.

ℹ️
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.

G.1. Launch and Shutdown

  1. Initial launch

    1. Download the .jar file and copy into an empty folder

    2. Double-click the .jar file
      Expected: Fastis shows the GUI with a set of sample contacts. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size, preferably to maximum size. Move the window to a different location. Close the window.

    2. Re-launch the app by double-clicking the .jar file.
      Expected: The most recent window size and location are retained.

G.2. Deleting a person

Deleting a person while all persons are listed

  1. Prerequisites: All persons are listed using the list command. Multiple persons exist in the list.

  2. Test case: delete 1
    Expected: First contact is deleted from the list. Details of the deleted contact are shown in the result display box. Timestamp of the last update in the status bar is updated.

  3. Test case: delete 0
    Expected: No person is deleted. Error details are shown in the result display box. Status bar remains the same.

  4. Other incorrect delete commands to try: delete John, delete x (where x is larger than the list size) {give more}
    Expected: Similar to previous.

G.3. Adding a person

Adding a person specified by the command line input with required person prefixes.

  1. Test case: add n/John Doe p/98765432 e/[email protected] a/311, Clementi Ave 2, #02-25 l/http://modsn.us/MYwiD d/Likes tennis t/friends t/owesMoney
    Expected: A new person named John Doe is added to Fastis. Details of person added are shown in the result display box.

  2. Test case: add p/98765432 e/[email protected] a/311, Clementi Ave 2, #02-25 l/http://modsn.us/MYwiD d/Likes tennis t/friends t/owesMoney
    Expected: No person is added. Essential NAME field is missing. Error details are displayed in result display box.

  3. Other incorrect add commands to try: add, add x (where x is any input)
    Expected: Similar to previous.

G.4. Adding a to-do

Adding a to-do with content specified by the command line input.

  1. Prerequisites: To-do with the content specified by user must not already be in Fastis.

  2. Test case: addToDo Do homework
    Expected: New to-do with content Do homework will be added to Fastis. Successful adding of to-do Do homework will be reflected in the result display box.

  3. Test case: addToDo Submit assignment - + -
    Expected: No to-do is added. To-do content must be alphanumeric. Error details are displayed in the result display box.

  4. Other incorrect commands: addToDo Submit assignment!
    Expected: Similar to previous.

  5. To-do Do homework already existed.
    Test case: addToDo Do homework
    Expected: Error details are displayed in status bar that to-do already exists.

G.5. Deleting a to-do

Deleting a to-do while all to-dos are listed

  1. Prerequisites: All to-dos are listed. Multiple to-dos exist in the list.

  2. Test case: deleteToDo 1
    Expected: First to-do is deleted from the list. Details of the deleted to-do are shown in the result display box. Timestamp of the last update in the status bar is updated.

  3. Test case: deleteToDo 0
    Expected: No to-do is deleted. Error details are shown in the result display box. Status bar remains the same.

  4. Other incorrect deleteToDo commands to try: deleteToDo Swim, deleteToDo x (where x is larger than the list size)
    Expected: Similar to previous.

G.6. Checking a to-do

Checking a to-do while all to-dos are listed

  1. Prerequisites: All to-dos are listed. Multiple to-dos exist in the list.

  2. Test case: check 1
    Expected: First to-do status is changed to "done". Details of the checked to-do are shown in the result display box. Timestamp of the last update in the status bar is updated.

  3. Test case: check 0
    Expected: No to-do is checked. Error details are shown in the result display box. Status bar remains the same.

  4. Other incorrect check commands to try: check Swim, check x (where x is larger than the list size)
    Expected: Similar to previous.

G.7. Unchecking a to-do

Unchecking a to-do while all to-dos are listed

  1. Prerequisites: All to-dos are listed. Multiple to-dos exist in the list.

  2. Test case: uncheck 1
    Expected: First to-do status is changed to "undone". Details of the unchecked to-do are shown in the result display box. Timestamp of the last update in the status bar is updated.

  3. Test case: uncheck 0
    Expected: No to-do is unchecked. Error details are shown in the result display box. Status bar remains the same.

  4. Other incorrect uncheck commands to try: uncheck Swim, uncheck x (where x is larger than the list size)
    Expected: Similar to previous.

G.8. Editing a to-do

Editing a to-do while all to-dos are listed

  1. Prerequisites: All to-dos are listed. Multiple to-dos exist in the list.

  2. Test case: editToDo 1 c/Do homework
    Expected: First to-do content is changed to "Do homework". Details of the edited to-do are shown in the result display box. Timestamp of the last update in the status bar is updated.

  3. Test case: editToDo 0 c/Do homework
    Expected: No to-do is edited. Error details are shown in the result display box. Status bar remains the same.

  4. Other incorrect editToDo commands to try: editToDo c/Swim, editToDo x c/Swim (where x is larger than the list size)
    Expected: Similar to previous.

G.9. Adding a group

Adding a group with information specified by the command line input.

  1. Prerequisites: Group with the information specified by user must not already be in Fastis.

  2. Test case: addGroup CS1010
    Expected: New group with information CS1010 will be added to Fastis. Successful adding of group CS1010 will be reflected in the result display box.

  3. Test case: addGroup CS1-1-
    Expected: No group is added. Group information must be alphanumeric. Error details are displayed in the result display box.

  4. Other incorrect commands: addGroup CS!
    Expected: Similar to previous.

  5. Group CS1010 already existed.
    Test case: addGroup CS1010
    Expected: Error details are displayed in status bar that group already exists.

G.10. Adding a member to group

Adding a member identified by INDEX to the group identified by INFORMATION.

  1. Prerequisites: Group and Person both exist in Fastis. Person must exist on the current Person List.

  2. Test case: addGroupMember 1 g/CS1010
    Expected: Member that is first on Person List will be added to the group with information CS1010. Successful adding of the person will be displayed on the result display box.

  3. Test case: addGroupMember 1 CS1010
    Expected: No member is added as command input is invalid since group field g/ is missing. Error details are displayed in the result display box.

  4. Other incorrect commands to try: addGroupMember, addGroupMember 1 t/
    Expected: Same as previous.

G.11. Deleting a member from group

Deleting a person from a group specified by the user. Often used after listGroupMembers command to see which members are in the group.

  1. Prerequisites: Group and Person both exist in Fastis. Person must exist on the current Person List.

  2. Test case: deleteGroupMember 1 g/CS1010
    Expected: Member is successfully deleted from the group CS1010. Successful deletion is displayed in the result display box.

  3. Test case: deleteGroupMember 1 CS1010
    Expected: No member is deleted due to missing field g/ in command. Error details are displayed in the result display box.

  4. Other incorrect commands to try: deleteGroupMember, deleteGroupMember 1 t/
    Expected: Same as previous.

G.12. Listing group members from a group

Listing all persons from a group specified by the user.

  1. Prerequisites: Group must exist in Fastis.

  2. Test case: listGroupMembers CS1010
    Expected: All members in group with information CS1010 are listed on Person List. Successful listing is displayed in the result display box.

  3. Test case: listGroupMembers !
    Expected: No person is listed. Error details are displayed in the result display box.

G.13. Deleting a group

Deleting a group with information specified by the user from Fastis.

  1. Prerequisites: Group must exist in Fastis.

  2. Test case: deleteGroup CS1010
    Expected: Group with information CS1010 is deleted. Successful deletion is displayed in the result display box.

  3. Test case: deleteGroup @
    Expected: No group is deleted. Error details are displayed in the the result display box.

G.14. Adding an event

Adding an event specified by command line input with required event prefixes.

  1. Test case: addEvent n/CS2101 meeting v/COM1 Hackerspace d/15/04/2018 st/1600 et/1800
    Expected: New event "CS2101 meeting" is added to Fastis. Details of the event added are shown in the result display box.

  2. Test case: addEvent v/COM1 Hackerspace d/15/04/2018 st/1600 et/1800
    Expected: No event is added. Essential NAME field is missing. Error details are displayed in the result display box.

  3. Other incorrect addEvent commands to try: addEvent d/18/04/15, addEvent d/30/02/2018, addEvent st/1900 et/1700, etc.
    Expected: Similar to previous.

G.15. Listing persons with specified tags

Listing all persons that have any of the specified tag(s).

  1. Prerequisites: Tag(s) must exist in Fastis.

  2. Test case: listTagMembers friends
    Expected: All members with tag friends will be listed on Person List. Number of person listed will be shown in status bar.

  3. Test case: listTagMembers 2131 (Tag 2131 does not exist in Fastis)
    Expected: 0 persons listed.

G.16. Changing a tag’s color

Changing a tag identified by `TAG` to have the color identified by `COLOR`.
  1. Prerequisites: TAG already exists in Fastis. COLOR must be supported by Fastis.

  2. Test case: changeTagColor friends pink
    Expected: Color of all tags named "friends" changes to "pink". Successful message of the change will be displayed in the result display box.

  3. Test case: changeTagColor friends rainbow
    Expected: No tag is changed as an unsupported color "rainbow" was input. Error details are displayed in the result display box.

  4. Other incorrect commands to try: changeTagColor, changeTagColor pink friends
    Expected: Same as previous.

G.17. Saving data

Dealing with missing/corrupted data files

  1. {explain how to simulate a missing/corrupted file and the expected behavior}