By: Team Modulo      Since: Feb 2020      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

ArchitectureDiagram
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.

The .puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the Using PlantUML guide to learn how to create and edit diagrams.

Main has two classes called Main and MainApp. It is responsible for,

  • At app launch: Initializes the components in the correct sequence, and connects them up with each other.

  • At shut down: Shuts down the components and invokes cleanup method where necessary.

Commons represents a collection of classes used by multiple other components. The following class plays an important role at the architecture level:

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

The rest of the App consists of four components.

  • UI: The UI of the App.

  • Logic: The command executor.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

Each of the 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 the class diagram given below) 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

How the architecture components interact with each other

The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.

ArchitectureSequenceDiagram
Figure 3. Component interactions for delete 1 command

The sections below give more details of each component.

2.2. UI component

UiClassDiagram
Figure 4. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, ListPanel, StatusBarFilter, RightPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.

The ListPanel is located at the left of the application and it consists of UI EventCard, ModuleCard, TitleCard to display list of events or modules. The RightPanel is located at the right of the application and it consists of UI RightPanelDeadlineCard , RightPanelDescription, and RightPanelEventCard to display the details of the module or event.

For example, user can do view command to view the deadlines of the event in the ListPanel and the details and deadlines of the event will be displayed on the RightPanel.

The UI component uses the 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.

  • Listens for changes to Model data so that the UI can be updated with the modified data.

2.3. Logic component

LogicClassDiagram
Figure 5. Structure of the Logic Component

API : Logic.java

  1. Logic uses the ModuloParser 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 an event).

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

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

2.3.1. StatefulLogic Interface:

StatefulLogic is implemented by classes that only manages logic while a state exists. This state would be loaded from special CommandResult subclasses, and allows this StatefulLogicManager to take priority over the default LogicManager. The exact implementation of state is up to the developer.

Currently, there is only one class that implements it: AddModuleStatefulLogicManager. Its state is loaded from a special AddModuleCommandResult created by the AddModuleCommand, i.e. when the user uses the module m/MODULE_CODE command.

The state is created using a list of the event types (tutorial, lecture, lab etc.) that the added module has. Subsequently, while the list is not empty, the AddModuleStatefulLogicManager handles all inputs, thus allowing Modulo to add the relevant events.

More details on the implementation can be found here.

2.3.2. Writer Component:

The Writer component is activated when the ExportCommand is executed. It then calls the writeIcsFile() function from the IcsWriter class which retrieves the current list of events from the Model component which, along with its deadlines, are converted into IcsEvent and IcsDeadline objects, which are then written into the ICS file.

2.3.3. Sample Interactions

Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeleteSequenceDiagram
Figure 6. Interactions Inside the Logic Component for the delete 1 Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

2.4. Model component

ModelClassDiagram
Figure 7. Structure of the Model Component

API : Model.java

The Model,

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

  • stores Modulo data.

  • exposes an unmodifiable ObservableList<Module> and ObservableList<Event> that can be 'observed' e.g. the UI can be bound to these lists so that the UI automatically updates when the data in the lists change.

  • does not depend on any of the other three components.

As of now, there are two separate ObservableList being maintained, and with each individual module keeping its own list of events as well. In the future, to better enable the concept of a single source of truth, we can discard the use of a ObservableList<Event> and expose solely the unmodifiable ObservableList<Module>, and have events accessed through its parent module.

BetterModelClassDiagram

Alternatively, we can remove the list of events under each module and instead just maintain the two separate UniqueModuleList and UniqueEventList. This may, however, make it costly to render the module list, since we now need to search through the entire list of events to find relevant ones.

2.5. Storage component

StorageClassDiagram
Figure 8. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the Modulo data in json format and read it back.

2.6. Common classes

Classes used by multiple components are in the modulo.commons package.

3. Implementation

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

3.1. Stateful Logic Feature

Multistep commands are facilitated by StatefulLogic. It is an interface with three methods exposed, and currently only has one class implementing it, AddModuleStatefulLogicManager.

StatefulLogicClassDiagram
Figure 9. Structure of the Stateful Logic Component

Let us understand how StatefulLogic works.

3.1.1. How StatefulLogic works

As long as a StatefulLogicManager, which is a class that implements StatefulLogic, has state, it will take over the LogicManager in executing the given String.

AddModuleHasStateSequenceDiagram
Figure 10. The current implementation

Should there be more StatefulLogicManager instances in play, we will see something like this:

MultipleHasStateSequenceDiagram
Figure 11. If more Stateful Logic Managers are added

At any point of time, only one StatefulLogicManager will have state. The LogicManager will thus check through them one by one, and will only directly parse the command itself should no StatefulLogicManager have state. We can think of these StatefulLogicManager as "consumers" that consume the input if it has state.

The abstraction of how these StatefulLogicManager execute the given String helps to maintain the Single Responsibility Principle. The interaction between the LogicManager and StatefulLogicManager is also facilitated through the interface, StatefulLogic, which upholds the Dependency Inversion Principle.

3.1.2. How state is loaded and maintained

State is loaded into StatefulLogicManager using special CommandResult subclasses. In the instance of the AddModuleStatefulLogicManager, its state is loaded by passing a AddModuleCommandResult into its loadStateFromCommandResult method.

Let us take a look at the full process, using AddModuleCommand as an example:

AddModuleOverviewSequenceDiagram
Figure 12. Executing the module m/CS2103 command

There is no difference for the first part from a regular Command execution. The differences lie in the state preparation and state loading.

StatePreparationSequenceDiagram
Figure 13. State Preparation for AddModuleCommandResult

The state is prepared during the initialising command, and that command will pack that state into a special subclass of CommandResult. This CommandResult is then passed back to the default LogicManager.

State loading is then done, if suitable.

StateLoadingSequenceDiagram
Figure 14. State Loading for AddModuleStatefulLogicManager

The eventList is passed on to the AddModuleStatefulLogicManager to be used as state. As long as the list is not empty, it is considered to have state.

3.1.3. Design Considerations

Aspect: How StatefulLogic should be positioned with respect to Logic
  • Alternative 1 (current choice): Have StatefulLogic exist as a sub-logic-circuit within Logic that activates when conditions are met.

    • Pros: Reduce repeated code (DRY) and adheres to the Open Closed Principle, since the use of a simple interface makes it easy to create future StatefulLogic classes and integrate them.

    • Cons: Logic now has to take care of checking for state prior to execution of command, as well as follow up on special subclasses of CommandResult, thus violating the Single Responsibility Principle.

  • Alternative 2: Have StatefulLogic extend Logic and have a separate LogicDispatcher class that decides which Logic to dispatch the command to.

    • Pros: Seems to follow the Single Responsibility Principle better.

    • Cons: A lot of repeated code, and to some extent, this may be an adaptation of the current implementation, where the Logic class acts as the LogicDispatcher. Furthermore, it may not be correct to say that Logic and StatefulLogic are similar. StatefulLogic does operate quite differently from Logic.

  • Future Extension: It may be worth looking into this and find a better way to handle this logic without breaking the existing Command Pattern. There may be more similarities that can be abstracted out and maximised using OOP.

Aspect: How multistep commands should be implemented and achieved
  • Alternative 1 (current choice): Use StatefulLogic to keep relevant states and logic together.

    • Pros: Uses OOP to reduce complexity. Adheres to the Open Closed Principle, since each class can just implement StatefulLogic, and the exact management of its state is open.

    • Cons: Logic now needs to handle the pre and post-command logic.

  • Alternative 2: Maintain a global state that Logic listens to when executing commands.

    • Pros: All commands can push state to this global state without having to go through Logic, reducing the pre and post-command handling.

    • Cons: The implementation of this global state will be highly complex, since the logic required for different states is different as well. Logic would be overwhelmed. If a new type of state is required, the changes required will be heavy as well, thus violating the Open Closed Principle.

3.2. Done Feature

This feature allows the User to set the deadline’s status to be completed or not completed. The user input is handled and retrieved by the MainWindow class in the Ui component first, before being passed to the LogicManager to execute. First,LogicManager will call ModuloParser, which will parse the input to give a DoneCommandParser. Then, DoneCommandParser will return a DoneCommand, which will help to set the status of deadline and update the Model. Invalid inputs such as an invalid index (e.g. done 1000) are also handled properly, with suitable error messages being displayed to the user. The DoneCommand is implemented according to the operation in the Logic module:

  • DoneCommand — Sets the status of the deadline.

For the command, a DoneCommandParser is implemented to parse the input into the required index.

  • DoneCommandParser — Parses the done command input and generates a DoneCommand.

Given below is a sequence diagram to show how the done mechanism behaves at each step.

Done SequenceDiagram

Given below is an activity diagram to show how the done operation works.

Done ActivityDiagram

3.2.1. Design Considerations

Aspect: How done is executed
  • Alternative 1 (current choice): User can done one deadline at a time.

    • Pros: Easy to implement and not likely to create bugs.

    • Cons: More steps are required for the user if they wish to complete different deadlines.

  • Alternative 2 : User can done multiple deadlines at a time.

    • Pros: Less time-consuming than if the user were to complete a list of deadlines, one at a time.

    • Cons: User input will be highly complex, as we may need to consider the different use cases, e.g. deadlines of different events, of different modules etc. We will be required to check and account for various possibilities before the operation can be done. Difficult to implement, and even harder to troubleshoot if bugs occur.

Other considerations
  • Modulo will keep track of all the deadlines' statuses and send reminders to the user accordingly.

    • Pros: A good feature that helps to remind users of their incomplete deadlines.

    • Cons: Hard to implement and it increases coupling. Difficult to write test cases as well.

  • Future Extension: Modulo can have another UI panel to display every deadline that needs to be done a certain week. The user can then use the done command to update the deadlines' statuses from there.

3.3. Export Feature

Modulo supports exporting user’s calendar to .ics file format to facilitate data transfer between different scheduling platforms.

By using a simple FileWriter class and generating the .ics entities, we’re able to generate an .ics file that can be consumed by commonly used platforms (e.g. Google Calendar)

An overview of the process is shown as below through the triggering of ExportCommand:

ExportCommandSequenceDiagram

3.3.1. Design Considerations

Aspect: How Deadline should be exported together with Event

Event entities can be mapped to VEVENT .ics type, but there is a lack of suitable counterparts for deadline.

  • Alternative 1: Export Deadline as VTODO

    • Pros: Deadline has its standalone VTODO .ics item type.

    • Cons: Some popular calendar applications do not support VTODO importing, thus making users lose out on important information regarding events.

  • Alternative 2: Export Deadline within the description of each Event

    • Pros: Users are able to see at a glance what are the Deadline for each Event easily

    • Cons: Users are unable to take advantage of VTODO import functionality of certain calendar application.

  • Alternative 3 (current choice): Combine both options Users are able to make full use of .ics importing capabilities, while also providing a quick overview of Deadline

3.4. Module / Event / Deadline Deletion Feature

This Deletion feature allows the user to delete modules, events or deadlines. The user input is first retrieved by the MainWindow class which is then passed to the LogicManager via the execute function. LogicManager will call the parseCommand function of ModuloParser`, which will parse the input to create a temporary DeleteCommandParser object, parsing the input and returning a DeleteCommand. The command will then be executed in the LogicManager, returning a CommandResult object which will then be returned as feedback to the user.

Given below is a sequence diagram to show how the delete feature parsing an input of '1' behaves at each step:

DeleteSequenceDiagram

Given below is an activity diagram to show how the delete operation works.

DeleteActivityDiagram

3.4.1. Design Considerations

Aspect: How delete may be executed
  • Alternative 1 (current choice): User can delete multiple items using the command at the same time.

    • Pros: Allows the user more flexibility in deleting modules and events instead of just deleting them one by one. For example users can choose to delete one, many or even all modules and events, depending on their command input.

    • Cons: This has caused the code to become more complex in dealing with the many possible inputs and scenarios, leading to a higher amount of potential errors.

With respect to deadlines, users can only delete one or all deadlines of a particular event. This is to avoid any confusion and unnecessary complexity which may be caused by deleting deadlines across all events, especially since the user may only observe deadlines of one event at any one time and do not have access to the overall list of deadlines.
  • Alternative 2 : User can delete only one or all items.

    • Pros: Reduces the lack of potential errors due to the decreased complexity of the code.

    • Cons: It is less intuitive for the user as users are now limited by deleting one or all the events / modules / deadlines.

  • Future Extension: Modulo can have another UI panel to display every deadline that needs to be done a certain week. The user can then use the delete command to delete multiple deadlines at one go, making it more convenient for the user.

3.5. [Proposed] Edit Feature

Currently, Modulo does not allow for the editing of the details of events and deadlines that have been created.

3.5.1. Proposed Implementation

The Edit functionality will be achieved through the introduction of an EditCommand and its parser EditCommandParser.

EditCommandClassDiagram

The edit command will have the following format:

  • Editing events: edit n/EVENT_NAME m/MODULE_CODE [nn/NEW_NAME] [s/NEW_START_DATETIME] [e/NEW_END_DATETIME] [v/NEW_VENUE]

  • Editing deadlines: edit d/INDEX m/MODULE_CODE e/EVENT_NAME nn/NEW_NAME

The flow of the command parsing will be as such:

EditCommandActivityDiagram

If an EditCommand is successfully created, it will be executed on the Model. It will work mainly through the setEvent method already exposed in the Model interface, as well as a setDeadline that will be exposed through the parent event.

Here’s an example of how it may look like if the EditCommand was to modify an event’s venue.

User input: edit n/Tutorial 1 m/CS2103 v/Home

EditCommandSequenceDiagram

3.5.2. Limitations

Due to the fact that repeated events are not currently being tagged or grouped in any way, it is difficult to allow mass editing of repeated events.

If there’s a need to edit a repeated event, there would be a need to edit the events one by one.

3.5.3. Design Considerations

Aspect: How to easily modify deadlines
  • Alternative 1 (current choice): Manually fetch the deadline from the event and replace.

    • Pros: Easy to implement.

    • Cons: May have slight performance issues in terms of speed, and a lot of coding to be done.

  • Alternative 2: Consolidate the deadlines in a UniqueDeadlineList.

    • Pros: Less code to write for this feature specifically, in terms of the setDeadline method.

    • Cons: Increases complexity of the application, since now three lists are maintained. There is also the same issue with events and modules in terms of the source of truth.

3.6. [Proposed] Undo/Redo Feature

3.6.1. Proposed Implementation

The undo/redo mechanism is facilitated by VersionedModulo. It extends Modulo with an undo/redo history, stored internally as an moduloStateList and currentStatePointer. Additionally, it implements the following operations:

  • VersionedModulo#commit() — Saves the current modulo state in its history.

  • VersionedModulo#undo() — Restores the previous modulo state from its history.

  • VersionedModulo#redo() — Restores a previously undone modulo state from its history.

These operations are exposed in the Model interface as Model#commitModulo(), Model#undoModulo() and Model#redoModulo() respectively.

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

Step 1. The user launches the application, toggles to the event list and views an event. The VersionedModulo will be initialized with the initial modulo state, and the currentStatePointer pointing to that single modulo state.

UndoRedoState0

Step 2. The user executes delete 5 command to delete the 5th event in Modulo. The delete command calls Model#commitModulo(), causing the modified state of Modulo after the delete 5 command executes to be saved in the moduloStateList, and the currentStatePointer is shifted to the newly inserted Modulo state.

UndoRedoState1

Step 3. The user executes deadline n/Draw UML to add a new deadline to the viewed event. The deadline command also calls Model#commitModulo(), causing another modified modulo state to be saved into the moduloStateList.

UndoRedoState2
If a command fails its execution, it will not call Model#commitModulo(), so the Modulo state will not be saved into the moduloStateList.

Step 4. The user now decides that adding the deadline was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoModulo(), which will shift the currentStatePointer once to the left, pointing it to the previous Modulo state, and restores Modulo to that state.

UndoRedoState3
If the currentStatePointer is at index 0, pointing to the initial Modulo state, then there are no previous Modulo states to restore. The undo command uses Model#canUndoModulo() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.

The following sequence diagram shows how the undo operation works:

UndoSequenceDiagram
The lifeline for UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

The redo command does the opposite — it calls Model#redoModulo(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores Modulo to that state.

If the currentStatePointer is at index moduloStateList.size() - 1, pointing to the latest Modulo state, then there are no undone Modulo states to restore. The redo command uses Model#canRedoModulo() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.

Step 5. The user then decides to execute the command list modules. Commands that do not modify Modulo, such as list, will usually not call Model#commitModulo(), Model#undoModulo() or Model#redoModulo(). Thus, the moduloStateList remains unchanged.

UndoRedoState4

Step 6. The user executes clear, which calls Model#commitModulo(). Since the currentStatePointer is not pointing at the end of the moduloStateList, all modulo states after the currentStatePointer will be purged. We designed it this way because it no longer makes sense to redo the deadline n/Draw UML command. This is the behavior that most modern desktop applications follow.

UndoRedoState5

The following activity diagram summarizes what happens when a user executes a new command:

CommitActivityDiagram

3.6.2. Design Considerations

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

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage.

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

    • Pros: Will use less memory (e.g. for delete, just save the deadline being deleted).

    • Cons: We must ensure that the implementation of each individual command are correct.

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (current choice): Use a list to store the history of Modulo states.

    • Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.

    • Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both HistoryManager and VersionedModulo.

  • Alternative 2: Use HistoryManager for undo/redo

    • Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.

    • Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as HistoryManager now needs to do two different things.

3.7. Logging

We are using 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 3.8, “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.

Logging Levels

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

  • WARNING : Can 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

3.8. Configuration

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

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • has a need to manage their modules and the deadlines for these modules

  • prefer desktop apps over other types of apps

  • can type fast and prefers typing over mouse input

  • is reasonably comfortable using CLI apps

  • is a current NUS student who is taking modules in AY19/20 Sem 2

Value proposition: Manage modules and related deadlines faster than a typical mouse/GUI driven app

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…​

* * *

new user

see usage instructions

refer to instructions when I forget how to use Modulo

* * *

user

view my events by week

never miss any event

* * *

user

view the deadlines of my events

can know the deadlines I have

* * *

user

view class slots (e.g. tutorial) of my events

remember which class slot I signed up for

* * *

busy user

create deadlines

ensure I do not miss any of my module / assignment deadlines

* * *

user

complete deadlines

track the work I have done

* * *

user

set routine deadlines based on events

routinely prepare for these events

* * *

user

categorise my work based on module

don’t have to manually categorise myself

* * *

user

add events to modules easily

get started on deadline planning earlier

* * *

user

delete modules / events / deadlines

if I finished doing them or made an error while adding them

* * *

busy user

delete all modules / events / deadlines

if I want to save time

* * *

user

find modules / events according to keyword

find modules / events are relevant to me

* *

user

export my data from this app

access the data I’ve created from anywhere

{More to be added}

Appendix C: Use Cases

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

Use case: UC01 - Add a deadline

MSS Preconditions: Module data file is loaded properly.
Guarantees: Deadline is added under the correct module and event, with the correct details.

  1. User adds a module (UC02).

  2. User adds a deadline to the correct module and event, with all the required details.

  3. Modulo shows the newly created deadline.

    Use case ends.

Extensions

  • 2a. User enters incorrect information.

    • 2a1. Modulo shows user the correct format for the deadline creation.

    • 2a2. User enters new information following the correct format.

      Use case resumes from step 3.

Use case: UC02 - Add a module

MSS Preconditions: Module data files are loaded properly.
Guarantees: Module is added to the user’s Modulo.

  1. User enters a module code, e.g. CS2103.

  2. Modulo searches its data files for the module and creates the module using information from the data files.

  3. Modulo prompts user to enter the slot for an event type.

  4. User enters their slot for the event type.
    Steps 3-4 are repeated for as many times as required until the User has entered slots for all event types of the module.

  5. Modulo shows the newly created module.

    Use case ends.

Extensions

  • 1a. User enters incorrect data and the wrong module is found.

  • 1b. User enters invalid data and no modules are found.

    • 1b1. Modulo informs User that no modules with the given information can be found.

    • 1b2. Step 1 repeated until User enters a correct module code.

      Use case resumes from step 2.

  • 3a. User added a module with no events.

    • Use case resumes from step 5.

  • 3b. User exited Modulo before adding all events.

    • 3b1. Modulo saves all events that were already added.

      Use case ends.

  • 4a. User enters an invalid slot.

    • 4a1. Modulo cancels the request by the User.

    • 4a2. Modulo informs the User of the cancellation.

      Use case ends.

Use case: UC03 - Delete a module / event / deadline

  1. User enters delete followed by an input or delete d/ followed by an input for deadlines.

  2. Modulo parses the input.

  3. The input is parsed and the relevant item is deleted.

  4. Modulo displays the item or items that have been deleted. Use case ends.

Extensions

  • 1a. User enters an invalid input.

  • 1b. Step 2 takes place.

    • 1b1. Modulo informs the user that the item the user wants to delete does not exist.

    • 1b2. User enters a new item to deleteadd

      Use case resumes from step 1.

Use case: UC04 - Set Done to Deadline if user viewing a event

MSS Preconditions: Module, Event and deadline are added.
Guarantees: Status of viewed deadline is updated.

  1. User list all the registered event (UC06).

  2. User view the selected events(UC09).

  3. User enter index of deadline. e.g: done 1.

  4. Modulo checks is if the index is valid or not and toggles the completion status of the deadline. If the deadline was incomplete, it would be completed, and vice versa. The color of the status changes accordingly and success message will displayed in result box.
    Use case ends.

Extensions

  • 5a. User enters invalid index. e.g: done 1000

    • 5a1. Module inform user that index is not valid.
      Use case resumes from step 5.

Use case: UC05 - Set Done to deadline if user not viewing event.

MSS Preconditions: Module, Event and deadline are added and exits in Modulo.
Guarantees: Status of deadline under correct module and event is updated.

  1. User enter module code, event name and index of deadline. e.g: done 1 m/CS2103 e/Tutorial 2.

  2. Modulo searches for the registered module, event and index of the deadline toggles the completion status of the deadline. If the deadline was incomplete, it would be completed, and vice versa. A success message will displayed in result box
    Use case ends.

Extensions

  • 1a. User enters wrong module code and no module is found.

    • 1a1. Modulo informs User that the module does not exists.

    • 1b2. Step 1 repeated until User enters a correct module code.
      Use case resumes from step 2.

  • 1a. User enters correct module code but wrong event name and no event is found.

    • 1a1. Modulo informs User that the event does not exists.

    • 1b2. Step 1 repeated until User enters a correct event name. Use case resumes from step 2.

Use case: UC06 - List Event

MSS Preconditions: Modules and Events are already added in Modulo .
Guarantees: A list of added Events are displayed.

  1. User enter list event.

  2. Modulo searches for all the events that are added in the system and displayed in the left panel.

    Use case ends.

Extensions

  • 1a. User enters invalid command. e.g: list tutorial

    • 1a1. Module inform user the command is invalid and display correct format to user
      Use case resumes from step 1.

Use case: UC07 - List Module

MSS Preconditions: Modules are added in Modulo .
Guarantees: A list of added Modules is displayed.

  1. User enter list module

  2. Modulo searches for all the modules that are added in the system and displayed in the left panel.

    Use case ends.

Extensions

  • 1a. User enters invalid command. e.g: list CS2103

    • 1a1. Module inform user the command is invalid and display correct format to user
      Use case resumes from step 1.

Use case: UC08 - View Module

MSS Preconditions: Modules data are added in Modulo.
Guarantees: Details of selected module will be displayed.

  1. User list all the registered module (UC07).

  2. User enter view command, e.g view 1(index).

  3. Modulo will searches and for the correct index from module list and display the details of module at the right panel. Use case ends.

Extensions

  • 2a. User enters invalid index. e.g: view 1000

    • 2a2. Module inform user that index is not valid.

    • 2b2. Step 2 repeated until user enters a valid index.

Use case resumes from step 2.

Use case: UC09 - View Event

MSS Preconditions: Modules and events are added in Modulo .
Guarantees: Details of selected event will be displayed.

  1. User list all the registered event (UC06).

  2. User enter view command, e.g view 1(index).

  3. Modulo will searches and for the correct index from the events list and display the details of event at the right panel.

    Use case ends.

Extensions

  • 2a. User enters invalid index. e.g: view 1000

    • 2a2. Module inform user that index is not valid.

    • 2b2. Step 2 repeated until user enters a valid index.

Use case resumes from step 2.

Use case: UC10 - Export

MSS Preconditions: Application is running.
Guarantees: An .ics file is generated containing Event and Deadline from user’s calendar.

  1. User enters a directory for system to export, e.g. /data.

  2. Modulo looks for the directory specified by user.

  3. Modulo deposits an .ics file into the specified directory.

    Use case ends.

Extensions

  • 2a. Modulo is unable to find the directory specified by user.

    • 2a1. Modulo creates the directory.

      Use case resumes from step 3.

Appendix D: Non-Functional Requirements

  1. A NUS student 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.

  2. Should work on any mainstream OS as long as it has Java 11 or above installed.

  3. Should be able to run seamlessly with 10 modules’ worth of data.

  4. Data should be persistent within the local machine and the save file should be editable.

  5. The application should not require an installer and be for a single user, with its size being smaller than 100mb.

  6. Object-oriented.

{More to be added}

Appendix E: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Module

Modules that the User is taking for AY19/20 Semester 2.

Event

There are two types of events: official and user-added. Official ones include events such as Lectures, Tutorials, Recitations, Sectionals etc. User-added are events that are not recognised.

Refer to here for the list of recognised event types.

Deadline

Individual tasks to complete that can be tagged to a specific event.

Appendix F: Product Survey

NUSMods

Author: Zhu Hanming

Pros:

  • Extremely clean and intuitive UI.

  • Effortless data population and contains all the information I may need.

  • Can save my data as a .ics file.

Cons:

  • Not a CLI app.

  • Doesn’t help me plan my deadlines.

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: Shows the GUI with no data. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum 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 is retained.

  3. Shutting down

    1. Launch the help window by typing help.

    2. Quit the app by typing exit.
      Expected: Both the main window and the help window should close.

G.2. Adding a module

  1. Adding CS2103

    1. Prerequisites: CS2103 not already added. If added, delete it.

    2. Test case: module m/cs2103
      Expected: CS2103 to appear in the list of modules, and app to prompt for further input.

    3. If prompt is for tutorial, test case: 3
      Expected: Tutorial slot 3 should be added.

    4. If prompt is for lecture, test case: 1
      Expected: Lecture slot 1 should be added.

G.3. Adding an event

  1. Adding Exam to CS2103

    1. Prerequisites: CS2103 already added. No event named Exam has been added to CS2103 yet.

    2. Test case: event n/Exam m/CS2103 s/2020-01-15 09:00 e/2020-01-15 10:00 v/Home
      Expected: Event named Exam should appear in the list of events. To check, enter list events. It should be near the top of the list. The details should be as entered.

  2. Adding recurring events to CS2103

    1. Prerequisites: CS2103 already added. No recurring event named Self Study has been added to CS2103 yet.

    2. Test case: event n/Self Study m/CS2103 s/2020-01-20 09:00 e/2020-01-20 10:00 v/Home r/YES until/2020-02-20
      Expected: Events named Self Study 1, Self Study 2, until Self Study 5 should appear, with a frequency of 1 week, and stopping before 2020-02-20.

G.4. Adding a deadline

  1. Adding a deadline to CS2103 Exam

    1. Prerequisites: CS2103 added. Event named Exam added. No deadline named "Study hard for exam" has been added to the event yet.

    2. Test case: deadline n/Study hard for exam m/CS2103 e/Exam
      Expected: Deadline added to Exam. To check, first make sure you’re listing events with list events, then enter view INDEX, where INDEX is the index of the event on the list.

G.5. Completing a deadline

  1. Complete Study hard for exam.

    1. Prerequisites: CS2103 added. Event named Exam added. Deadline named Study hard for exam added, and is not completed.

    2. Test case: done 2 m/CS2103 e/Exam
      Expected: Deadline named Study hard for exam is completed.

G.6. Switching lists

  1. List events

    1. Test case: list events
      Expected: If not already listing events, events will now be listed.

  2. List modules

    1. Test case: list modules
      Expected: If not already listing modules, modules will not be listed.

G.7. View event or module

  1. View module

    1. Prerequisite: List all modules using the list modules command. At least one module.

    2. Test case: view 1
      Expected: Details of the first module should show on the right panel.

  2. View event

    1. Prerequisite: List all events using the list events command. At least one event.

    2. Test case: view 1
      Expected: Details of the first event should show on the right panel.

G.8. Find event or module

  1. Find event(s) with Self Study in their names

    1. Prerequisite: List all events using the list events command. Has event(s) named Self Study.

    2. Test case: find self study
      Expected: All events with Self Study in their names would appear. You can operate on this filtered list.

  2. Find Software Engineering

    1. Prerequisite: List all modules using the list modules command. CS2103 added.

    2. Test case: find software engineering
      Expected: CS2103 should show, along with any other modules that may have Software Engineering in their names.

G.9. Deleting a module

  1. Deleting a module using index while all modules are listed

    1. Prerequisites: List all modules using the list modules command. Multiple modules in the list.

    2. Test case: delete 1
      Expected: First module is deleted from the list. All events of that module are deleted. Details of the deleted module shown in the status message.

    3. Test case: delete 0
      Expected: No module is deleted. No events deleted. Error details shown in the status message.

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

  2. Deleting a module using search terms while all modules are listed

    1. Prerequisites: List all modules using the list modules command. CS2103 in the list. Other CS modules in the list.

    2. Test case: delete CS2103
      Expected: CS2103 is deleted from the list. Details of the deleted module shown in the status message.

    3. Test case: delete cs
      Expected: All CS modules are deleted. Number of deleted modules shown in the status message.

    4. Test case: delete cs2999
      Expected: No module is deleted. Information shown in the status message.

    5. Other incorrect delete commands to try: delete x (where x is a term that does not exist in the list).
      Expected: Similar to previous.

G.10. Deleting an event

  1. Deleting an event using index while all events are listed

    1. Prerequisites: List all events using the list events command. Multiple events in the list.

    2. Test case: delete 1
      Expected: First event is deleted from the list. Details of the deleted event shown in the status message.

    3. Test case: delete 0
      Expected: No event is deleted. Error details shown in the status message.

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

  2. Deleting an event using search terms while all events are listed

    1. Prerequisites: List all events using the list events command. At least one Tutorial 1 in the list. Other Tutorials in the list as well.

    2. Test case: delete Tutorial 1
      Expected: All events with Tutorial 1 in their names are deleted from the list. Number of deleted events shown in the status message.

    3. Test case: delete Tutorial
      Expected: All Tutorials are deleted. Number of deleted events shown in the status message.

    4. Test case: delete Tvtor!al
      Expected: No event is deleted. Information shown in the status message.

    5. Other incorrect delete commands to try: delete x (where x is a term that does not exist in the list).
      Expected: Similar to previous.

G.11. Deleting a deadline

  1. Deleting a deadline using index while an event is focused

    1. Prerequisites: List all events using the list events command. Events in the list. View first event with view 1. First event has a deadline.

    2. Test case: delete d/1
      Expected: First deadline is deleted from the list. Details of the deleted deadline shown in the status message.

    3. Test case: delete 0
      Expected: No deadline is deleted. Error details shown in the status message.

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

G.12. Exporting data as .ics file

  1. Export data

    1. Test case: export
      Expected: A modulo.ics file should be created in the same ./data/ folder. You can use this .ics file to add your events and deadlines into your calendar.

G.13. Viewing help

  1. View help

    1. Test case: help
      Expected: Help window appears.

G.14. Clearing Modulo

  1. Clear all existing data in Modulo

    1. Prerequisites: Some data has been added to Modulo.

    2. Test case: clear
      Expected: All data cleared.

G.15. Saving data

  1. Dealing with missing/corrupted data files

    1. Corrupt the current save file under ./data/. The easiest way is to type - somewhere in one of the saved modules' academic year. Another way may be to add random characters that make the JSON format unreadable.

    2. Double-click the jar file
      Expected: Shows the GUI with no data.

    3. Delete the current save file under ./data/.

    4. Double-click the jar file
      Expected: Shows the GUI with no data.

Appendix H: Effort

H.1. Model

The Model of Modulo is certainly more complex than that of AddressBook. In AddressBook, there was only one key object in play - Person. Most of the other classes were ones that served as attributes for the Person object.

For Modulo, three different objects are managed at once, with the Model class having to juggle two different lists at all times. As such, there was much greater complexity, especially when the commands used one type of object as a reference for another! An example would be finding an event that belongs to a certain module. The logic behind can be implemented in various ways, and we sought to reduce the complexity of this logic.

The process was rough - we didn’t get it right from the start (and we cannot say for sure that we have gotten it right currently), and we had to refactor our code over quite a few times, as we realise the limitations of our previous implementations. This is with careful planning right from the start!

H.2. Logic

Modulo implemented its own StatefulLogic that allows users to perform multistep commands. This in itself is quite a huge step up from the existing Logic flow in AddressBook, where commands were all "one-shot".

And as mentioned earlier, with the increased complexity of the Model and its classes, naturally, the complexity of Logic follows. Commands are no longer "single-dimensional", and now need to perform various operations before being able to determine the correct action to execute.

Our team spent quite a lot of effort to come up with ways to implement both the StatefulLogic and the commands.

H.3. Storage

The complexity of Storage naturally increased as well, as now we have to store objects of three types into a single JSON file, and still have a way to recover and restore the associations between all of these "save data" upon loading. The process of deriving our current way of doing things took quite a while as well.

H.4. Ui

Lastly, the Ui. Our Modulo team spent quite a bit of effort in ensuring that our interface was pleasing to the eye. And we’re glad that we did, as the Ui turned out the way we wanted! This is not a painless process, however. We did spend quite a bit of time undoing what we’ve designed at times, as we designed and built iteratively.

H.5. Overall

As a whole, this process was not an easy one for the Modulo team. We started off with a grandiose idea in mind, and met obstacle after obstacle. We did fight hard, but for a large part, we were slowly worn down. It’s rather sad to see that we did not achieve the goal we initially set out to due to these challenges. But we’re also very glad to say that, in exchange, we’ve learnt a lot more than we expected to. In overcoming a lot of the problems mentioned above, our team spent sessions discussing, debating and brainstorming, and we learnt together in the end.

We wouldn’t say we’re the team that spent the most effort, but we can say for sure that we didn’t spare any effort throughout the process.