[Github]
PROJECT: Cow
1. Overview
Cow is a project management app with an emphasis on Command Line Interface ("CLI") interaction. It allows users to completely manage their contacts and tasks without taking their fingers off the keyboard. In addition, a calendar view is available the user to visualise his tasks.
Cow is written in Java, and its Graphical User Interface ("GUI") is created with JavaFX. It has approximately 15k LoC. This portfolio documents my contributions to this project.
2. Summary of contributions
-
Major enhancement: added the ability to visualise tasks in a calendar
-
What it does: allows the user to view all tasks due in a specified month through the
calendar show
command. -
Justification: This feature achieves a significant improvement in the task management workflow by allowing easier and more intuitive deadline management. The user would be able to visualise his tasks for the entire month via the calendar view instead of in a single list.
-
Highlights: This enhancement involves significant changes to the GUI. It requires a good understanding of the tools available via JavaFX in order to both build the feature and test it. In addition, the implementation was challenging as it involved changes at multiple levels in the app.
-
-
Code contributed: Collated code at RepoSense
-
Other contributions:
3. Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.
Calendar features section |
3.1. Calendar
Clicking on an entry in the calendar would display it in the task details panel. |
3.1.1. View calendar for tasks due within given year and month: calendar show
Displays the specified month in the calendar panel.
Format: calendar show y/YEAR m/MONTH
Entries from the end of the previous month and the start of the following month may also be displayed depending on the length and start day of the specified month. |
Examples:
-
calendar show y/2018 m/12
Displays tasks due in December 2018 in the calendar.
4. 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.
Implementation details of the calendar show feature |
4.1. Calendar show feature
4.1.1. Current Implementation
The calendar show feature is facilitated by the ModelManager
and displayed through the CalendarPanel
. The purpose of this feature is to allow the user to more easily view his tasks.
This feature can be broken down into two stages: updating the model based on user input and rendering the UI.
Stage 1: Input handling
The following operation is exposed via the Model
interface:
-
Model#updateCalendarMonth()
— Saves the given calendar that encapsulates the month to be displayed in the calendar panel.
The basic flow of the calendar show
command is as such:
Step 1. The user enters the command calendar show y/2018 m/12
Step 2. The command is parsed and a ShowCommand
object is created with the appropate values for year and month.
Step 3. The ShowCommand#execute()
method is invoked, and Model#updateCalendarMont()
is called with a Calendar
object encapsulating the first day of the specified month 1 Dec 2018
.
The date of the month is arbitrarily chosen. However this is not strictly necessary as the necessary processing will be done by the UI component when rendering the calendar. |
This is summarised in the following image.
Stage 2: UI Rendering
The following operation is exposed via the Model
interface:
-
Model#getCalendarMonth()
— Returns anObservableValue<Calendar>
for the calendar UI elements to determine the month to display and the weekday it starts on.
Given below is how the calendar UI is initialised.
Step 1. The user launches the application. The Model
is initialised with a ObservableValue<Calendar>
representing the current date. The MainWindow
class calls Model#getCalendarMonth()
and Model#getFilteredTaskList()
when creating the CalendarPanel
. This initialises the CalendarPanel
with an ObservableList<Task>
and ObservableValue<Calendar>
to allow it to perform UI updates when necessary.
Step 2. The CalendarPanel
constructs a GridPane
and sets the row and column constraints.
Step 3. The CalendarPanel
populates the GridPane
. The cells in the header row are populated with CalendarHeaderCell
elements containing the days of a week. All other cells are populated with CalendarContentCell
elements based on its position in the grid. The CalendarContentCell
elements are intialised with the ObservableList<Task>
and ObservableValue<Calendar>
.
Step 4. The CalendarContentCell
computes the date that it represents based on the calendar it receives and its position in the grid. It then creates a FilteredList<Task>
from the ObservableList<Task>
that only contains tasks belonging to that state. Finally, the ListView<Task>
element configured to display elements in the FilteredList<Task>
with CalendarTaskCard
elements.
Step 5. The CalendarContentCell
listens to updates to the ObservableValue<Calendar>
that would update the predicate for the FilteredList<Task>
.
Step 6. The CalendarPanel
writes the header for the month and year it is displaying.
Step 7. The CalendarPanel
listens to updates to the ObservableValue<Calendar>
that would update the calendar header with the month and year of the new value.
Initialisation complete.
Given below is how calendar show
command is handled by the UI components.
Step 1. The user enters calendar show y/2018 m/1
. This causes Model#updateCalendarMonth
to called, which sets the new value for the ObservableValue<Calendar>
.
Step 2. The update to the ObservableValue<Calendar>
triggers the listener registered by the CalendarPanel
. This causes the calendar header to be updated via CalendarPanel#handleUpdateCalendar
.
Step 3. The update to the ObservableValue<Calendar>
triggers the listener registered by the CalendarContentCell
. This causes it to recompute the date that it represents and update the predicate for its FilteredList<Task>
. This causes cell to display the appropriate tasks based on the new designated month.
Update complete.
The image below summarises the abovementioned mechanism for a single cell in the calendar.
4.1.2. Design Considerations
Aspect: Where to filter tasks by month for displaying in the calendar.
-
Alternative 1 (current choice): Calendar object representing current month and full task list passed to calendar pane, all filter operations done in the calendar pane.
-
Pros:
-
Less data duplication.
-
Allows effect of task filtering via the CLI to also be visible in the calendar view.
-
Allows display of tasks in adjacent months.
-
-
Cons:
-
Slightly less efficient since each cell needs to filter the entire task list.
-
-
-
Alternative 1: Done in the model
-
Pros:
-
Application logic does not reside in the view layer.
-
-
Cons:
-
Repeated filtering at multiple steps.
-
Task data is duplicated in multiple places.
-
Difficult to display events from adjacent months.
-
-
Aspect: Construction of grid cell.
-
Alternative 1 (current choice): Cells are constructed once and contents are updated each time the month is changed
-
Pros:
-
Better performance: Deleting and recreating elements incurs some computational cost.
-
Cleaner abstraction: Code better follows Single Responsibility Principle. Updating of predicate for a
FilteredList<Task>
more accurately represents the actual behaviour being modelled.
-
-
Cons:
-
Increased complexity of implementation.
-
-
-
Alternative 2: Delete and regenerate cell contents each time the month is changed
-
Pros:
-
Ease of implementation.
-
-
Cons:
-
Poorer performance.
-
Messy code. One huge class will be used for the entire calendar.
-
-
Use cases of the calendar show feature |
4.2. View calendar
MSS
-
User requests to display calendar for specified month and year.
-
Cow displays the specified month and year in the calendar panel populated with tasks based on task end date.
Use case ends
4.3. List calendars
MSS
-
User requests to list calendars.
-
Cow displays list of all calendars I have access to, including shared calendars.
Use case ends
4.4. Import calendar
MSS
-
User requests to import calendar XML file and specifies calendar name.
-
Cow imports tasks contained in XML file into the a calendar with the specified name.
Use case ends
Extensions
-
2a. A calendar already exists with the specified name.
-
2a1. Cow notifies the user and merges the incoming calendar with the pre-existing calendar.
Use case ends.
-
4.5. Share calendar
MSS
-
User requests to share his calendar.
-
Cow exports an XML file containing all current existing tasks to the specified path.
Use case ends
Manual testing instructions for the calendar show feature |
4.6. Calendar Show
Tasks with long names will be truncated in the calendar. If there are more than 5 tasks ending on that day, the cell will be scrollable, but a scroll bar is not displayed due to space constraints. |
-
Calendar show command displays specified month in calendar.
-
Test case:
calendar show y/2018 m/1
Expected: Calendar header changes to "January 2018". Days of the week should be correctly displayed.
-
-
Calendar displays tasks ending in specified month.
-
Pre-requisites:
-
List all tasks using the
tasks list
command. -
Display calendar for January 2018 using the
calendar show y/2018 m/1
command.
-
-
Test case:
tasks add n/test calendar show sd/20170101 ed/20180115 et/1200
Expected: Cell corresponding to 15 Jan 2018 contains the entry displaying "test calendar show".
-
-
Calendar displays multiple tasks due on the same day
-
Pre-requisites: List all tasks using the
tasks list
command. -
Enter the
tasks add n/test calendar multiple sd/20170101 ed/20181212 et/1200
command 3 times. -
Enter the
calendar show y/2018 m/12
command.
Expected: Cell corresponding to 12 December 2018 has multiple entries displaying "test calendar multiple".
-
-
Calendar displays adjacent months correctly.
-
Pre-requisites:
-
List all tasks using the
tasks list
command. -
Display calendar for December 2018 using the
calendar show y/2018 m/12
command.
-
-
Test case:
tasks add n/test calendar previous month sd/20170101 ed/20181127 et/1200
.
Expected: Cell corresponding to 27 November 2018 has one new entry displaying "test calendar previous month". -
Test case:
tasks add n/test calendar following month sd/20170101 ed/20190102 et/1200
Expected: Cell corresponding to 2 Jan 2019 has one new entry displaying "test calendar following month".
-
-
Default displayed calendar on app startup.
-
Create task ending in the current month.
-
Shut down the app
-
Launch the app
Expected: Calendar displays the current month. Calendar should be populated with tasks ending in the current month.
-
-
User input is validated.
-
Test cases:
-
calendar show y/0 m/12
-
calendar show y/10000 m/12
-
calendar show y/2018 m/0
-
calendar show y/2018 m/13
-
Expected: Calendar is unchanged. Error details shown in the status message.
-