<== Back to Home

Developer Guide

GULIO (Get Ur Life In Order) is a desktop app that provides a single consolidated and personalised workspace for NUS SoC students to organize their modules. It is optimized for use via a Command Line Interface (CLI) which SoC students will be familiar with typing in, instead of a Graphical User Interface (GUI).

This guide is for developers looking to modify GULIO. For users of GULIO, please refer to the User Guide here.

 


Table of Contents

 


How to Use This Guide

Icons & labels used in this guide:

💡 - indicates a tip that may be useful to you.
⚠ - indicates a warning that you should take note of.

Italic - Indicates that the content is a component.
Inline code - Indicates that the content is a class, method or input by the user.

 

🡅 Back to Table of Contents


Setting up GULIO on Your Computer

  1. Fork this repo, and clone the fork into your computer.
  2. Ensure you are using Java 11 or above.
  3. Import the project in your IDE.

💡 You are highly recommended to use Intellij IDEA.

To set up Intellij:

  1. Ensure Intellij is configured to use JDK 11.
  2. Import the project as a Gradle project.
  3. Verify the setup:
    1. Run seedu.duke.Duke and try a few commands.
  4. Run the tests to ensure they all pass.

 

🡅 Back to Table of Contents


Introduction

Background of GULIO

GULIO is a command line application for NUS SoC students to organize their modules. It has a 2-layer system: dashboard layer and module layer. In both layers, the user has access to a different set of commands.

On start up, the user will be on the dashboard layer and has an overview of all their modules. They will have access to module management commands such as adding, deleting or opening a particular module. Opening a module then puts them on the module layer where they can interact with the data within the module.

2-Layer System
Figure 1 - Visualisation of GULIO’s 2-layer system

Currently, GULIO is a basic university module manager intended to provide students with an overview and consolidated workspace for all of their modules, lessons, tasks and cheat-sheets. Going forward, we feel that GULIO has the potential for many more features to be added, some of which are proposed in the Implementation section.

Scope

This document describes the software architecture and software design decisions for the implementation of GULIO. The intended audience of this document is the developers, designers, and software testers of GULIO.

 

🡅 Back to Table of Contents


Design

Architecture

Architecture Diagram
Figure 2 - GULIO Architecture Diagram

Duke contains the main method which is required by Java to run the application. It is responsible for instantiating and calling methods from the UI, Parser and Command components.

Apart from Duke, the application consists of the following components:

GULIO is a local application that stores its application data using readable text files, allowing users the flexibility of viewing and editing data locally.

The way GULIO runs and handles user input can be described as follows:

Sequence Diagram
Figure 3 - GULIO Sequence Diagram

Upon starting up GULIO, the Duke (main) class calls run() which enters a while loop and reads in user input. In the loop, the Parser component processes the user input into various commands implemented in GULIO. The loop ends when the user enters exit.

 

UI Component

API: UI.java

 

Parser Component

API: Parser.java

 

Command Component

Dual Layer Command System
Figure 4 - Visualisation of Dual Layer Command System

API: Command.java

The Command component consist of an abstract Command class, as well as its subclasses. Each subclass handles a specific command in GULIO. The abstract Command class contains methods that these commands inherit from.

Steps for command execution:

  1. The Parser validates user input and returns a Command object to Duke
  2. Duke calls the execute method in the Command object
  3. Depending on the command, it may make changes to the objects within the Model component
  4. If there are changes, the Model component then updates application data via the Storage component
  5. The UI prints user information related to the command executed

 

Model Component

Class Diagram of Model
Figure 5 - Class Diagram of Model

The Model component consists of classes that represent real-world objects related to the program. ModuleList represents the various modules that a typical SoC student may be taking within the semester. Each of these modules is encapsulated in the Module class which contains an ArrayList of Lesson and Task objects representing the lessons that would be conducted for the module and tasks that students have to complete for the modules they are taking.

ModuleList:

ModuleList is responsible for managing loaded modules in the program and keeping track if a user is at the dashboard or within a selected module. ModuleList interacts with instances of the Loader and Writer class to load and write data respectively to the storage files. It also contains methods to sort data.

The ModuleList class contains the attributes:

Module:

The Module class contains the attributes:

Lesson:

In SoC, lessons are conducted by a combination of lectures, tutorials or labs. To enforce this constraint, the Enum class LessonType contains a set of constants for lecture, tutorial and lab.

The Lesson class contains attributes related to a typical course lesson:

Teaching staff:

Being enrolled in several modules, it would be useful for students to store names of the teaching staff the way they prefer to be addressed along with their email addresses in events that require the student to call upon or inquire a teaching staff for a module.

The TeachingStaff class contains the attributes related to the teacher(s) of a particular lesson:

Task:

The Task class contains attributes related to an assignment, deadline or task in a university setting

 

Storage Component

Storage Structure
Figure 6 - Illustration of Storage Structure

The Storage component is responsible for creating and loading modules and their respective data, as well as saving the data each time a change is made. It consists of two classes: Loader and Writer. At every moment, Loader only loads up to 1 module at a time and data for each module is stored separately. This is done to ensure fast loading and writing of files.

Loader:

Writer:

 

Editor Component

API: TextEditor.java

The Editor component is responsible for opening the text editor to add or edit cheat-sheets/notes. It consists of two classes:

Text Editor

ShortcutListener

 

Common Classes

Classes that are used by multiple components:

 

🡅 Back to Table of Contents


Implementation

In this section, we highlight a few of the key features whose implementations are reflective of most of the commands available, as well as those that are more unique to GULIO.

Adding of Lesson

The AddLessonCommand class is responsible for the creation and addition of a new Lesson object to the lesson list of a given module. The following sequence diagrams shows how a new Lesson is created and added to the lesson list.

parse() Sequence Diagram
Figure 7 - parse() Sequence Diagram

The creation process is facilitated by the Parser class, which parses the appropriate arguments from the user input and initialises the Lesson object attributes with the parsed values.

AddLessonCommand Constructor Sequence Diagram
Figure 8 - AddLessonCommand Constructor Sequence Diagram

The newly created Lesson object is then passed to a new AddLessonCommand object as an argument.

execute() AddLessonCommand Sequence Diagram
Figure 9 - execute() AddLessonCommand Sequence Diagram

AddLessonCommand then adds the Lesson object to the lesson list of a module. The lessons in the list are sorted by their lesson types each time a new lesson is added. AddLessonCommand also calls the writeLesson() method of ModuleList to update the change locally.

 

Adding of Cheat-Sheet

The AddCheatSheetCommand class enables the creation, addition and saving of a “.txt” file to the current module’s “Cheatsheet” directory (see Figure 6). Upon creating a new instance of it and calling the execute() method on it, a text editor window will also be automatically opened if there is none opened yet.

An invocation of the add cheat-sheet command involves the following interactions:

AddCheatSheetCommand Invocation Sequence Diagram A
Figure 10a - AddCheatSheetCommand Invocation Sequence Diagram

When AddCheatSheetCommand is executed, it gets the currently selected module by calling the getSelectedModule() method in ModuleList. It then checks if the file name given by the user is invalid. If no, AddCheatSheetCommand proceeds to call the getDirectoryPath() method in itself to obtain the directory where the cheat-sheet would be saved to. It then calls the openTextEditor() method itself, which will interact with the TextEditor class, a Singleton class, in the following way:

AddCheatSheetCommand Invocation Sequence Diagram B
Figure 10b - Opening the Text Editor

The openTextEditor() method will first check if the single instance of TextEditor is null. If it is, then there is no text editor window currently opened and openTextEditor() proceeds to call the createNew() method of TextEditor. This initialises the single instance of TextEditor by calling the class constructor, which sets up, loads from previous data (if any) and opens the text editor for the user. The user can now start typing into the text editor.

 

Loading & Storing of Data

This section covers how the Storage component works, from the loading of all module codes to the loading of individual module and creation of data files.

Saving of Data

The Writer class is responsible for writing any changes to the module’s data file, as well as creating the file itself. Interaction with the Writer class is done through the ModuleList class, whose methods are called by the other components of the app.

writeModule() Sequence Diagram
Figure 11 - writeModule() Sequence Diagram

Whenever some data in a module changes, the command that made those changes would call the method writeModule() in ModuleList to update the change in the data file. This method would then call a method of the same name in the Writer class, which overwrites the existing data in the file with the new data.

Due to how much data needs to be written each time, we decided to split the data file by module. That way, we only need to overwrite the module’s data when changes are made.

Loading of Data

The Loader class is responsible for identifying all the modules currently added, as well as loading the data file of the selected class. Methods in the Loader class are accessed by the other components via the ModuleList class.

loadModuleCodes() Sequence Diagram
Figure 12 - loadModuleCodes() Sequence Diagram

To identify modules in the “Data” directory, Duke would call loadModuleCodes() method in the ModuleList. This method would then call the getModules() method in Loader, which returns a list of module codes. For each of the identified module code, ModuleList would call its own insertModule() method to add it to the module list.

setSelectedModule() Sequence Diagram
Figure 13 - setSelectedModule() Sequence Diagram

When a module is selected via the setSelectedModule() method, the specified module code would be searched for in the module list. If it is inside, loadModule() method in the Loader would be called. This method reads the module’s data file for data and adds them into a new instance of Module class. This Module is then returned to ModuleList and set as the selected module.

If the Loader failed to load the file, null would be returned. If null is not returned, ModuleList would sort the data and then use Writer to override the existing file. This is done to remove invalid entries that were initially in the file.

 

Design Considerations

Implementation of EditLessonCommand and EditTaskCommand

Future Features

  1. Add weightage for modules.
  2. Integrate with Github.
  3. Group project information for each module (e.g. group members’ emails, off-limit days).
  4. Search via a filter.

 

🡅 Back to Table of Contents


Appendix: Requirements

Product Scope

Target user profile:

  1. Needs a consolidated and personalisable workspace to organize their university modules
  2. Prefers desktop apps over other types
  3. Can type fast
  4. Is comfortable using CLI apps
  5. Is familiar with command-line shell environment

Value proposition:

Efficiently view and update regularly-needed information on modules and deadlines using a single keyboard.

 

User Stories

💡 Priority levels:
1: High (Must have)
2: Medium (Good to have)
3: Low (Unlikely to have)

Priority As a/an … I want to … So that I can …
1 new user see available commands refer to the help page when I forget how to use the app
1 NUS student add a module store useful information by module that I can easily refer to
1 NUS student faced with e-learning add a lesson consolidate regularly-needed information such as Zoom links by tutorial/lecture, for quick access before the lesson
1 busy NUS student add a task keep track of assignments and deadlines for a module in an organised to-do list
1 NUS student get an overview of the module / lesson / task list filter out specific information with a single command
2 NUS student delete a module store the information only temporarily, e.g. for the semester/term
2 NUS SoC student open a module’s cheat sheet(s) I have a handy list of tools for the module, tests and exams at my disposal
2 NUS SoC student with many team projects View a module’s project team information and contact details keep track of the various teams I am in and communicate more efficiently with my teammates
3 busy NUS student sort tasks by graded and done status know which tasks are of highest priority

Note: some are features to be implemented in future.

 

Non-Functional Requirements

  1. Text editor will only work on OS with GUI support.
  2. All other features will work on any mainstream OS.
  3. It should work for students taking up to 10 modules.
  4. Each module should be able to store 100 tasks without issues.
  5. Every command should respond within 10s of input on a typical modern computer.

 

Glossary

 

🡅 Back to Table of Contents


Appendix: Instruction for Manual Testing

Due to the 2-layer command system, you will need to identify which layer you are on in order to run the tests correctly. To identify which layer you are on, simply check the tag beside your input, known as the input label.

Dashboard Label
Figure 3a - Dashboard Layer

Module Label
Figure 3b - Module Layer

Launching GULIO

  1. Shift the file GULIO.jar to your desired directory.
  2. Open command prompt and navigate to the directory.
  3. Enter java -jar GULIO.jar into the command prompt.

    Expected outcome: Prints welcome message.

Exiting GULIO

  1. Ensure that no module is selected. Input label should show GULIO.
  2. If you see a module code instead, enter close to close the module.

    Expected outcome: Input label changes to GULIO.

  3. Enter exit.

    Expected outcome: Prints exit message and program closes.

Adding a Module

  1. Ensure that no module is selected. Input label should show GULIO.
  2. If you see a module code instead, enter close to close the module.

    Expected outcome: Input label changes to GULIO.

  3. Enter mods.

    Expected outcome: Lists all existing modules.

  4. Enter add <module> where <module> is a module code that is not in the list.

    Expected outcome: Prints success message.

  5. Enter mods again to list all existing modules.

    Expected outcome: New module is added to list.

Deleting a Module

  1. Ensure that no module is selected. Input label should show GULIO.
  2. If you see a module code instead, enter close to close the module.

    Expected outcome: Input label changes to GULIO.

  3. Enter del.

    Expected outcome: Lists all existing modules and asks for indices to delete.

  4. Enter indices of modules to delete, separated by space.

    Expected outcome: Prints success message.

  5. Enter mods.

    Expected outcome: Specified modules deleted.

Opening a Module

  1. Ensure that no module is selected. Input label should show GULIO.
  2. If you see a module code instead, enter close to close the module.

    Expected outcome: Input label changes to GULIO.

  3. Enter mods.

    Expected outcome: Lists all existing modules.

  4. Enter open <module> where <module> is a module code in the list.

    Expected outcome: Prints overview of module and input label changes to module code.

Closing a Module

  1. Check if a module is selected via the input label.
  2. If the input label shows GULIO, enter mods.

    Expected outcome: Lists all existing modules.

  3. Add a new module if the list is empty. E.g. add CS2113T
  4. Open one of the modules. E.g. open CS2113T

    Expected outcome: Prints overview of module.

  5. Enter close.

    Expected outcome: Input label changes back to GULIO.

Adding a Lesson

  1. Check if a module is selected via the input label.
  2. If the input label shows GULIO, enter mods.

    Expected outcome: Lists all existing modules.

  3. Add a new module if the list is empty. E.g. add CS2113T
  4. Open one of the modules. E.g. open CS2113T

    Expected outcome: Prints overview of module.

  5. Enter lsn.

    Expected outcome: Lists all lessons for that module.

  6. Add a new lesson. E.g. add lsn lecture ;; Friday 6pm.

    Expected outcome: Prints success message.

  7. Enter lsn.

    Expected outcome: New lesson added to list.

Deleting a Lesson

  1. Check if a module is selected via the input label.
  2. If the input label shows GULIO, enter mods.

    Expected outcome: Lists all existing modules.

  3. Add a new module if the list is empty. E.g. add CS2113T
  4. Open one of the modules. E.g. open CS2113T

    Expected outcome: Prints overview of module.

  5. Enter del lsn.

    Expected outcome: Lists all existing lessons and asks for indices to delete.

  6. Enter indices of lessons to delete, separated by space.

    Expected outcome: Prints success message.

  7. Enter lsn.

    Expected outcome: Specified lessons removed from list.

  1. Check if a module is selected via the input label.
  2. If the input label shows GULIO, enter modules.

    Expected outcome: Lists all existing modules.

  3. Add a new module if the list is empty. E.g. add CS2113T
  4. Open one of the modules. E.g. open CS2113T

    Expected outcome: Prints overview of module.

  5. Add a new lesson with a link. E.g. add lsn lecture ;; Friday 4pm ;; https://nus-sg.zoom.us/.

    Expected outcome: Prints success message.

  6. Enter link.

    Expected outcome: Lists all existing lessons.

  7. Enter indices of lessons with links to open.

    Expected outcome: Opens link for lessons selected.

 

🡅 Back to Table of Contents


Command Summary

Dashboard Commands Summary

Keyword Format
help help
exit exit
open open <module code>
add add <module code>
delete del
modules mods

Module Commands Summary

Keyword Format
help help
close close
info info
add lesson add lsn <lesson type> ;; <day & time> ;; <link> ;; <teaching staff name> ;; <email>
delete lesson del lsn
edit lesson edit lsn
link link
teacher tch
lessons lsn
add task add task <task name> ;; <deadline> ;; <remarks>
delete task del task
edit task edit task
mark mark
unmark unmark
tasks task
add cheat-sheet add cs <cheat-sheet name>
delete cheat-sheet del cs <cheat-sheet name>
edit cheat-sheet edit cs <cheat-sheet name>
cheat-sheets cs

 

🡅 Back to Table of Contents