- Introduction
- Development
- Setting Up
- Architecture
- UI Component
- Logic Component
- Model Component
- Storage Component
- Commons Package
- Testing
- Dev Ops
- Troubleshooting
- Known Issues & Future Plans
- Appendices
Introduction
CommanDo is a to-do list manager. It is designed to cater to the needs of people who type fast. The user manage his/her to-do list by typing commands on a text input - just like in a Command Line Interface (CLI). To-dos are displayed on a graphical user interface (GUI), split into 2 panels of Events (To-dos with a date range) and Tasks (To-dos without a date range), as shown below:
This guide describes the development of CommanDo, how it is currently designed and implemented at a technical level, some of its known issues, and some planned developments and extensions for it.
If you are a new developer, we warmly welcome you on board to our CommanDo team! If you are someone interested to join us in this exciting project, we invite you to contact us to help make CommanDo even better.
Development
Target Users
Our main target users (Jim) are characterised by people who...
- Have most to-dos coming as emails
- Update their to-do list very often and desire speed in doing so
- Want to capture the idea of deadlines in their to-dos
Our Product Survey has revealed that many of the existing to-do list managers are unable to satisfy the needs of our main target users, especially in terms of speed of entry and absence of deadlines.
Features
In summary, we are focusing on these features:
- 2 types of to-dos: Events and Tasks, displayed in separate panels in chronological order.
- Command-line style input, with commands being short, flexible and intuitive.
- Able to search through to-dos easily, empowered by a tagging system.
- Undoing and redoing to-do list operations.
- Importing and exporting to-do list to a human-readable data file.
The full list of features is outlined in our User Stories. To ensure that the interface is user-friendly and the codebase stays maintainable, we also set ourselves some Non-Functional Requirements.
Setting Up
Prerequisites
-
JDK
1.8.0_60
or later (Install it here) - Eclipse IDE
- e(fx)clipse plugin for Eclipse (Do the steps 2 onwards given in this page)
- Buildship Gradle Integration plugin from the Eclipse Marketplace
Importing Project into Eclipse
- Fork this repo, and clone the fork to your computer.
- Open Eclipse (Note: Ensure you have installed the e(fx)clipse and buildship plugins as given in the prerequisites above).
-
Click
File
>Import
. -
Click
Gradle
>Gradle Project
>Next
>Next
. - Click
Browse
, then locate the project's directory. -
Click
Finish
.- If you are asked whether to 'keep' or 'overwrite' config files, choose to 'keep'.
- Depending on your connection speed and server load, it can even take up to 30 minutes for the set up to finish (This is because Gradle downloads library files from servers during the project set up process).
- If Eclipse modifies any settings files during the import process, you can discard those changes.
Architecture
This section explains the high level design of the application. The architecture of CommanDo is as follows:
The MainApp
class is the entry point of the application. It is responsible for:
- On application launch, initializing all components in the correct sequence, and connecting them up with one another.
- On application exit, shutting down all components and invoking cleanup methods where necessary.
The application consists of 4 components, each with distinct roles:
-
UI Component: Acts as the middleman between the user and the API provided by Logic (package
seedu.commando.ui
) -
Logic Component: Executes commands from the UI, using the API provided by Model and Storage (package
seedu.commando.logic
) -
Model Component: Defines how data is represented and holds the data of the application in-memory (package
seedu.commando.model
) -
Storage Component: Reads data from and writes data to the file system (package
seedu.commando.storage
)
To minimize coupling and help with unit testing, the API of each component is defined by a single Java interface known publicly. This Java interface corresponds to the name of component (e.g. Logic has the interface Logic.java
). Each component then exposes its functionality using a concrete class implementing its interface, as listed below:
UI | Logic | Model | Storage |
---|---|---|---|
UIManager.java which implements UI.java |
LogicManager.java which implements Logic.java |
ModelManager.java which implements Model.java |
StorageManager.java which implements Storage.java |
Note that for the Model component, besides the API defined byModel.java
, it also contains data structures such as theUserPrefs
andReadOnlyToDo
classes that the other components are dependent on.
Underlying all 4 components are the package seedu.commando.commons
. It is a collection of utility classes and application constants that are used in all the components. We use Event Driven Design for components to communicate with one another, and manage logging through a centralized Logs Center.
What Happens in a Command Execution
When the user types a command and presses Enter, the UI calls the execute(String)
method of Logic with the input string. Logic parses the input string and determines the command type. Then, Logic would call methods of the Model to modify the to-do list, or post events to the Events Center (which would in turn trigger the relevant components to take action). Refer to the following diagram for the execution of command >> add task
.
Typically, a command would modify the to-do list in the Model (add
, edit
, delete
, etc). Within Model, as we have used JavaFX's Observable classes, the modification would trigger a call to the UI to update its view of the to-do list. On top of that, Model would post a ToDoListChangedEvent
to the Events Center, which would trigger Logic to call the saveToDoList(ReadOnlyToDoList)
method of Storage. Subsequently, when the to-do list is successfully saved to the file system, the event ToDoListSavedEvent
would be posted to update the status bar in UI. Refer to the following diagram for a graphical walkthrough of this sequence.
UI Component
The UI component (package seedu.commando.ui
) is in charge of:
- Handing and passing user input to the appropriate methods of the Logic component.
- Displaying the graphical user interface (GUI).
- Updating the GUI automatically when data in the Model component changes, done by binding itself to the data using JavaFX's Observable collections.
- Responding to events posted in EventsCenter that involve a change in the GUI (e.g. opening the help window when
ShowHelpRequestEvent
is posted).
It uses the JavaFX UI framework (more information about JavaFX here) - it is made up of GUI parts such as CommandBox
, ResultDisplay
and EventListPanel
. Each part has a class inheriting from the abstract UiPart
class (which may be loaded with UiPartLoader
), and has a layout defined in a corresponding .fxml
file of the same name, located in the resources/view
folder. For example, the layout of the MainWindow
class is specified in resources/view/MainWindow.fxml
.
How the GUI Updates
The UI component adds change listeners to 2 Observable lists of UiToDo
: one for Events in the EventListPanel
class, another for Tasks in the TaskListPanel
class. These lists are provided through the API of Logic. When the Model component updates the to-do list, these lists will also update (which will be described in detail later), and this triggers each panel's ListView
to update its contents based on the lists.
Logic Component
The Logic component (package seedu.commando.logic
) is in charge of:
- Parsing the string commands from the UI component through the
excute(String)
method. - Calling the appropriate methods of Model and Storage components, or posting the appropriate events on EventsCenter based on the commands.
- Informing the UI of the results of the commands executed.
- Responding to any events from EventsCenter that would require an action on the
Model
orStorage
components (e.g. saving the to-do list to the file system with Storage when theToDoListChangeEvent
is posted). - Relaying the data of Model to the UI through its methods of
getUiEvents()
,getUiTasks()
andgetToDoList()
.
When execute(String)
is Called
When the UI calls execute(String)
, LogicManager
passes the string command to CommandFactory
. CommandFactory
, with the help of CommandParser
, would determine the type of command and parse it accordingly, creating one of the sub-class of the abstract Command
class. The Command
would then have its execute()
method called in LogicManager
, producing a CommandResult
. The CommandResult
is finally returned to UI, which contains the user feedback message and indicates whether the command was successful. Refer to the following diagram for a graphical walkthrough.
Parsing of Datetimes
The DateTimeParser
class in charge of taking in an input string with parseDateTime(String)
, and returning a LocalDateTime
if the string represents a valid datetime. Within the class, it first validates and pre-processes the input string (using regex), then delegates the actual parsing to the Natty library.
Model Component
The Model component (package seedu.commando.model
) is in charge of:
- Defining how data in CommanDo is represented in the form of classes (e.g.
ToDo
,ToDoList
). - Keeping the user's to-do list in memory and supporting CRUD functionality to it.
- Keeping track of changes to the to-do list and support undoing and redoing of these changes.
- Exposing Observable collections of Events and Tasks that are to be shown on the GUI, as well as the filtering, sorting and assigning of indices to these to-dos for the GUI.
Changing, Undoing and Redoing the To-Do List
Within ModelManager
, the ToDoListManager
class is in charge of supporting the editing, undoing and redoing of the to-do list, hinging on the ToDoListChange
class. All commands define an edit to the to-do list in a consistent way with the ToDoListChange
class and the changeToDoList(ToDoListChange)
method, which provides greater flexibility in edits, looser coupling between Model and Logic, and more predictable effects from undoToDoList()
and redoToDoList()
, which undos or redos the most recent ToDoListChange that has been pushed to Model.
Preparing for the UI
Within ModelManager
, the UiModel
class is in charge of processing, sorting and filtering the list of to-dos for the UI. It tracks changes to the actual list of ToDo
of Model, and when a change happens, it will update the Observable lists of UiToDo
, which are exposed via getUiEvents()
and getUiTasks()
for the GUI. In an update, it will split the new list of ToDo
into Events and Tasks, filter out those which shouldn't be displayed on the GUI, sort them, assign indices to each of them in the correct order, and wraps each ToDo
in UiToDo
with some additional data.
A similar update is triggered when the user submits a command that calls clearUiToDoListFilter(...)
or clearUiToDoListFilter(...)
(e.g. the find
or recall
command).
Storage Component
The Storage component (package seedu.commando.storage
) is in charge of the reading of the data for the to-do list and the data for user preferences on the file system, as well as the saving of these data to the file system.
The StorageManager
class consists of XmlToDoListStorage
, which is in charge of reading/loading the to-do list data, and JsonUserPrefsStorage
, which is in charge of reading/loading the user preferences data. The XmlToDoListStorage
class saves/loads the to-do list data to the specified file path in XML with the help of Java Architecture for XML Binding. On the other hand, the JsonUserPrefsStorage
class saves/loads the user preferences data to the specified file path in JSON with the help of the Jackson JSON Processor library.
Commons Package
The package seedu.commando.commons
contains utility classes (in /util
), events (in /events
), exceptions (in /exceptions
), application constants and data structures used in all the components.
EventsCenter
and Event Driven Design
For components to inform one another that something has happened, we use Google's Event Bus library, packaged in the EventsCenter
class. This is especially important for lower-level components to communicate with higher-level components that they should not be dependent on. An example is the posting of ExitAppRequestEvent
by Logic to inform MainApp
to close the window.
All events should extend theBaseEvent
class and be placed in packageseedu.commando.commons.events
.
LogsCenter
and Logging
We are using the java.util.logging
package for logging. The LogsCenter
class is used to manage the logging levels and logging destinations. 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 the console and to a .log
file at the project root.
Logging Levels
-
SEVERE
: Critical problems detected which may possibly cause the termination of the application. -
WARNING
: Actions that can be continued, but with caution. -
INFO
: Information showing the noteworthy actions by the application. -
FINE
: Details that are not usually noteworthy but may be useful in debugging (e.g. print the actual list instead of just its size).
Messages
The Messages
class contains a list of static String constants that used for displaying user feedback, primarily referenced from the Logic component and the subclasses of Command
. All messages displayed to the user should be abstracted to static String constants in this class so that changes to user interaction can be easily made in the same place.
Testing
Tests can be found in the test folder (./src/test/java
). We aim to maximise our test coverage, so every class written should be accompanied by a corresponding test class in a similar path within this test folder.
Running Tests
Tests can be run in 2 ways:
-
In Eclipse - Right-click on the
./src/test/java
folder,Run as
and thenJUnit Test
. To run a subset of tests, right-click on a test package, test class, or a test instead. - Using Gradle - See UsingGradle.md for how to run tests using Gradle.
If you are not using a recent Eclipse version (i.e. Neon or later), enable assertions in JUnit tests as described here.
Types of Tests
- GUI Tests - They are System Tests that test the entire application by simulating user actions on the GUI. These are in the
guitests
package. -
Non-GUI Tests - They include:
-
Unit tests: targeting the lowest-level methods/classes.
E.g.seedu.commando.commons.UrlUtilTest
-
Integration tests: checking the integration of multiple code units (those code units are assumed to be working).
E.g.seedu.commando.storage.StorageManagerTest
-
Hybrid tests: testing multiple code units as well as how the are connected together.
E.g.seedu.commando.logic.LogicManagerTest
-
Unit tests: targeting the lowest-level methods/classes.
Headless GUI Testing By applying TestFX library, GUI tests can be run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means you can do other things on your device while the tests are running. See UsingGradle.md to learn how to run tests in headless mode.
Dev Ops
Build Automation
We use gradle for build automation - see UsingGradle.md to learn how.
Continuous Integration
We use Travis CI to perform Continuous Integration on our projects (link to our project's Travis), and we use Coveralls to track our code coverage (link to our project's Coveralls). See UsingTravis.md for more details.
Making a Release
- Generate a
.jar
file using Gradle. -
Tag the repo with the version number. e.g.
v0.1
-
Create a new release using GitHub
and upload the
.jar
file you created.
Managing Dependencies
Our project's dependencies are automated using Gradle. Gradle downloads the dependencies automatically for the new developer, which is better than the alternatives of:
- Including those libraries in the repo (this bloats the repository size).
- Requiring developers to download those libraries manually (this creates extra work for developers).
Currently, our project's dependencies include:
Troubleshooting
Frequently Asked Questions
Eclipse reports compile errors after new commits are pulled from Git.
It is likely that Eclipse failed to recognise the new files that appeared in the new commits. Refresh the project in Eclipse by right-clicking the project in the package explorer panel and choosing Gradle
> Refresh Gradle Project
.
Eclipse reports some required libraries missing.
Libraries used by the project might not have been downloaded during project import, or new ones might have been added. Run tests using Gradle once to refresh the libraries in Eclipse.
Known Issues & Future Plans
High RAM Usage
The application currently consumes quite a bit of RAM, up to 150-200+ MB of RAM when we add more than 50 to-dos. We wish to make it less resource-consuming in order to create a better user experience for those with slower systems.
Quick Access Keyboard Shortcut
One of the nice-to-have features is to allow the user to quickly summon CommanDo using a customizable keyboard shortcut, even when the application is closed. This would bring convenience to users who would view and edit their to-do list frequently.
Real-time Syntax Highlighting
A nice-to-have feature is colour-coding the input command in real-time as the user types to reflect the different fields of the command. For example, as the user types >> add event from 10 Oct 2016 9pm to 10pm weekly
in the command box, "add" (the command word), "event" (one of the command's fields) and "from" (a keyword in the command) could appear in different colours and the feedback box could state the command format for command word. This allows users to easily validate that their command visually does what they intend it to.
Appendices
Appendix A: User Stories
Priority | As a... | I want to... | So that I can... |
---|---|---|---|
* * * |
user | add to-dos | start viewing and managing my to-dos |
* * * |
user | delete to-dos | remove any outdated or invalid to-dos |
* * * |
user | edit the description of my to-dos | correct any typos or update the details of my to-dos over time |
* * * |
user | edit the time constraints of my to-dos | correct any typo or update to-dos' timings after they are postponed or confirmed |
* * * |
user | view upcoming Events in chronological order, from the current day onwards | figure out what is happening next |
* * * |
user | view my list of unfinished Tasks | figure out what I can do when I am free |
* * * |
user | mark my Tasks as done | dismiss pending Tasks that I have done |
* * * |
user with many to-dos | add tags to to-dos, and search for to-dos by tags | quickly determine what kind of classification the to-dos are when I skim through my to-do list |
* * * |
user with many to-dos | search for to-dos by their description or tags | navigate through a long list of to-dos |
* * * |
user | undo my recent edits to the to-do list | revert any mistakes made |
* * * |
user | redo my previous undos | revert any mistakes made |
* * * |
user | export or import to-dos to a specified folder | backup my to-do list or share the to-do list across multiple devices |
* * * |
user with multiple devices and a cloud-syncing service | specify a save/load location for my to-do list | keep my to-do list synchronized across multiple devices |
* * * |
new user | view a list of commands with a help command | learn about the functionality of the application while using it |
* * * |
new user | view the correct command syntax and sample commands after inputting a command wrongly | learn the correct command syntax while using it |
* * |
user | clear all the to-dos on my to-do list | start afresh with my to-do list |
* * |
user | set events and tasks with due dates as recurring | avoid having to enter identical events and tasks periodically |
* * |
user | use command keywords (e.g. "from", "to", "by") in titles of my to-dos | avoid having to change how I write my to-do because of the command keywords |
* * |
user with many to-dos | view all to-dos within a specified date range | be able to preview or review the to-dos that are upcoming or done at a glance |
* * |
user | browse and search through my past Events and finished Tasks | to review and refer to what I have done in the past |
* * |
user | receive a visual confirmation of the details of the to-do I have added/edited | be able to verify modifications to my to-do list |
* |
very active user | summon the application and have it ready for input immediately via a keyboard shortcut | quickly be able to add to or remove from my to-do list when I have to |
* |
new user | view syntax highlighting of the various fields of a command while inputting, in real time | be clear about how the application parses my to-do’s fields and avoid unintended errors in input |
Priorities:
-
* * *
- High (Must have) -
* *
- Medium (Nice to have) -
*
- Low (Unlikely to have)
Appendix B: Use Cases
In all the listed use cases, the System is our application and the Actor is the user.
UC01 - Add an Event MSS:
- 1. User types in an
add
command with details of the Event, including a title, a date range, a recurrence (if any) and tags (if any). - 2. Application adds the Event to the current to-do list and updates the GUI to reflect the changes.
- Use case ends.
- 1a. Command word is mistyped.
- 1a1. Application updates the GUI to inform the user that command word is unknown.
- Use case ends.
- 1b. Title is missing.
- 1b1. Application updates GUI to inform the user that the title is missing.
- Use case ends.
- 1c. Either of the start or end of the date range (i.e. from ... to ...) is not in a valid datetime format.
- 1c1. Application updates GUI to inform the user that the which of start date or end date is invalid.
- Use case ends.
- 1d. Both start and end of the date range (i.e. from ... to ...) are not in valid datetime formats.
- 1d1. Application considers the date range clause as part of a title, adds a corresponding Task to the current to-do list, and updates the GUI to reflect the changes.
- Use case ends.
- 1e. The start of the date range (i.e. from ... to ...) is after its end.
- 1e1. Application updates GUI to inform user that the start of the date range must not be after its end.
- Use case ends.
- 1f. The specified recurrence's interval is shorter than the specified date range.
- 1f1. Application updates GUI to inform user that the recurrence is invalid.
- Use case ends.
UC02 - Add a Task MSS:
- 1. User types in an
add
command with details of the Task, including a title, a due date and its recurrence (if any), and tags (if any). - 2. Application adds the Task to the current to-do list and updates the GUI to reflect the changes.
- Use case ends.
- 1a. Command word is mistyped.
- 1a1. Application updates the GUI to inform the user that command word is unknown.
- Use case ends.
- 1b. Title is missing.
- 1b1. Application updates GUI to inform the user that the title is missing.
- Use case ends.
- 1c. The due date (i.e. by ...) is not in a valid datetime format.
- 1c1. Application considers the due date clause as part of a title, adds a corresponding Task to the current to-do list, and updates the GUI to reflect the changes.
- Use case ends.
UC03 - Delete an Event or Task MSS:
- 1. User types in a
delete
command with the index of the to-do to delete. - 2. Application removes the to-do with the specified index from the current to-do list, and updates the GUI to reflect the changes.
- Use case ends.
- 1a. Command word is mistyped.
- 1a1. Application updates the GUI to inform the user that command word is unknown.
- Use case ends.
- 1b. Index of the to-do is not specified.
- 1b1. Application updates GUI to inform the user that the index is missing.
- Use case ends.
- 2a. Index of the to-do is invalid.
- 2a1. Application updates GUI to inform the user that the index is invalid.
- Use case ends.
UC04 - Searching through upcoming Events and unfinished Tasks MSS:
- 1. User types in a
find
command, including a list of search keywords and tags. - 2. Application searches through the to-do list and updates the GUI to show only upcoming Events and unfinished Tasks that match the search filter.
- Use case ends.
- 1a. Command word is mistyped.
- 1a1. Application updates the GUI to inform the user that command word is unknown.
- Use case ends.
- 1b. No search keywords or tags specified.
- 1b1. Application updates GUI to show all upcoming Events and unfinished Tasks.
- Use case ends.
- 2a. No to-dos were found in the search.
- 2a1. Application updates GUI to inform user that no to-dos were matched.
- Use case ends.
UC05 - Edit to-do item MSS:
- 1. User types in a
edit
command with the index of the to-do to edit, including the new title, date range, due date, and tags to edit to. - 2. Application modifies the target to-do to the current to-do list and updates the GUI to reflect the changes.
- Use case ends.
- 1a. Command word is mistyped.
- 1a1. Application updates the GUI to inform the user that command word is unknown.
- Use case ends.
- 1b. Index of the to-do is not specified.
- 1b1. Application updates GUI to inform the user that the index is missing.
- Use case ends.
- 2a. Index of the to-do is invalid.
- 2a1. Application updates GUI to inform the user that the index is invalid.
- Use case ends.
- 2b. A due date is to be added to a Event with a date range.
- 2b1. Application informs the user that a to-do cannot have both a due date and a date range.
- Use case ends.
- 2c. A date range is to be added to a Task with a due date.
- 2c1. Application informs the user that a to-do cannot have both a due date and a date range.
- Use case ends.
- 2d. A date range or due date is to be added to a Task with no time constraints.
- 2d1. Application attaches the date range or due date to the Task and updates the GUI to reflect the changes.
- Use case ends.
Appendix C: Non Functional Requirements
- Should start-up in at most 3s
- Should process every command in at most 1s
- Should work on any mainstream OS as long as it has Java 8 or higher installed
- Should be able to hold up to 1000 to-dos
- Should come with automated unit tests
- Should make the code be open source
- Should favor DOS style commands over Unix-style commands
- Should not use more than 300MB of RAM
- Should keep the number of existing files that has to be edited to add new commands at most 2
- Should not take more than 1 hour for new user to learn the commands and their syntax
Appendix D: Glossary
- Mainstream OS: Refers to Windows, Linux, Unix and OS-X.
- Event: A to-do that has a date range.
- Task: A to-do without a date range, and optionally has a deadline.
- Index of to-do item: The number visually tagged to a to-do item on the UI (changes with how to-dos are listed).
- MSS: Main Success Scenario of a use case.
- CRUD: Create, Read, Update and Delete.
Appendix E: Product Survey
We tested a few existing to-do managers and analysed how much they would meet the needs of our main target user Jim:
Product (Reviewer) | Positive points | Negative points |
---|---|---|
Google Keep (Zhiwen) | + It has high level of simplicity (clear and simple UI) + It can be easily accessed from anywhere + It supports native sync and integration with Google + Mark things done easily + Support photos, audios and lists in content |
- It is unable to do text formatting - Its search function only supports titles - It is unable to prioritise activities |
Trello (Sheng Xuan) | + It supports multiple platforms (Web, mobile, desktop) + It has due date function, which is suitable for tasks with deadlines + It can search by keyword of a task + It archives completed tasks + It has check list to track the progress of each task + It can attach files to a task (ie. forms to reply in a email) |
- It needs at least 2 clicks (taps) to add a new task - It costs money to use the calendar view functionis. In free version, no timeline is provided. Adding events that happen in specific dates are not supported - It is unable to undo |
Anydo (Conan) | + It is able to push tasks to a later date + It can easily reorder tasks + It has user-friendly interface (4 major groups) + It can be used on mobile and on browser + It supports double confirmation of deleting a task when complete + It can add details in later |
- It has no clear distinguishing of the 3 types of tasks - It has little sense of timeline, and ends up with just tasks to complete by the end of the day - Its deadlines are not shown unless the task is clicked - It does not support search function (however, you can Ctrl+F, though no content search) - Its other 2 groups “Upcoming” and “Someday” are kind of ambiguous |
Google Calendar (Yun Chuan) | + It is able to mark as done, and undo “done” + It has clean, simple interface which is not cluttered + It can autocomplete based on crowd-sourced or history (but doesn’t feel very “intelligent”) + It can push notifications for reminders/events + It is able to repeat events + It is automatically synchronised both on mobile and on website + It has “All-day” events + It supports “Schedule” view which lists everything in chronological order, starting from today + It is able to “zoom in” (day view) and “zoom out” (month view) + Its items are split into: “events” and “reminders”. Events have start to end time while reminders only have a reminder time |
- It cannot export to data file online - It is unable to mark deadlines accurately (not an “event”) - It cannot search for to-dos - It has too many screens or user actions to add a task |