PROJECT: Student Schedule Planner


Overview

This document showcases my contributions in building desktop application Student Schedule Planner for software engineering module CS2103T as a member of team T12-3 together with other 4 members.

Student Schedule Planner is a desktop task management application built specially for university students. Our application offers university students more convenience than other todo-list application through a series of features, such as multiple tagging for each tasks, customized task and tag management and so on. This application is built on top of original Address Book Level-4, which is around 6kLoC, written in JAVA OOP fashion. Currently our Student Schedule Planner has approximately 10kLoC.

Summary of contributions

  • Major enhancement: Major enhancement: Task management, which mainly involves two components: one is archive and another is category.

    • What it does: Archive command allows users to archive completed tasks. Archived tasks are stored in separate list, which can be viewed with command listarchived. The tags used on tasks can be managed by customizable categories by adding tags to relevant category.

    • Justification: Archive is a necessary command for a task managing application, because users have the need to hide completed tasks, and review them in a separate list.
      As for category, our application allows user to attach multiple tags to a task when adding the task. Category gives user further freedom and power to manage the tags according to their needs. Our user can create their own categories and add relevant tags into a category.

    • Highlights: Both functions, especially category, required good planning of detailed implementation as well as deep understanding and prediction of user-experience. It required deep analysis of users' demand as well as sophisticated and sustainable design to decide how to let user organize the tags and what to use, and the implementation involved building a whole new set of structure and commands. This enhancement affects the future direction and feature design of schedule planner.

  • Code contributed: RepoSense

  • Other contributions:

    • Project management:

      • Morphed AddressBook application to Schedule Planner: #39, #25, #15, #12

    • Enhancements to existing features:

      • Added sorting feature that allows tasks to always be displayed in the order of deadline date and priority.

      • Added automatic deletion feature that deletes archived tasks with deadline date earlier than 2 weeks before current date whenever application launches.

    • Documentation:

      • Documentation: Reformatted and edited existing User Guide: #56, #69, #73

    • Community:

      • Reported bugs and suggestions for other teams in the class: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

    • Tools:

      • Integrated Codacy to the team repo

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Archiving a Task

Archives the specified task from the schedule planner. Once a task is archived, it will be hidden from task list. You can view archived tasks in archived task list using listarchived command. For detailed guide regarding viewing archived tasks, please refer to [Viewing Archived Tasks].

archive INDEX

Example:

archive 1

Task with index 1 is removed from the task list.
Below is the partial screenshots of task list before and after executing the archive command.

archiveTask

The INDEX refers to the index number shown in the displayed task list. Refer to the task according to the index number. The INDEX must be a positive integer 1, 2, 3, …​ INDEX refers to the index of the task in the displayed task list. Refer to the task according to its index number. The INDEX must be a positive integer(≥1)

Use the listarchived command to find out the index of the task to be archived. View [Viewing Archived Tasks] for detailed guide.
Any archived tasks with deadline date earlier than 2 weeks before current date will be deleted from schedule planner when the application relaunches.

Adding a Category

Add a new category to the schedule planner. You can organize tags by adding tags to relevant categories. For detailed guide about how to add tags to category, please refer to [Adding a Tag to a Category].

addcat c/CATEGORY

Example:

addcat c/Steam shopping list

addingcat

Category name can contain space. For example, Steam, Steam2, Steam shopping list are all valid category names.

Modules and Others are two categories exist by default.

Please take note that category is case-sensitive. For example, category cats and category Cats are considered different.
Duplicated categories are not allowed in schedule planner. All categories must have different names.
All non-default categories (categories except Modules and Others can be removed. For detailed guide about how to remove categories, please refer to Deleting a Category.
All non-default categories (categories except Modules and Others can be renamed. For detailed guide about how to rename categories, please refer to Renaming a Category.

Clearing a Category

Clears all tags saved under selected category. After executing this command, the selected category will not contain any tags.

clearcat c/CATEGORY

Example:

clearcat c/Modules

clearcat

When a category is cleared, tags saved in other categories are not affected. For instance, in above example, if you have tag CS2105 in category Others as well, after clearing category Modules, tag CS2105 will still exist in category Others.
On the other hand, if tag CS2105 is only saved under category Modules, then after clearing category Modules, the tag CS2105 will be removed from schedule planner.

Deleting a Category

Delete an existing category from schedule planner.

removecat c/CATEGORY

Example:

removecat c/Steam shopping list

removecat
Default categories Modules and Others cannot be removed. The only operation available for default categories is to delete all tags saved under these two categories. For more detailed guide about how to do so, please refer to Clearing a Category.

Renaming a Category

Edit the name of an existing category.

editcat c/ORIGINAL CATEGORY NAME c/NEW CATEGORY NAME

Example:

editcat c/Steam shopping list c/Reading list

editcat
Default categories Modules and Others cannot be renamed.
Duplicated categories are not allowed in schedule planner. Please make sure the new name for selected category does not overlap with other existing categories in your schedule planner.

Viewing Tasks in the Order of Deadline Date and Priority

All tasks are automatically loaded in the order of deadlines except for archived tasks. The order of tasks first depends on deadline date, then priority.
Given below is an example of two tasks with different deadline dates. Task Do CS2030 lab is listed before task Self study because it has earlier deadline date.

sortingdate

Sorting Tasks by Deadline Date and Priority

All tasks are sorted chronologically by default. The order of tasks first depends on deadline date, then priority.

Given below is an example of two tasks with different deadlines. Task Do CS2030 lab is listed before task Self study because it has earlier deadline.

sortingdate

If two tasks have the same deadline, then the order depends on priority, one that has higher priority will appear before one that has lower priority. 3 is the highest priority, while 1 is the lowest.
Given below is an example of two tasks with the same deadline dates.

sortingpriority
Please take note that archived tasks are not shown in order.

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Managing Tags Using Category

The category feature enables users to organize their tags. Users can create category and save relevant tags inside category. There are two default categories in schedule planner, category Modules and category Others. These two default categories cannot be renamed or deleted, but user have full freedom to rename or delete other categories added by themselves.

Current Implementation

Each category has a unique name, and contains a list of tags. The list of tags is implemented using UniqueTagList, which does not allow duplicates, in other words, tags with same name. Given below is a snippet of implementation of UniqueTagList:

public class UniqueTagList implements Iterable<Tag> {
    private boolean tagsAreUnique(List<Tag> tags) {
        //Checks if tags are unique...
    }
}

Given below is a snippet of implementation of category:

public class Category {
    //Two attributes, name and tag list
    private String name;
    private UniqueTagList tags;

    ///Other implementation...
}

Schedule Planner contains a list of cateogry list, implemented using UniqueCategoryList. UniqueCategoryList is a list used to save categories which does not allow duplicates. Any two categories with same name are considered identical. Given below is a snippet its implementation:

public class UniqueCategoryList implements Iterable<Category> {
    public boolean contains(String name) {
        //Checks whether this category name has been used...
    }

    private boolean categoriesAreUnique(List<Category> categories) {
        //Checks whether there are duplicate categories...
    }
    //Other implementation...
}

Given below is an example usage scenario and how the category mechanism behaves at each step:

Step 1. User enters command addcat c/Game list to add a category named Game list.

  1. The addcat command is executed. AddCategoryCommand#execute() calls Model#addCategory().

  2. Model#addCategory() calls VersionedSchedulePlanner#addCategory().

  3. SchedulePlanner#addCategory() then calls UniqueCategoryList#add().

  4. UniqueCategoryList#add() checks if the existing category list contains any category with identical name as new category, if exists, DuplicateCategoryException() is thrown; if not, new category is created and added to category list.
    Given below is the sequence diagram of add category command which explains how the mechanism works:

AddCategoryCommand
Figure 1. Sequence Diagram of Add Category Command

When user is adding tasks using unspecified tags (tags that have never been added to any category), the tags will be automatically added to default category Others.

Step 2. User enters command addtag c/Game list t/Zelda to add tag Zelda into category Game list.

  1. The command string is first passed to AddTagCommandParser, which parses string Zelda to tag (let us call it tagZelda) and creates AddTag command.

  2. The command is then executed. AddTagCommand#execute() calls Model#addTag() and passes tagZelda and string Game list as parameter.

  3. Model#addTag() calls VersionedSchedulePlanner#addTag(), passes in tagZelda and string Game list as parameter.

  4. VersionedSchedulePlanner#addCategory() then calls UniqueCategoryList#getCategory(), passing in string Game list as parameter and obtains corresponding category (let us call it categoryGameList).

  5. Category#addTag() is then called with parameter categoryGameList to add tag tagZelda to category categoryGameList. If there already exists a tag named Zelda in UniqueTagList of category categoryGameList, exception DuplicateTagException is thrown.

Given below is the sequence diagram of add tag command.

AddTagCommand
Figure 2. Sequence Daigram of Add Tag Command

Step 3. User enters command editcat c/Game list c/Reading list to rename category from Game list to Reading list.

  1. EditCategoryCommandParser creates EditCategoryCommand. When EditCategoryCommand executes, it calls Model#editCategory() and passes in string Game list and string Reading list as parameter.

  2. Model#editCategory() calls VersionedSchedulePlanner#editCategory() with parameter string Game list and string Reading list.

  3. VersionedSchedulePlanner then calls UniqueCategoryList#setCategory() to obtain the category named Game list (let us call it categoryGameList) and create a new category with name Reading list and same tag list as category categoryGameList, replace category categoryGameList with this new category. Below is a snippet of implementation of UniqueCategoryList#setCategory() used here:

    public void setCategory(String originalName, String newName) {
        //...
        //Obtain the category with name "Game list"
        Category oldCategory = getCategory(originalName);
        //Creat a new category which is identical to original category except name
        Category newCategory = new Category(newName, oldCategory.getUniqueTagList());
        internalList.set(internalList.indexOf(oldCategory), newCategory);
    }

Given below is the sequence diagram of edit category command:

  1. Sequence Diagram of Edit Category Command

EditCategoryCommand

Step 4. User enters command removecat c/Reading list to remove the category named Reading list. Let us call this category categoryReadingList.

  1. RemoveCategoryCommandParser creates RemoveCategoryCommand.

  2. When RemoveCategoryCommand executes, it calls Model#removeCategory() and passes in string Reading list as parameter.

  3. Model#removeCategory() calls VersionedSchedulePlanner#removeCategory() with parameter string Reading list.

  4. VersionedSchedulePlanner then calls UniqueCategoryList#removeCategory() to obtain category named Reading list (let us call it categoryReadingList) and remove it.

  5. After categoryReadingList is removed, its tag list is removed as well. For example, if user has added tag Zelda only in category named Reading list, then after removing this category, tag Zelda will be lost from schedule planner.

Given below is the sequence diagram of remove category command:

RemoveCategory
Figure 3. Sequence Diagram of Remove Category Command

Besides adding tag, renaming (editing) and removing, we support clearing category as well. Clear category command clears the tags list of selected category. Mechanism of clearing category is very similar to renaming (editing) category. Model#clearCategory() calls VersionedSchedulePlanner#clearCategory(), which then initialize a new empty category with name "Modules". Below is a code snippet of VersionedSchedulePlanner#clearCategory():

    public void clearCategory(String name) {
        //...
        this.categories.setCategory(name, new Category(name));
    }

Below is a code snippet of #UniqueCategoryList#setCategory()` used here, which is slightly different from what is used in editing category:

    public void setCategory(String originalName, Category newCategory) {
        //...
        Category oldCategory = getCategory(originalName);
        internalList.set(internalList.indexOf(oldCategory), newCategory);
    }

We omit the sequence diagram here because of its similarity to edit category command.

Design Consideration

Aspect: How to store and manage tags
  • Alternative 1 (current choice): Store Categories as UniqueCategoryList and allow users to add tags to categories. There will be no UniqueTagList directly managed by schedule planner. All tags are saved under UniqueTagList under individual Category. Because our application is catered for university students, we set two default categories, Modules and Others.

    • Pros: We allow users more freedom to manipulate with their tags and categorize their tags. User can add one tag to several categories, and the tags saved under different categories do not interfere with each other. This is the most user-friendly design we can think of so far.

    • Cons: The implementation is more complicated than Alternative 2. Besides, this mechanism requires more commands to operate, which could be harder for user to remember.

  • Alternative 2: Store tags in UniqueTagList directly managed by schedule planner. The schedule planner has two tag lists, one is Modules and another one is Others.

    • Pros: It is easy to implement, and the operation requires less commands.

    • Cons: User has less freedom in managing tags. This design is less user-friendly than Alternative 1.

Automatic Partial Deletion of Archived Tasks

The automatic deletion feature removes archived tasks with deadlines date earlier than 2 weeks ago from current time point from archived task list. There are two main reasons behind this feature.
Firstly, we want to optimize the user experience of viewing archived tasks. Users should be able to view archived tasks, but displaying all archived tasks would make the archived task list too bulky and hard to view. In other words, we want to stop the archived task list from growing to infinity.
Another reason is we want to save storage space used by our application as much as possible.

Current Implementation

Every time when the application is launched, archived list is checked through. Tasks with deadline date earlier than 2 weeks ago are then permanently deleted from archived task list.

AutoDelete
Figure 4. Sequence Diagram of automatic partial deletion of archived tasks feature

Given below is detailed explanation of how auto-deletion mechanism behaves:

  1. Application is launched

  2. MainApp#init() is called, which instantiates Model class and calls Model#autoDeleteArchived().

  3. Model#autoDeleteArchived() then calls TaskList#autoDelete(). Note that TaskList is an object type implemented to store archived tasks. TaskList#autoDelete() then scan through archived tasks and deletes those archived tasks with deadline date earlier than 2 weeks before current time point.

Design Considerations

Aspect: What tasks should we delete?

We had a rough idea of deleting away "old" tasks. However, how should we define "old"?

  • Alternative 1 (current choice): Delete tasks with deadline date earlier than 2 weeks before current date.

    • Pros: This implementation is easier for testing. Testers do not have to alternate their system time to test the feature.

    • Cons: The logic may be less user-friendly comparing to Alternative 2. A user’s expectation is more likely to be "I can check tasks that were archived recently". For example, if user has just archived a task that has been overdue for 1 month (the deadline date of this task is 1 month earlier than current date), he/she may find it not so intuitive if next time he/she runs the app, the task cannot be found in archived task list.

  • Alternative 2 : Delete tasks that were archived 2 weeks before current date.

    • Pros: This implementation may be more user-friendly comparing with Alternative 1.

    • Cons: The feature would be hard to test for testers.

Sort tasks

The sorting feature enables tasks to be displayed in the order of deadline date and priority. This feature applies to all tasks except archived tasks.

Current Implementation

Sorting feature does not require any user input command. Whenever the tasks are listed, they are always listed according to deadline date, then priority. Our application offers 3 priority levels from 1 to 3, 3 is the highest priority and 1 is the lowest.

Assume there are two tasks in a task list, task A and task B. Given below is the scenario when task list is retrieved from schedule planner using any kind of list command and how the sorting mechanism behanves.

  1. UniqueTaskList#sorted() is called and Task#compare() is parsed in as comparator.

  2. Task#compare() calls Date.compare(), which compares the deadline date of task A and task B.

    1. If task A has earlier deadline date than task B, the order will be task A followed by task B, and vice versa.

    2. If task A and task B have the same deadline date, Priority#compare() is then called, which compares priority of task A and task B.

      1. If task A has higher priority than task B, the order will be task A followed by task B and vice versa.

      2. If task A and task B have the same priority, then Name#compare() is called, which compares the task name of A and B according to JAVA compareTo() method of String class.

Given below is a sequence diagram of the sorting feature.

Sorting
Figure 5. Sequence diagram of sorting feature.

Design Considerations

Aspect: How should sorting be executed
  • Alternative 1 (current choice): Automatically sort tasks whenever tasks are listed. In other words, whenever tasks are shown on UI, they are sorted according to deadline and priority.

    • Pros: The user experience is better using this approach, because tasks are always listed in the order of deadline and priority. The code required is less than Alternative 2 as well.

    • Cons: The performance of the application may be affected if the task list size is significantly large, because the task list has to be traversed and sorted before displaying on UI. Of course considering actual use case, such performance issue should be negligible.

  • Alternative 2: Implement sort command exclusively for sorting tasks. For example, use command sort tasks to obtain sorted list of all tasks, and sort archived for sorted list of archived tasks.

    • Pros: We do not have to worry about performance issue.

    • Cons: Users have to type command sort every time, which is apparently not so user-friendly.